Breathing Void - EH4X CTF 2026
Category: Miscellaneous | Points: 388 | Author: N0nchalantAc1d Solved by: Smothy @ 0xN1umb
1GB of dead vacuum. Can you find any life.
We get Breathing_Void.tar.gz. I extract it and... 1.1GB PCAP. Cool. My laptop fan started screaming before Wireshark even finished loading.
Step 1: Don't Open the 1GB PCAP in Wireshark
Seriously. Don't. I did. Waited 4 minutes for it to load, scrolled through a wall of identical TCP packets, learned nothing, and closed it.
Instead, capinfos is your friend:
capinfos Breathing_Void.pcapThis spit out a bunch of stats but the two things that mattered:
4,198,284 packets across two encapsulation types: Ethernet (4,198,011) and Raw IPv4 (273). And then I noticed the capture comment:
File created by merging:
File1: massive.pcap
File2: decoy_trap.pcap
File3: covert_timing_2.pcap
me: *reads "massive.pcap" and "decoy_trap.pcap"*
me: so 99.99% of this file is literally filler and bait
the challenge: "1GB of dead vacuum"
me: yeah that tracks
So covert_timing_2.pcap is where the flag lives. The name even tells us the encoding method - covert timing channel. Thanks for the hint, N0nchalantAc1d.
Step 2: Extract the Needle from the Haystack
The 273 Raw IPv4 packets use a different encapsulation type (interface #2), so filtering them out is trivial:
tshark -r Breathing_Void.pcap -Y "frame.interface_id==2" -w covert.pcap272 packets extracted (one was probably a header). Let's see what they look like:
- All 272 packets are identical HTTP GET requests:
10.10.10.50→10.10.10.200 - Source port 1337 (nice), destination port 80
- Same payload every time:
GET / HTTP/1.1 Host: ghost.local User-Agent: Chronos-Agent/v0.01-0.10
Every single packet is the same. Same source, same destination, same payload. So the data isn't in the content at all.
Then I looked at the User-Agent again: Chronos-Agent/v0.01-0.10. Chronos = time. v0.01-0.10 = two timing values. The flag is encoded in the delays between packets.
Step 3: Decode the Timing
Extract timestamps and compute inter-packet delays:
tshark -r covert.pcap -T fields -e frame.time_epoch > timestamps.txttimes = [float(l.strip()) for l in open("timestamps.txt")]
deltas = [round((times[i+1] - times[i]) * 1000) for i in range(len(times)-1)]
print(sorted(set(deltas))) # [10, 100]Exactly two unique delays: 10ms and 100ms. Binary encoding. 0.01 and 0.10 from the User-Agent version string - it was literally telling us the two timing values in seconds.
Step 4: Bits to Flag
Map 100ms → 1 and 10ms → 0. That gives us 271 bits from 272 packets. We need 272 bits (34 bytes × 8) for a clean decode.
Since the flag starts with E (0x45 = 01000101 which starts with 0), prepend a 0 bit to align:
times = [float(l.strip()) for l in open("timestamps.txt")]
deltas = [round((times[i+1] - times[i]) * 1000) for i in range(len(times)-1)]
bits = '0' + ''.join(['1' if d == 100 else '0' for d in deltas])
flag = ''
for i in range(0, len(bits), 8):
flag += chr(int(bits[i:i+8], 2))
print(flag)EH4X{pc@p5_@re_of+en_mo5+1y_noi5e}
Decoded from leetspeak: "pcaps are often mostly noise". Yeah, 1.1GB of noise hiding 272 packets. Point taken.
What Made This Click
Honestly, the solve was fast once I stopped trying to be smart with Wireshark. The real timeline was:
- Extract → try to open in Wireshark → suffer (~5 min)
- Run
capinfos→ see the merge comment → realize 99% is junk (~2 min) - Filter by interface ID → get 272 identical packets (~1 min)
- Notice User-Agent timing hint → compute delays → two values → binary (~5 min)
- Prepend alignment bit → decode → flag (~3 min)
Total: maybe 15 minutes of actual work. Plus 5 minutes of Wireshark loading screen.
Key Takeaways
capinfosbefore Wireshark. Always. Especially on big PCAPs. The metadata (capture comments, encapsulation types, packet counts per interface) can solve the challenge before you even look at packet data.- Different encapsulation types = different sources. When a PCAP has Ethernet AND Raw IPv4, those came from different capture interfaces. Easy filter target.
- Covert timing channels encode data in the gaps between packets, not in the packets themselves. All packets can be identical - the information is in the rhythm.
- Read the User-Agent.
Chronos-Agent/v0.01-0.10was basically a cheat code. Two timing values in the version string, named after the god of time. Subtle as a brick.
Flag: EH4X{pc@p5_@re_of+en_mo5+1y_noi5e}
1GB of noise, 272 meaningful packets, 34 bytes of flag. The void wasn't dead after all - it was just breathing very quietly.