63 lines
1.6 KiB
Python
63 lines
1.6 KiB
Python
#!/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()
|