
Self-contained PoC and analysis for CVE-2026-94300, a GSS-TSIG use-after-free in BIND 9.20.29, with a debugger-assisted model of the leak-to-code-execution chain.
Note: This analysis and PoC were produced substantially with AI assistance ("AI patchwork"). Every code, diff and measurement claim should be verified against the cited sources before being relied upon.
Self-contained PoC folder for the exploitation chain of CVE-2026-94300 (BIND 9.20.29 with GSS-TSIG, krb5 1.20.1, jemalloc 5.3.0).
What is proven here: A leaked address set (here from gdb) is enough to build code execution in
the named process out of the measured primitives. The exploit consumes the leak from
docker logs; it contains no address literals.
What is explicitly a model here (and stated as such in the report):
| Assumption | Reason |
|---|---|
| Leak from gdb | The CVE has no info-leak primitive; a real leak would have to come from another bug |
ASLR off (setarch -R) | without a leak there are no heap/code addresses |
| Object-content control injected via gdb | the reclaim of the freed 8-byte slot did not succeed in the real path with the means examined here (4.7M attempts, 0 hits) — a documented obstacle, not an impossibility proof |
No demonstrated remote RCE and no persistence. The command is given via --cmd on the exploit: host/exploit.py hands it over the Docker control channel (docker exec, the same authority the operator already has) into the container; the exploit itself
sends only the leaked addresses and the captured packet. The payload additionally writes the RCE-PROOF line (for verification) and terminates named.
sequenceDiagram
participant R as Researcher (host)
participant V as Container: named 9.20.29 + gdb
participant L as docker logs
R->>V: docker run -p 127.0.0.1:15353:53/udp
V->>V: TKEY capture (no send), gdb breaks on dns_db_currentversion
V->>L: LEAK: db=…, methods=…, heap=…, wire_b64=… (sha256)
V->>V: model armed, waits for host replay
R->>L: read docker logs + validate (11 checks)
R->>V: docker exec: --cmd to /tmp/rce-payload-cmd
R->>V: UDP replay of the leaked signed packet to 15353
V->>V: krb5_k_free_key → free(db) → reclaim → fake dns_db_t
V->>V: dns_db_currentversion → jmp *methods+0x30 → payload
R->>V: docker exec cat /tmp/rce-proof
| Path | Purpose |
|---|---|
docker/Dockerfile | Victim image: BIND 9.20.29 from the ISC tarball + gdb + KDC + lab drivers |
etc/ | krb5.conf, kdc.conf, named.conf, zone (copied into /etc by the image) |
host/exploit.py | Host exploit: reads docker logs, validates, replays over UDP, checks the marker |
lab/rce_victim.sh | In-container driver: named under gdb, capture without send, leak, wait |
lab/rce_model.py | gdb model: breakpoints, leak block, arming, dispatch observation |
lab/rce_leak.py | Leak stage: addresses + wire_b64 → stdout/file |
lab/rce_exploit.py | Exploit stage in the container: builds fake object from leak, reclaim, dispatch |
lab/rce_shim.c | Fixed-page shim: fake table, fake dns_db_t template, payload |
lab/replay-lab.py | TKEY capture (--no-send) |
lab/gss_context_lab.py | GSS context helper for the capture |
lab/start.sh, lab/named.replay.conf | KDC/keytab/zone bootstrap, named configuration |
RACE.md | Explanation of the race on the shared GSS-TSIG context: sharing, accesses, trigger, measurements, scoping |
VERIFY.md | Verification of the three claims against the source diff 9.20.29 → 9.20.30 (GSS-TSIG locking, destructive keyring dump, RCE scoping) |
EXPLOIT.md | Exploit description with code evidence and Mermaid |
USAGE.md | Build, run, expected outputs, troubleshooting |
ANAYLSE.md | Publication-ready disclosure addendum (impact reconciliation DoS vs. potential RCE, affected versions, mitigation, detection) — without exploit primitives |
ANALYZE.md | English version of the disclosure addendum |
(This file is README.md; the other PoC documents also exist as RACE.md, VERIFY.md,
EXPLOIT.md, USAGE.md.)
Only Docker + internet at build time. The image builds BIND 9.20.29 itself from the official
ISC tarball (https://downloads.isc.org/isc/bind9/9.20.29/bind-9.20.29.tar.xz, SHA-256 pinned),
with --with-gssapi=yes, and installs gdb, the MIT Kerberos KDC and the lab drivers. No distro
BIND, no prebuilt base image needed.
The image contains a throwaway KDC identity [email protected] (password attacker,
realm EXAMPLE.TEST, KDC on 127.0.0.1:88 in the container only) — for this lab exclusively, not
for GSS-TSIG tests against other servers; do not take the keytab out of the container.
cd poc/CVE-2026-94300-poc
docker build -f docker/Dockerfile -t cve-2026-94300-victim .
# Terminal 1: container
docker run --rm --name cve-2026-94300-victim \
-p 127.0.0.1:15353:53/udp \
--security-opt seccomp=unconfined \
cve-2026-94300-victim # prints the LEAK block to stdout
# Terminal 2: exploit from the host, target + command as arguments
python3 host/exploit.py --ip 127.0.0.1 --port 15353 --cmd 'id > /tmp/bla'
docker exec cve-2026-94300-victim cat /tmp/bla # uid=0(root) …
Expected (excerpt):
LEAK: db=0x7ffff6901c00
LEAK: db_methods=0x7ffff7c497c0
LEAK: payload=0x7ffff7fbe37b
LEAK: wire_len=3907
HOST-EXPLOIT-VALIDATE OK checks=11
HOST-EXPLOIT-REPLAY target=127.0.0.1:15353 bytes=3907
RCE-DISPATCH-INDIRECT target=0x7ffff7fbe37b (rce_payload) match=YES
RCE-PAYLOAD-EXECUTED RCE-PROOF pid=… uid=0 euid=0 db=0x7ffff6901c00
HOST-EXPLOIT-VERDICT payload_executed=YES marker=YES
Advisory sentence: ISC rates CVE-2026-94300 as remote, High, CVSS 8.1 (AC:H) with potential code execution. What is publicly/reproducibly established is a credential-free, replay-triggered memory corruption (use-after-free/double-free) on the shared GSS-TSIG context — DoS- to heap-corruption class. A path to code execution has so far been shown only under debugger-assisted model assumptions (ASLR off, addresses/object contents injected); no demonstrated remote RCE exists.
Established: given a leak, RCE follows in the target process. Not established: a remote attack without a leak and without gdb — the info-leak primitive and the achieved reclaim step are missing for that. This is a documented set of obstacles, not an impossibility proof; ISC carries the code-execution class as potential. The code basis (synchronization bug, destructive dump, what the patch fixes and what it does not) is checked in VERIFY.md against the diff of the two trees; how the race works technically is in RACE.md. Exploit details and code evidence: EXPLOIT.md, execution and options: USAGE.md. Publication-ready disclosure: ANALYZE.md.