Home > Writeups > DEADROP Network 4 - ICMP Exfil

DEADROP Network 4 - ICMP Exfil

A PCAP containing ICMP echo requests with flag data hidden in the payload fields. Use Scapy or tshark to extract and reassemble the payload bytes across the packet sequence.

ICMP Exfil

Overview

A file is exfiltrated by embedding it in ICMP echo request payloads. A custom 4-byte header in each payload carries the sequence number and total chunk count. The file is a PNG image with one unredacted corner. Reassemble it to find the flag.

Identifying the Traffic

Most ICMP traffic in this PCAP is normal ping traffic (ICMP ID 0x1234). The exfil stream uses ICMP ID 0x1337, filter in Wireshark:

icmp.type == 8 && icmp.ident == 0x1337

This reveals ~209 echo requests, all from the same source IP.

Payload Structure

Each ICMP echo request has a custom payload layout. Note that in tools like dpkt, the ICMP .data field includes the id and seq fields (4 bytes) before the actual payload content:

Bytes 0-1:  ICMP ID (0x1337)
Bytes 2-3:  ICMP sequence number
Bytes 4-5:  File chunk sequence number (big-endian)
Bytes 6-7:  Total chunk count (big-endian)
Bytes 8-40: 32 bytes of file data

Reassembly

import dpkt, struct, io
from PIL import Image

EXFIL_ID = 0x1337
PAYLOAD_DATA_SIZE = 32
chunks = {}

with open('icmp_exfil.pcap', 'rb') as f:
    for ts, raw in dpkt.pcap.Reader(f):
        eth = dpkt.ethernet.Ethernet(raw)
        if not isinstance(eth.data, dpkt.ip.IP): continue
        ip = eth.data
        if ip.p != 1: continue
        icmp = ip.data
        if icmp.type != 8: continue
        d = bytes(icmp.data)
        if len(d) < 8: continue
        if struct.unpack('>H', d[0:2])[0] != EXFIL_ID: continue
        seq, total = struct.unpack('>HH', d[4:8])
        chunks[seq] = d[8:8+PAYLOAD_DATA_SIZE]

reassembled = b''.join(chunks[k] for k in sorted(chunks.keys()))
# Trim to PNG IEND marker
iend = b'\x00\x00\x00\x00IEND\xaeB`\x82'
end = reassembled.find(iend)
if end != -1:
    reassembled = reassembled[:end+len(iend)]

Image.open(io.BytesIO(reassembled)).save('recovered.png')

The recovered image is a redacted surveillance photo. Most of the frame is blacked out, but the bottom-right corner shows a pigeon wearing a small camera harness. The flag is watermarked across the unredacted area.

Flag: DEADROP{icmp_is_a_tunnel_now_apparently}

Key Takeaway

ICMP echo payloads are rarely inspected by firewalls. The 32 bytes of data per ping is a low-and-slow exfiltration technique that can transfer megabytes over hours without triggering volume-based alerts.

< Back to All Writeups