File Transfer Techniques
Cheatsheet for moving files across Linux, Windows, restricted shells, and inspected networks. Built for CTF players, bug bounty hunters, and internal pentesters.
Moving tools, loot, and implants between machines is one of the most repetitive — and most detection-prone — activities on an engagement. A clean file transfer is often the difference between a quiet beachhead and a tripped EDR. This guide catalogues the techniques I reach for across Linux, Windows, restricted shells, and inspected networks, with an emphasis on living off the land, OPSEC, and fallback chains when your first option gets blocked.
Every technique here leaves artifacts: process logs, Sysmon EID 1/3/11, proxy logs, TLS JA3
hashes, SMB share mounts. Always assume the defender is logging. Prefer native binaries, encode
when you must, and rotate methods when a transfer fails — a single failed certutil will often
trip your first EDR rule.
Throughout this cheatsheet, the following IPs are used consistently:
- ▹
10.10.14.5→ Your Kali / attacker machine - ▹
10.10.10.23→ The victim / target machine - ▹
10.10.20.x→ Internal network hosts (reachable only through the victim)
Each code block that involves two or more machines includes a comment at the top reminding you which IP is which.
Linux-Based Transfers
Linux targets are usually the friendlier side of an engagement. You typically have a real shell, a curl/wget pair, and outbound network access — though egress filtering, break-glass proxies, and bastion jumps will constrain you. The techniques below progress from the trivial (curl) to tunneling through SSH when nothing else is open.
::curl
curl is the swiss-army knife on most Linux hosts. Prefer it over wget when you need protocol flexibility (SMB, FTPS, GOPHER) or fine-grained header control.
curl supports file://, gopher://, and dict:// out of the box. In SSRF chains these
protocols are gold — gopher:// in particular lets you craft arbitrary TCP payloads against
internal services (Redis, Memcached, internal SMTP).
::wget
wget is older, recursive-friendly, and almost always present on minimal containers. It also tends to write less to the terminal by default, which matters over shaky shells.
::scp
scp is the workhorse when SSH is open and you have credentials or a key. It's simple, but the SCP protocol itself is legacy (SFTP-based transfers in OpenSSH 9+ are preferred under the hood).
::rsync
rsync is scp with a brain: delta transfers, resume, exclude patterns, and SSH transport. It's the right tool for moving large or repeatedly-updated trees.
| Flag | Purpose |
|---|---|
-a | archive mode (recursive, preserve perms/owner/symlinks) |
-v | verbose |
-z | compress during transfer |
--partial | keep half-transferred files for resume |
--inplace | update the destination file in-place (no temp + rename) |
-e | specify the remote shell, including custom SSH flags |
::netcat and socat
When SSH isn't an option but a raw TCP socket is open, nc and socat give you a clean two-way pipe. They're noisy on the wire (cleartext TCP) but trivially reliable.
>Receiving on attacker, sending from victim
>Sending from attacker, receiving on victim (push a tool in)
>socat — encrypted and more robust
socat is nc with superpowers. You get TLS, fine-grained buffering, and fork modes for multi-connection listeners.
Windows-Based Transfers
On Windows you'll rarely have curl.exe pre-installed (though Windows 10 1803+ ships it). The default workflow is to use signed, native binaries that defenders have to allow — certutil, bitsadmin, PowerShell, and the SMB stack.
::certutil.exe
certutil is a Microsoft-signed CA utility that happens to have a -urlcache mode which will happily fetch any URL and write it to disk. It is one of the most abused LotL binaries in existence.
certutil -urlcache -f is one of the most heavily signatured LotL patterns in existence. Defender
for Endpoint, CrowdStrike, and SentinelOne all flag it by default. If you must use it: - Strip the
.exe from your URL (e.g. /agent.jpg) - Use a redirector with a legitimate-looking User-Agent
(certutil sends Microsoft-CryptoAPI/10.0) - Prefer -decode of a staged base64 blob over the
direct URL fetch - Avoid entirely on EDR'd hosts. Move to PowerShell Net.WebClient or SMB.
::bitsadmin
bitsadmin is the BITS (Background Intelligent Transfer Service) CLI. BITS runs as a service and queues transfers — meaning your download survives user logoff and is throttled based on network cost. It's slower than other methods but blends well with legitimate Windows Update traffic.
BITS is asynchronous — bitsadmin /transfer blocks, but /create + /addfile + /resume
returns immediately. Use /info or /getstate to poll, and remember to call /complete or the
job lingers in the queue (defender-visible via Get-BitsTransfer).
::PowerShell
PowerShell is the most flexible native option and is present on every modern Windows host. The trade-off: Script Block Logging (EID 4104) and AMSI will see everything you run. Obfuscation is out of scope here — assume your commands are logged.
>Invoke-WebRequest (alias iwr, curl, wget)
>Net.WebClient — older, often less-instrumented than IWR
Both IEX and DownloadString feed content through AMSI before execution. On a
fully-instrumented host, an unobfuscated Mimikatz download will be caught within milliseconds. If
AMSI bypass isn't viable, prefer DownloadFile to disk + a separately-staged loader.
::SMB File Transfers (Impacket's smbserver.py)
SMB is the protocol of locked-down AD environments. Domain-joined hosts already speak SMB to DCs for SYSVOL, Group Policy, and authentication — your transfer blends right in. The cleanest setup is smbserver.py from Impacket on your attacker box, then copy from the Windows side.
Language-Specific One-Liners (Quick HTTP Servers)
When you've popped a shell on a host that has a Python, PHP, Ruby, or Perl interpreter but no web server, the fastest way to expose a directory for download is to spin up a tiny HTTP listener. Each of these serves the current directory on port 8000 (or wherever you point it).
::Python 3
The default http.server module sends a Server: SimpleHTTP/0.6 Python/3.x header and
Content-Type guesses that are immediately recognizable in proxy logs. Defenders pivot on this
header. If you need stealth, write a 20-line Flask/FastAPI server or proxy through nginx.
::PHP
::Ruby
::Perl
Restricted Shells / No-Network Transfers
Sometimes the only channel you have is a clipboard, a web terminal, or a serial console with no networking at all. In these cases you fall back to encoding: pack the binary as base64 text, paste it through whatever channel you have, and decode it on the other side.
::Base64 Round-Trip
>On the attacker side — encode the file
>On the victim (Linux) — decode it back
>On the victim (Windows / PowerShell) — decode it
>On the victim (Windows / certutil — no PowerShell needed)
::Hex Encoding (when base64 isn't available)
On stripped appliances (busybox without base64), xxd or od can fill in.
Encrypted / Evasive Transfers
Clear-text HTTP/SMB transfers are trivially inspectable. Even HTTPS can be blocked by TLS-intercepting proxies (and your C2 cert won't pass their trust store). The techniques below use end-to-end encryption you control — the proxy sees encrypted bytes it cannot MITM.
::OpenSSL
OpenSSL's s_client / s_server pair gives you a poor-man's encrypted tunnel with no extra tooling. Generate a self-signed cert once, then use it for both directions.
>One-time setup — generate a self-signed cert on the attacker
>Attacker — listen for encrypted transfer
>Victim — push file to attacker over TLS
>Victim — pull file from attacker over TLS
::Chisel
Chisel is a single-binary TCP/UDP tunnel over WebSocket, with optional TLS. It's the modern replacement for ptunnel/ iodine/stunnel combos and is the first thing I reach for when only HTTPS (443) egress is allowed.
>Attacker — run the server
>Victim — run the client and bring up tunnels
>File transfer through a Chisel SOCKS proxy
Once the reverse SOCKS is up on 127.0.0.1:1080 of your attacker box, you can curl to internal hosts that were previously unreachable:
Closing OPSEC Notes
A few habits that have saved me more than once:
- ▹Rotate methods. Don't
certutilyour way through every host in a domain — once one transfer gets caught, every subsequentcertutilinvocation will be correlated. - ▹Time your transfers. Align exfil windows with normal business-hour activity. A 2 AM SMB push to an unknown host is an instant anomaly.
- ▹Use redirectors. Your attacker IP should never appear in victim logs directly. Cloudflare, fastly, a cheap VPS with nginx in front — all work.
- ▹Test for breakage before relying on it. Many of these techniques have host-specific quirks (PowerShell Constrained Language Mode, AppLocker on
certutil, SELinux denyingncbind). Have at least one fallback in each category. - ▹Clean up.
net use /delete,bitsadmin /complete, kill thehttp.serverprocess, delete staged.b64blobs. Persistence is great; sloppiness is not.
File transfer is infrastructure. The technique you pick matters less than the discipline of picking the right one for the environment you're in — and being ready to switch the moment the network pushes back.
MSFvenom Cheat Sheet
Enhanced, practical msfvenom reference covering payload generation across all platforms, staged vs stageless selection, encoding, encryption, bad-character handling, template injection, advanced handlers, and real-world delivery techniques.
Linux Privilege Escalation: Basics & Exploitation
Kill chains for sudo abuse, SUID/capabilities, PATH hijacking, cron exploitation, NFS no_root_squash, and runtime process hunting with pspy. Built for Red Teamers and CTF players who skip the theory.
Linux Privilege Escalation: Enumeration Cheatsheet
Copy-paste-ready enumeration commands covering every critical Linux privesc vector — OS, users, network, files, capabilities, and scheduled tasks. Built for Red Teamers, pentesters, and CTF players.
