Cached at:
07/30/26, 10:52 PM
# Bad Apple!! but it's traceroute
Source: [https://jssfr.de/2026-07-27-bad-apple-but-traceroute.html](https://jssfr.de/2026-07-27-bad-apple-but-traceroute.html)
As a follow\-up to[my post about how to make traceroute tools show arbitrary content](https://jssfr.de/2026-07-25-messing-with-traceroute.html)and inspired by[the release of another Bad Apple cover the other day](https://www.youtube.com/watch?v=zcGdKK_cQbE)I simply[had to](https://jssfr.de/2026-07-27-bad-apple-but-traceroute.html#why)\.
Of course, I'm[not the first one to do this](https://www.youtube.com/watch?v=Od02Xse4axY)\. That couldn't stop me though\.
## How it works
In the post I linked above, I had demonstrated how to inject fake hops into traceroute output\.
Using[the`numgen`feature of nftables](https://wiki.nftables.org/wiki-nftables/index.php/Math_operations), we can make the hops vary every time an ICMPv6 packet is generated\.`numgen`gets us either random numbers or a monotonic counter\. With a counter, we can easily make each hop return a different IPv6 address each time a response packet is generated\. Using[the playground from the other post](http://localhost:8002/2026-07-25-messing-with-traceroute.html#setting-up-a-playground):
```
ip netns exec tracemess nft -f - <<EOF
destroy table inet tracemess
table inet tracemess {
chain prerouting {
type filter hook prerouting priority raw;
ip6 daddr fd00::1 ip6 hoplimit 1 reject with icmpv6 admin-prohibited;
}
chain postrouting {
type filter hook postrouting priority raw;
icmpv6 type destination-unreachable icmpv6 code admin-prohibited ip6 saddr fd00::1 @th,120,8 1 ip6 saddr set numgen inc mod 3 map { 0: fd00::2, 1: fd00::3, 2: fd00::4 } icmpv6 type set 3 icmpv6 code set 0 accept;
}
}
EOF
```
Two other things were needed to make this happen\. First of all, we need to disable the kernel's rate limit \(by default, 1/s\) for ICMPv6 egress using`sysctl net\.ipv6\.icmp\.ratelimit=0`, otherwise the party will be over really quick\.
The second problem is that`mtr`will normally show multiple addresses for each hop, because that indicates that multiple different paths are in use for a packet and that is normally useful information\. In this case, however, that's rather annoying:

In order to fix that, we have to apply a one\-line patch[1](https://jssfr.de/2026-07-27-bad-apple-but-traceroute.html#fn:i-like-mtr)to mtr[2](https://jssfr.de/2026-07-27-bad-apple-but-traceroute.html#fn:max-paths):
```
diff --git a/ui/net.c b/ui/net.c
index c0cbf28..7c52710 100644
--- a/ui/net.c
+++ b/ui/net.c
@@ -266,6 +266,7 @@ static void net_process_ping(
break; /* Found first vacant position */
}
}
+ i = 0;
if (found == 0 && i < MAX_PATH) {
memcpy(&nh->addrs[i], &addrcopy, sockaddr_addr_size(sourcesockaddr));
```
With all this in place, I used ffmpeg to resample the video to 8 frames\-per\-second \(which equates an interval of 125 ms between frames\) and export scaled\-down \(to 30x11 pixels\) individual frames to PNG files\. I then wrote a python script to read the image files and convert them into an nftables ruleset to generate the corresponding ICMPv6 responses\.
That results in a bit over a megabyte of nftables rules, but it's definitely worth it\.
## Why?
The[shadow art Bad Apple music video](https://www.youtube.com/watch?v=i41KoE0iMYU)has become the benchmark for hacked displays, for[a very loose definition of "display"](https://www.youtube.com/watch?v=A__lP5Vtdug), similar to how[running Doom \(the 1993 video game\)](https://canitrundoom.org/)has become the benchmark of gaining code execution on a new hardware platform\. I suspect the reason for that is that, due to its shadow art style, the video can be rendered even on "displays" which only have one bit per pixel \(on/off\)\.
There is[a subreddit dedicated](https://www.reddit.com/r/ItPlaysBadApple/)to showing off the kinds of devices people have gotten Bad Apple to display on\. My favourite would at this point be[this hack abusing a HD47780\-compatible character LCD](https://www.youtube.com/watch?v=lI8jfwCPBJM), simply because I enjoy hacking these devices, too[3](https://jssfr.de/2026-07-27-bad-apple-but-traceroute.html#fn:close-second)\. There's also more than[one compilation video showing multiple versions](https://www.youtube.com/watch?v=fu4RvH0W3mg)\.
Considering that … I simply had no choice, did I?