This commit is contained in:
Lain Iwakura 2025-07-26 11:00:04 +03:00
parent 19f0007e40
commit 80fe58d1e5
No known key found for this signature in database
GPG Key ID: C7C18257F2ADC6F8

129
src/blog/icmp.mdx Normal file
View File

@ -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, Ill 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 youre 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)