{
    "archive_path": "archive/1792058760.79951",
    "base_url": "blog.dfb.sh/blog/eap770-root-for-two-zeros",
    "basename": "",
    "bookmarked_date": "2026-10-15 10:06",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/blog.dfb.sh/blog/eap770-root-for-two-zeros",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=blog.dfb.sh",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": "blog.dfb.sh/blog/eap770-root-for-two-zeros/index.html"
    },
    "domain": "blog.dfb.sh",
    "extension": "",
    "hash": "1TG3DD8PPDSXSFPPM8A3",
    "history": {
        "archive_org": [],
        "dom": [],
        "favicon": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "120",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://www.google.com/s2/favicons?domain=blog.dfb.sh"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-10-15T10:08:22.415514+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1792058760.79951",
                "schema": "ArchiveResult",
                "start_ts": "2026-10-15T10:08:21.947810+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--head",
                    "--max-time",
                    "120",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://blog.dfb.sh/blog/eap770-root-for-two-zeros/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-10-15T10:08:22.750265+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1792058760.79951",
                "schema": "ArchiveResult",
                "start_ts": "2026-10-15T10:08:22.424757+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [],
        "media": [],
        "mercury": [
            {
                "cmd": [
                    "/app/node_modules/@postlight/parser/cli.js",
                    "https://blog.dfb.sh/blog/eap770-root-for-two-zeros/"
                ],
                "cmd_version": "1.0.0",
                "end_ts": "2026-10-15T10:08:29.353783+00:00",
                "index_texts": null,
                "output": "mercury",
                "pwd": "/data/archive/1792058760.79951",
                "schema": "ArchiveResult",
                "start_ts": "2026-10-15T10:08:25.547784+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/app/node_modules/readability-extractor/readability-extractor",
                    "/tmp/tmpv68q1joj",
                    "https://blog.dfb.sh/blog/eap770-root-for-two-zeros/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2026-10-15T10:08:25.537740+00:00",
                "index_texts": [
                    "TL;DR:\n  My TP-Link EAP770 v1 corrupts downloads over Wi-Fi and TP-Link EOL'd it before I unboxed it. The fix is two zeros in sysfs. TP-Link's shell won't let me write them, so I wrote a kernel exploit for my own fucking access point.\n\nLong downloads kept breaking#\n\nIn August 2023 I bought a shiny new Wi-Fi 7 access point, a TP-Link EAP770.\nThe connection was a bit janky, a video would occasionally start buffering, but it didn't bother me much.\nI mostly worked on a workstation connected over Ethernet.\nWhen I needed to go somewhere, I'd rsync my ~ to the laptop over Wi-Fi and take it with me.\nThose transfers started failing on files larger than a few GiB.\nSSH was reporting MAC errors, so I spent a while debugging rsync and SSH.\nEverything else worked, changing rsync options made it better or worse, Wireshark showed zero bad checksums and zero retransmissions, and a single UDP stream of random bytes came through clean.\nI trusted TCP to deliver the right bytes because that's what the fucking thing is for, so I was sure the problem was in rsync or SSH.\nI wrote a wrapper around rsync with retries and moved on.\nLater I happened to start using Tailscale for traffic inside my home network, and the transfers stopped needing retries.\nWireGuard drops a packet if its authentication fails, so the TCP connection inside the tunnel sees a lost packet and retransmits it.\nSince the transfers worked, I stopped digging.\nZero firmware updates#\n\nThe device is an EAP770(EU) v1.0 with a Qualcomm IPQ9574 running Linux 5.4.164 and firmware 1.0.0 Build 20230605 Rel. 71641.\nThat's the firmware it shipped with, and apparently the last time TP-Link remembered this thing even existed :)\nI bought this thing in August 2023, and the Wi-Fi 7 standard was only finalized in September 2024.\nIt has no Wi-Fi Alliance certification, and buying it was stupid of me.\nPLZ DON'T BUY STUFF UNTIL STANDARDS ARE FINALIZED AND DEVICES ARE CERTIFIED.\nIn 2025 I noticed that everything else was getting updates while this thing was still on its original firmware.\nI contacted support in June because the website only had firmware for v2.\nThey couldn't find v1 in their database and asked for photos of the device and box before sending me this:\n\nThe EAP770 Version 1 is an End-of-Life product. While it may still be available through some retailers, it is no longer supported with firmware updates.\n\nNICE.\nTracking down the corruption#\n\nIn 2026 I decided to switch to NixOS and found that a 128 MiB file from the Nix binary cache on Fastly would fail over HTTP/2 but downloaded fine over HTTP/1.1.\nI still don't know why HTTP/1.1 helped; my guess is that HTTP/2 was simply faster.\ngit clones also failed, and HTTPS connections died with bad record mac.\nIn March, downloading a NixOS ISO with wget died with a TLS error:\n2026-03-05 12:37:18 (31.6 MB/s) - Read error at byte 2722477636/3683778560 (error:0A000119:SSL routines::decryption failed or bad record mac; error:0A000139:SSL routines::record layer failure). Retrying.\nI forced HTTP/1.1 and left it alone again.\nIn September I turned the workstation into a build farm and switched to the laptop, which connects over Wi-Fi.\nWi-Fi was also dropping every day around 11:00, right before my daily call.\nAfter it had died right before the call several days in a row, I decided to open this Pandora's box again and sat down with Opus 5.5 to trace what was happening.\nSpoiler alert: the drops turned out to be a separate bug.\nI covered the laptop's Qualcomm driver in BPF probes and ran apstats on the AP as root.\nThe bug is in the closed-source firmware on the laptop's Wi-Fi card; see the update at the bottom.\nI had tried enabling and disabling Wi-Fi 7, turning off GRO on the client, and replacing the MediaTek adapter in my Framework 16 with a Qualcomm one.\nThe new adapter and disabling GRO seemed to help, but none of this stopped the corruption.\nI captured a failing HTTPS download with tcpdump and found a 1440-byte TCP segment with 64 wrong bytes in a row and a valid TCP checksum.\nTcpInCsumErrors stayed at zero.\nTCP accepted the segment and handed it to TLS, which rejected the record with bad record mac.\nThe damaged record wouldn't decrypt, so I couldn't inspect the bad bytes against the expected payload.\nI switched to raw TCP between a wired machine and the Wi-Fi laptop, sending known data that I could compare byte for byte.\nThe corruption only appeared with several TCP streams running at once, in the LAN-to-Wi-Fi direction.\nThe test found three bad 64-byte blocks in 8192 MiB, each starting with zeros.\nA valid checksum on a damaged segment meant something had recalculated it after the corruption, so the question became what on the path rewrites TCP headers.\nThe corruption still showed up after swapping the MediaTek card for the Qualcomm one, so it wasn't the laptop.\nWired clients were clean and the CCMP MIC on the bad frames was intact, so it wasn't the cable and it wasn't the air.\nThat left the bridge between Ethernet and Wi-Fi inside the AP.\n64 bytes is a cache line on the IPQ9574's cores, which points at a cache or DMA bug rather than a flipped bit.\nThe only thing on that path that both accelerates bridged traffic and recalculates checksums is Qualcomm's SFE/PPE offload.\nTwo writes that need root#\n\nReading the driver source suggested disabling SFE/PPE with these two settings:\necho 0 > /sys/sfe/l2_feature\necho 0 > /sys/sfe/ppe_rfs_feature\nBoth sysfs files are writable only by root, but TP-Link's SSH shell runs as uid 1 with no capabilities.\nThere's no GUI setting for this either.\nThere's also no v1 firmware image to patch and flash, and the v2 firmware is for different hardware.\nI tried the sibling EAP773's EAP773(EU)_V1_1.0.14, and the device rejected it.\nNewer v2 firmware releases are encrypted.\nFlashing the chip directly needed a flash clip.\nI didn't want to hunt one down or brick the fucking AP.\nI wasn't going to spend another $200 replacing an AP because TP-Link couldn't be bothered to maintain the one they had already sold me.\nIt's sitting in my house, I know which setting to change, and their software won't let me.\nShout-out to TP-Link though: the system is pretty hardened.\nI found zero vectors in their own binaries, they use whitelists everywhere and load only the modules they need.\nSo no free ; echo 0 > /sys/sfe/ppe_rfs_feature cheese for me.\nSo the way in had to be the kernel.\nWith Opus 4.8, I put together a chain using CVE-2022-0185 and pipe-buffer manipulation.\nCVE-2022-0185 is an integer underflow in legacy_parse_param(), reachable from an unprivileged user namespace, that lets a write overflow a 4 KiB slab object.\nThe pipe-buffer manipulation turns that overflow into an arbitrary write.\nThere were already public write-ups and PoCs for these.\nThe exploit had to leave the AP running because the broken offload comes back after a reboot.\nThe overflow leaves the 4 KiB slab in a state where a second attempt panics, so there's one shot per boot.\nI gave Opus guidance on the primitives, then had it iterate until the exploit was stable.\n\nExploit details\nWithout a v1 GPL source drop, I used the nearest published source, for the EAP783, whose kernel config differs from the AP's /proc/config.gz by three cosmetic lines.\nI built a QEMU harness with that config, got the chain working there, and then moved to the real device.\nThe kernel has no KASLR, so addresses stay the same between boots, but kallsyms is zeroed and I still had to find the addresses at runtime.\nThe QEMU build loaded the kernel at physical 0x40080000, but the device loaded it at 0x42080000, putting the calculations off by 0x2000000.\nThe correct address was in a build config variable in the EAP783 source.\nEven after correcting the base, the device's .text, .rodata and .data had each moved by a different amount relative to the QEMU build, so adding one offset to everything didn't work.\nThe exploit:\n\nUnshare into a user namespace so that fsopen is reachable and the underflow can be triggered.\nDefragment the 4 KiB slab with a few hundred same-size allocations, then groom it to put the overflow source, a victim key, a SysV message and pipe rings next to each other.\nOverflow into the victim key's metadata and enlarge its length field.\nReading the key back now leaks neighbouring objects, including a pipe's buf[0].ops, which contains the address of anon_pipe_buf_ops.\nRepoint one pipe's buffer at another pipe's ring page, then forge an entry in that second ring using the leaked ops pointer.\npipe_buf_can_merge() checks that the ops pointer matches, so a merge write through the forged entry can reach an arbitrary physical page, including a page of the kernel image.\nScan .data to find modprobe_path.\nReading kernel-image pages through a pipe normally calls put_page() on the reserved page when the buffer is consumed, causing Bad page map and a panic.\nBut pipe_read only calls ->confirm and ->release, and does not check that the ops table is real.\nA forged pipe_buf_operations with both entries pointing to generic_pipe_buf_confirm, which returns zero without doing anything else, lets the scan read the pages without releasing them.\nIt can then walk .data in batches until it finds the string.\nOverwrite modprobe_path and execve a file with magic that matches no binary format.\nThe kernel calls request_module(), which runs the replacement path as global uid 0.\nKeep a child alive holding the forged pipe.\nLetting the process exit would tear down the pipe and panic on the reserved page.\n\n\nGetting this working took about seventeen hours of token gambling with Opus 4.8, including reading the device's binaries in radare2, checking the enabled protections, and working through the crashes.\nThe AP stayed up, and disabling the offload stopped the corruption.\nA DMA cache coherency bug#\n\nQualcomm's qca-nss-dp driver reuses packet buffers without synchronizing the CPU cache for the whole receive buffer before handing it back to the NIC.\nOn this hardware, DMA writes directly to DRAM without keeping the CPU caches in sync.\nA dirty cache line left over from the previous use of a buffer can be written back after the NIC has received a new packet, overwriting part of that packet in memory.\nSFE/PPE then recalculates the checksums over the corrupted payload, so the client gets a fresh TCP checksum that is valid for the garbage.\nTCP accepts it; the end-to-end MACs in TLS and SSH catch the damage, reporting bad record mac and corrupted MAC.\nOn x86, the hardware keeps DMA coherent with the CPU caches, so the same missing cache maintenance wouldn't corrupt anything.\nWhile looking through the kernel sources, I found similar DMA cache maintenance problems in several other drivers too.\nI don't know how to test those on hardware or who to report them to yet.\n\nDriver details\nThis is Qualcomm's out-of-tree NSS code, available in the openwrt/qca-nss-dp mirror.\nSFE's fast transmit path cleans skb_headlen(skb) bytes from the current skb->data, covering the linear part of the outgoing packet.\n\n\tbuff_addr = (dma_addr_t)virt_to_phys(skb->data);\n\tEDMA_TXDESC_BUFFER_ADDR_SET(txd, buff_addr);\n\n#ifdef EDMA_40BIT_SUPPORT\n\tEDMA_TXDESC_BUFFER_ADDR_HI_SET(txd, buff_addr);\n#endif\n\n\tdmac_clean_range_no_dsb((void *)skb->data, (void *)(skb->data + buf_len));\nIt then sets skb->fast_recycled = 1 and returns the buffer to a per-CPU recycle list without clearing its contents.\n\n\t\t/*\n\t\t * We set fast_recycled flag if packet has taken the\n\t\t * SFE fast transmit path, so that any Rx DMA driver\n\t\t * that allocates this packet later can avoid\n\t\t * an invalidate operation\n\t\t */\n\t\tif (likely(skb->fast_xmit) && likely(skb->is_from_recycler)) {\n\t\t\tskb->fast_recycled = 1;\n\t\t}\nThe recycler zeroes the sk_buff struct up to its tail field, restores fast_recycled, and resets skb->data to skb->head + NET_SKB_PAD.\nWhen that buffer is reused for receive, the refill path sees the flag and skips invalidation:\n\n\t\t/*\n\t\t * Invalidate skb->data\n\t\t * A73 flush operation does an invalidate operation as well.\n\t\t * If the packet is fast transmitted and hence fast recycled,\n\t\t * we can be assured that invalidate was already done at the\n\t\t * time of previous transmit\n\t\t */\n\t\tif (unlikely(!skb->fast_recycled)) {\n\t\t\tdmac_inv_range_no_dsb((void *)skb->data,\n\t\t\t\t\t      (void *)(skb->data + rx_alloc_size -\n\t\t\t\t\t      EDMA_RX_SKB_HEADROOM -\n\t\t\t\t\t      NET_IP_ALIGN));\n\n\t\t}\n\t\tskb->fast_recycled = 0;\nThe receive region is 1856 bytes, or 29 cache lines, starting at head + 192.\nThe previous transmit cleaned only two or three lines from a different offset.\nDirty lines outside that cleaned range can be written back after the NIC's DMA, replacing 64 bytes of the received packet at a time.\nNormal cache eviction can cause the write-back.\nOn arm64, invalidating an unaligned range can also do it: __dma_inv_area uses dc civac, clean and invalidate, on the partial edge lines.\nOnce the dirty data has overwritten the packet in DRAM, invalidating the CPU cache cannot recover the received bytes.\nThe NIC verifies the checksum of the original packet before that overwrite, and the AP's receive path marks it CHECKSUM_UNNECESSARY using the hardware status bits.\nThe exact sequence inside PPE is hidden in proprietary hardware and driver code, but the packet capture shows that the checksum was calculated after the corruption.\nBuffer recycling is enabled by CONFIG_SKB_RECYCLER, a compile-time option with no runtime switch.\nDisabling the offload stops buffers taking the fast transmit path, so the driver no longer sets fast_recycled and receive invalidates the full buffer before handing it to the NIC.\nOnly downloads to a Wi-Fi client go through the AP's wired receive path; uploads don't, and wired-to-wired traffic stays on the switch.\n\nOpus 5.5 found the bug and then stopped talking about it#\n\nWhen I moved from diagnosing the corruption to applying the fix, Opus 5.5 started cutting sessions off roughly every other message.\nMentioning something like \"local privilege escalation\" is enough.\nI have the Cyber Verification Program enabled on my account, which hasn't helped.\nOpus 4.8 worked through the exploitation without that problem.\n5.5's guards also kill the session when I just ask it to read this article.\nGPT-6 Astra reads and edits the same article without any cyber verification.\nBefore and after#\n\nI tested raw TCP transfers between the same two machines with the offload enabled and disabled.\nOffloadDirectionDataSpeedBad 64-byte blocks\nonLAN -> Wi-Fi8192 MiB103.4 MiB/s3\noffLAN -> Wi-Fiovernight run95.4 MiB/s0\n\nDisabling the offload cost about 8% of the download speed in this test.\nI have to give up performance to get correct data because TP-Link won't let me properly fix my own fucking device.\nWith the offload on, I could never download a large file over Wi-Fi in a single stream; only chunked downloads got through.\nWith the offload off, the overnight run came back with zero bad blocks, and large downloads have worked every time since.\nUploads from Wi-Fi to the LAN were already clean before the fix.\nThe NOT_SUPPORT_BRIDGE counter in /sys/sfe/exceptions increases after disabling the offload, as bridged flows take the normal path instead of being accelerated.\nThe settings reset after a reboot, so a watcher on my NAS polls the AP and reruns the exploit when the offload is back on.\nIf the attempt fails, it reboots the AP through TP-Link's management API and tries again on the next boot, with a hard cap on the number of reboots.\nQualcomm can fix their driver if they want, or host it somewhere more open.\nOpenWrt doesn't have this bug, and TP-Link won't release new firmware for my AP anyway.\nThe similar DMA bugs I found in Linux deserve a closer look, though.\nI'll get back to those over the weekend.\nUpdate: tracking down the drops#\n\nThe Qualcomm card I put in the Framework 16 is a WCN785x, and every few hours it stopped sending data for 1 to 4 minutes.\nSince I already had root on the AP, I ran apstats on the EAP770 alongside the BPF probes on the laptop and caught three drops with logs from both sides.\nEverything the AP sent to the laptop arrived and got ACKed, so the laptop's radio was transmitting and the AP's receiver worked.\nOnly data frames from the laptop stopped going out.\nOn the laptop, packets kept going into ath12k and the queue grew to thousands of frames.\nThe firmware confirmed a few frames at a time and eventually returned the rest to the driver with CMD_REMOVE_AGED_FRAMES, 10630 out of 26388 in one drop.\nThe driver was otherwise quiet.\nOn the AP, rx_data stayed at +0 for most ticks apart from an occasional burst, with zero RX errors and zero retries, so the frames never left the card.\nThen the card unblocked on its own and sent the whole backlog in two seconds.\nThe AP saw rx_data+3273 and then +12498, and the laptop saw 7751 ACKed frames.\nThe signal was -31 to -42 dBm, the drops happened with no scan running, and the IP layer on the laptop was fine during them.\nI'm already on the latest upstream firmware, WLAN.HMT.1.1.c7-00108 UPSTREAM-3.\nath12k only gets completion statuses back, and everything about when a frame goes on the air is decided inside Qualcomm's closed-source amss.bin.\nThat leaves the firmware.\nI still don't know why it stops transmitting.\nThe bursts that got through during a drop look like 802.11ax/be uplink scheduling, trigger-based uplink or MU EDCA, but I didn't find those settings on the AP to check.\nI switched the AP's 5 GHz radio from Wi-Fi 7 to Wi-Fi 6 (802.11ax) and left a watcher running for 24 hours.\nIf the drops stop, it's a Wi-Fi 7 bug, so I stay on Wi-Fi 6 and send a bug report to ath12k.\nIf they don't, the firmware is broken regardless of the mode, and it's either a bug report or an Intel card."
                ],
                "output": "readability",
                "pwd": "/data/archive/1792058760.79951",
                "schema": "ArchiveResult",
                "start_ts": "2026-10-15T10:08:23.843540+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "120",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://blog.dfb.sh/blog/eap770-root-for-two-zeros/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-10-15T10:08:23.836107+00:00",
                "index_texts": null,
                "output": "Wanted to download an ISO, ended up writing a kernel exploit | deafbeef blog",
                "pwd": "/data/archive/1792058760.79951",
                "schema": "ArchiveResult",
                "start_ts": "2026-10-15T10:08:23.818934+00:00",
                "status": "succeeded"
            }
        ],
        "wget": [
            {
                "cmd": [
                    "wget",
                    "--no-verbose",
                    "--adjust-extension",
                    "--convert-links",
                    "--force-directories",
                    "--span-hosts",
                    "--no-parent",
                    "-e",
                    "robots=off",
                    "--reject=js,mjs,woff,woff2,ttf,otf,eot,mp4,m4v,mov,webm,ogv,mkv,avi,flv",
                    "--timeout=120",
                    "--restrict-file-names=windows",
                    "--page-requisites",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) wget/GNU Wget 1.21.3",
                    "--compression=auto",
                    "--timestamping",
                    "https://blog.dfb.sh/blog/eap770-root-for-two-zeros/"
                ],
                "cmd_version": "GNU Wget 1.21.3",
                "end_ts": "2026-10-15T10:08:23.809924+00:00",
                "index_texts": null,
                "output": "blog.dfb.sh/blog/eap770-root-for-two-zeros/index.html",
                "pwd": "/data/archive/1792058760.79951",
                "schema": "ArchiveResult",
                "start_ts": "2026-10-15T10:08:22.760179+00:00",
                "status": "succeeded"
            }
        ]
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": null,
        "dom": null,
        "favicon": "favicon.ico",
        "git": null,
        "media": null,
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "Wanted to download an ISO, ended up writing a kernel exploit | deafbeef blog",
        "warc": null,
        "wget": "blog.dfb.sh/blog/eap770-root-for-two-zeros/index.html"
    },
    "link_dir": "/data/archive/1792058760.79951",
    "newest_archive_date": "2026-10-15T10:08:25.547784+00:00",
    "num_failures": 0,
    "num_outputs": 6,
    "oldest_archive_date": "2026-10-15T10:08:21.947810+00:00",
    "path": "/blog/eap770-root-for-two-zeros/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_id": "f3b387cc-ec8a-4abd-ab63-6204f363424f",
    "sources": [
        "/data/sources/1792058760-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1792058760.79951",
    "title": "Wanted to download an ISO, ended up writing a kernel exploit | deafbeef blog",
    "updated": "2026-10-15T10:08:21.947357+00:00",
    "updated_date": "2026-10-15 10:08",
    "url": "https://blog.dfb.sh/blog/eap770-root-for-two-zeros/"
}