diff --git a/src/blog/icmp.mdx b/src/blog/icmp.mdx new file mode 100644 index 0000000..30e4571 --- /dev/null +++ b/src/blog/icmp.mdx @@ -0,0 +1,129 @@ +--- +layout: blog.njk +title: Making eBPF "Cursed Ping" Work on Linux, macOS, and BusyBox +date: 2025-07-25 +description: How I made my eBPF ping hack universal +--- + +## Introduction + +Messing with ping using eBPF is fun-just mutate the timestamp in the ICMP Echo Reply and watch the round-trip time go wild! +But in practice, different ping implementations use different payload formats. If you corrupt the wrong bytes, BSD/macOS ping will instantly complain about "wrong data byte". + +In this post, I’ll show how I made eBPF hack universal: it now works on Linux and macOS/BSD! + +--- + +## The Problem + +- **Linux (iputils):** timestamp is 16 bytes (2 x uint64) +- **macOS/BSD:** timestamp is only 8 bytes, followed by a signature sequence (0x08, 0x09, 0x0a, ...), which must not be touched! +- **BusyBox:** timestamp is just 4 bytes (uint32_t) + +If you mutate the "extra" bytes, BSD ping immediately reports a corrupted payload. + +--- + +## The Solution + +In the eBPF program, we: +- Automatically detect the ping type by inspecting the payload signature +- Mutate only the correct number of bytes: + - Linux: 16 bytes + - BSD/macOS: 8 bytes + - BusyBox: 4 bytes + +### Key eBPF Code Snippet + +```c +__u8* payload = (void*)(icmphdr + 1); +int ping_type = 0; // 0=linux, 1=bsd, 2=busybox + +if ((void*)(payload + 16) <= data_end) { + if (payload[8] == 0x08 && payload[9] == 0x09 && payload[10] == 0x0a && payload[11] == 0x0b) { + ping_type = 1; // BSD/macOS + } +} +if (ping_type == 0 && (void*)(payload + 8) <= data_end) { + if ((void*)(payload + 16) > data_end || + (payload[8] != 0x08 && payload[9] != 0x09)) { + ping_type = 2; // BusyBox + } +} + +if (ping_type == 2) { + __u32* ts_busybox = (void*)(icmphdr + 1); + if ((void*)(ts_busybox + 1) <= data_end) { + __u32 old_ts = *ts_busybox; + *ts_busybox -= bpf_get_prandom_u32() % 500; + recalc_icmp_csum(icmphdr, old_ts, *ts_busybox); + } +} else if (ping_type == 1) { + __u64* ts_secs = (void*)(icmphdr + 1); + if ((void*)(ts_secs + 1) <= data_end) { + __u64 old_secs = *ts_secs; + *ts_secs -= bpf_get_prandom_u32() % 500; + recalc_icmp_csum(icmphdr, old_secs, *ts_secs); + } +} else { + __u64* ts_secs = (void*)(icmphdr + 1); + if ((void*)(ts_secs + 1) <= data_end) { + __u64 old_secs = *ts_secs; + *ts_secs -= bpf_get_prandom_u32() % 500; + recalc_icmp_csum(icmphdr, old_secs, *ts_secs); + } + __u64* ts_nsecs = (void*)(icmphdr + 1) + sizeof(__u64); + if ((void*)ts_nsecs + sizeof(__u64) <= data_end) { + __u64 old_nsecs = *ts_nsecs; + *ts_nsecs -= bpf_get_prandom_u32(); + recalc_icmp_csum(icmphdr, old_nsecs, *ts_nsecs); + } +} +``` + +--- + +## Real-World Examples + +### Linux (iputils): + +```bash +$ ping 77.110.117.147 +PING 77.110.117.147 (77.110.117.147): 56 data bytes +64 bytes from 77.110.117.147: icmp_seq=1 ttl=63 time=9796999 ms +64 bytes from 77.110.117.147: icmp_seq=2 ttl=63 time=9997898 ms +``` + +### macOS/BSD: + +```bash +platon@Moofbook~> ping 77.110.117.147 +PING 77.110.117.147 (77.110.117.147): 56 data bytes +64 bytes from 77.110.117.147: icmp_seq=72 ttl=133 time=-872349695955.565 ms +64 bytes from 77.110.117.147: icmp_seq=446 ttl=66 time=-368967679955.594 ms +64 bytes from 77.110.117.147: icmp_seq=447 ttl=86 time=704643072044.353 ms +^C +--- 77.110.117.147 ping statistics --- +3 packets transmitted, 3 packets received, 0.0% packet loss +round-trip min/avg/max/stddev = -872349695955.565/-178891434622.269/704643072044.353/657684464294.250 ms +``` + +### BusyBox: + +```bash +/ # ping 77.110.117.147 +PING 77.110.117.147 (77.110.117.147): 56 data bytes +64 bytes from 77.110.117.147: seq=893 ttl=63 time=82.448 ms +64 bytes from 77.110.117.147: seq=664 ttl=63 time=61.749 ms +``` +> On busybox mutate ONLY seq (idk why) +--- + +## Conclusion + +Now our eBPF hack works on all major ping implementations, without breaking the payload or triggering "wrong data byte" errors. +You can safely troll sysadmins and test network tools on any platform! + +--- + +If you’re interested, the original source code is on [GitHub](https://github.com/x3lfyn/cursed-ping) and mine on [Github](https://github.com/crypetxctl/cursed-ping) and [own Gitea](https://git.iwakurahome.ru/lain/cursed-ping)