Shmooganography is a little CTF event that takes place each year at Shmoocon in Washington, DC. This CTF is focused on stegonagraphy, and related techniques. I ended up participating in, and coming in first place with my team. I wanted to showcase an interesting method of hiding data that was used in the fourth round of the event.
# Challenge basics
This level starts with a .pcap
file which contains a single MPEG audio stream. A sample of the packets can be seen with tshark
$ tshark -r ../Downloads/time_turner.pcap
--- snip ---
4 0.012998 127.0.0.1 → 127.0.0.1 MPEG TS 1364 PT=MPEG-II transport streams, SSRC=0xEA80289, Seq=65356, Time=1664842007 Program Association Table (PAT) Program Map Table (PMT) Service Description Table (SDT) [MP2T fragment of a reassembled packet]
5 0.014997 127.0.0.1 → 127.0.0.1 MPEG-1 1364 Audio Layer 3, 160 kb/s, 44.1 kHz Audio Layer 3, 160 kb/s, 44.1 kHz Audio Layer 3, 160 kb/s, 44.1 kHz
--- snip ---
There were 5820 packets in total in this capture, and there is some extra information encoded within the packet, somewhere.
# IP header basics
The general structure of an IPv4 header according to rfc791 follows:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Each “-” in the above diagram represents one bit. We are concerned with, specifically, the Options
field. In this field, there are many different type of “options” you can specify, however each packet we are looking at, has its type as 0x44, or the Timestamp
option. The structure of this sub field follows:
+--------+--------+--------+--------+
|01000100| length | pointer|oflw|flg|
+--------+--------+--------+--------+
| internet address |
+--------+--------+--------+--------+
| timestamp |
+--------+--------+--------+--------+
The first packet we have has the Options
field containing the following bytes 44 08 05 40 00 00 00 01
, so lets break this down.
The first byte 0x44
is the first entry, specifying the type of this Options
field. Next, we have 0x08
for our length, the total length of this field, obviously 0x05
is the pointer field, which we are not really concerned with. Next we have 0x4
which is the upper half nibble of the next byte, and this nibble is the chosen covert channel of communication for our challenge. This is a known method of data exfiltration and a rather interesting one at that. The rest of the data in the Options
field is not important to us.
# Reconstructing the message
Equipped with our new knowledge of how the hidden message is encoded, we can use a quick and dirty method of extracting our full payload from the packet capture file. For this, I used tshark
:
$ tshark -r data.pcap -T fields -e 'ip.options.timestamp' | grep -v '^$' | cut -c 7-7 | tr -d '\n' | xxd -r -p > payload.dat
A quick explanation of the above command, the tshark
command is used to read our packet capture and extract the ip.options.timestamp
field from each IPv4 packet, then the results are filtered to remove empty lines with grep. Next, the high nibble of the fourth byte is extracted with cut, and new lines are removed to join the nibbles together. Finally, xxd is used to transform the resulting hex data into the corresponding raw bytes, and we are left with payload.dat
, a GIF
file containing the flag for the current level: ELDER
.
Cool technique.