#!/usr/bin/env python3 """ Decode the flag from the timing-based ICMP channel in public/task.pcapng. Requires scapy: pip install scapy """ from scapy.all import rdpcap, IP, ICMP # type: ignore import sys from typing import Iterable, List TARGET_IP = "192.168.13.37" ZERO_DELAY = 1.2 ONE_DELAY = 1.6 TOLERANCE = 0.08 # Acceptable drift around each delay marker def load_icmp_times(pcap_path: str) -> List[float]: packets = rdpcap(pcap_path) icmp_flow = [ pkt for pkt in packets if IP in pkt and ICMP in pkt and (pkt[IP].src == TARGET_IP or pkt[IP].dst == TARGET_IP) ] icmp_flow.sort(key=lambda p: float(p.time)) return [float(pkt.time) for pkt in icmp_flow] def as_deltas(times: List[float]) -> List[float]: return [cur - prev for prev, cur in zip(times, times[1:])] def decode_bits(deltas: Iterable[float]) -> str: bits = [] for dt in deltas: if abs(dt - ZERO_DELAY) <= TOLERANCE: bits.append("0") elif abs(dt - ONE_DELAY) <= TOLERANCE: bits.append("1") return "".join(bits) def bits_to_ascii(bits: str) -> str: # Drop trailing bits if not a whole byte usable_len = len(bits) - (len(bits) % 8) out = [] for i in range(0, usable_len, 8): out.append(chr(int(bits[i : i + 8], 2))) return "".join(out) def main() -> None: pcap_path = sys.argv[1] if len(sys.argv) > 1 else "../public/task.pcapng" times = load_icmp_times(pcap_path) bitstring = decode_bits(as_deltas(times)) plaintext = bits_to_ascii(bitstring) print(plaintext) if __name__ == "__main__": main()