upd
This commit is contained in:
parent
19f0007e40
commit
80fe58d1e5
129
src/blog/icmp.mdx
Normal file
129
src/blog/icmp.mdx
Normal 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, 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)
|
Loading…
x
Reference in New Issue
Block a user