CTF:             USCG Combine 2024
Category:        Forensics
Key Concepts:    Packet Timing, Steganography

Givens

  • timingiseverything.pcap (2kb)

First Impressions

This is a very small packet capture file: opening it with Wireshark shows that it only contains 30 packets, all ICMP pings from 192.168.72.128 to 192.168.100.100.

The entire packet capture

This seems very simple, and looking through the packet contents gives no useful information. Opening the file in Network Miner shows the same thing: this is simply a series of pings, with no hidden files or other information.

Nothing else is happening here

In The Sign of Four, Sherlock Holmes remarks that:

“When you have eliminated the impossible, whatever remains, however improbable, must be the truth”

Finding What Remains

In this case, all that remains are the time values: they are the only possible source of data. Instead of the date-time format above, it’s easier to compare time values in the “Seconds Since First Captured Packet” format, which can be changed in View:

Changing the time display setting

Note: After solving the challenge, I realized that the challenge could be solved much more quickly by using the “Seconds since Previous Captured Packet” setting. I am still leaving the following steps to demonstrate my thought process and to show an alternate solution to the “easy way”.

While the values are now in seconds, they are still offset by the time value of the previous packet.  

|185
Seconds since Previous Captured Packet

Visualizing Data

The Desmos online graphing calculator is a useful tool to visualize this data: here, the packets are represented by a series of lines from left to right, with the gaps between them representing the respective time delays.

Packet times, unadjusted

I wrote the following formula in Desmos to adjust each packet by subtracting the previous packet’s time value.

Adjustment formula

After adjustment, the graph shows a visualization of the relative time delay between the packets.

Packet times, adjusted

Exporting this list, I noticed that most of the numbers seemed to be below 100, which hinted at the use of decimal text formatting.

adjusted_times = [0.083, 0.073, 0.086, 0.085, 0.083, 0.067, 0.071, 0.123, 0.084, 0.049, 0.109, 0.049, 0.110, 0.057, 0.095, 0.049, 0.053, 0.095, 0.051, 0.118, 0.051, 0.114, 0.121, 0.116, 0.104, 0.049, 0.110, 0.057, 0.125]

Cleaning up the values by removing the leading zeroes and decimal places gives the following:

cleaned_list = [83, 73, 86, 85, 83, 67, 71, 123, 84, 49, 109, 49, 110, 57, 95, 49, 53, 95, 51, 118, 51, 114, 121, 116, 104, 49, 110, 57, 125]

Now, simply running the list through CyberChef’s decimal converter yields the flag!

Decoding the flag

Reflection

This challenge presented a steganographic technique that I had never seen before. Thankfully, the challenge was very focused: there were no red herrings or junk data in the packet capture. In a real-world scenario, this type of encoding would be much more difficult to detect. While the time-adjustment part of my solution was not entirely necessary due to Wireshark’s extra options, it was still very interesting to visualize the packet timings and extract the offsets manually. This challenge was novel, engaging, and a lot of fun to work through!