58b44ebc43
build / build (clang / debug) (push) Waiting to run
build / build (clang / default) (push) Waiting to run
build / build (gcc / debug) (push) Waiting to run
build / build (gcc / default) (push) Waiting to run
build / sanitizers (ASan + UBSan) (push) Waiting to run
build / clang-tidy (push) Waiting to run
build / drift-check (CISA KEV + Debian tracker) (push) Waiting to run
build / static-build (push) Waiting to run
overlayfs_setuid (CVE-2023-0386) investigated on Ubuntu 22.04.0 / 5.15.0-25 (genuinely vulnerable): the non-FUSE chown copy-up yields upper/file owned by uid 1000 (no escalation), and overlay refuses a userns-mounted FUSE lowerdir with ENOSYS (plain overlay-in-userns works). A working exploit must mount FUSE in the init ns via the setuid fusermount helper (fd-passing protocol) then overlay in the userns — a substantial dedicated port. A raw /dev/fuse server was written and reverted after hitting the ENOSYS wall. sudoedit_editor (CVE-2023-22809) on sudo 1.9.9 returns EXPLOIT_FAIL — the SUDO_EDITOR/-- arg injection reaches sudoedit's writable-dir guard; needs target-file tuning and module debugging. Tractable next. Ledger + VERIFICATIONS.jsonl updated. No code change (overlayfs_setuid reverted to baseline; not committing a second non-working variant). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0118iUgHY44hdRtANgyCmu7y
96 lines
6.6 KiB
Markdown
96 lines
6.6 KiB
Markdown
# Exploit verification ledger
|
||
|
||
**What this is:** results of actually *running each exploit* against a genuinely
|
||
vulnerable VM and confirming `uid=0` **out of band** (an independent root-owned
|
||
write / `/etc/shadow` read / setuid-bash sentinel — never the module's own
|
||
self-report). This is distinct from `docs/VERIFICATIONS.jsonl`'s historical
|
||
records, which only checked that `detect()` returns the right verdict.
|
||
|
||
Harness: rootless qemu/KVM over frozen point-release cloud images (unpatched →
|
||
vulnerable by default), driver in the session scratch dir. Root witnessed via
|
||
`witness.sh` (shell-probe + setuid-bash finisher + module sentinels + `/etc/passwd`
|
||
tamper check).
|
||
|
||
> **Headline finding:** the corpus was only ever *detect*-verified, never
|
||
> *exploit*-verified. Running the exploits shows a mix of genuinely-working,
|
||
> honestly-failing, and **falsely-succeeding** modules. Two flagship modules
|
||
> reported `EXPLOIT_OK` while obtaining **no root at all** (`pwnkit`,
|
||
> `ptrace_traceme`) — a false positive from the dispatcher's "execve
|
||
> transferred → clean child exit = OK" path. Both are addressed below.
|
||
|
||
## Confirmed landing root (uid=0 witnessed out of band)
|
||
|
||
| module | CVE | target | notes |
|
||
|---|---|---|---|
|
||
| `refluxfs` | CVE-2026-64600 | Rocky 9.8 / 5.14.0-687.el9 | full chain, `/etc/passwd` → root (earlier) |
|
||
| `overlayfs` | CVE-2021-3493 | Ubuntu 20.04.0 / 5.4.0-26 | userns + xattr copy-up, clean |
|
||
| `pwnkit` | CVE-2021-4034 | Ubuntu 20.04.0 / polkit 0.105-26ubuntu1 | **after a fix** — see below |
|
||
| `sudo_runas_neg1` | CVE-2019-14287 | Ubuntu 18.04.2 / sudo 1.8.21p2 + sudoers `(ALL,!root)` | `sudo -u#-1` → uid 0 |
|
||
|
||
## Fixed this session
|
||
|
||
- **`pwnkit`** — reported `EXPLOIT_OK` but did **not** root (glibc "Could not
|
||
open converter … to PWNKIT"). Root cause: missing the `GCONV_PATH=.`
|
||
re-injection directory + `chdir(workdir)`. Fixed → now lands real root on a
|
||
vulnerable host. (commit `24b839e`)
|
||
- **`ptrace_traceme`** — reported `EXPLOIT_OK` but did **not** root; the bundled
|
||
ptrace sequence is a non-working placeholder (it `PTRACE_ATTACH`es to the
|
||
tracer, which by then has reparented to init → `EPERM`). Made **honest**
|
||
(verifies `euid==0`, otherwise `EXPLOIT_FAIL`); a faithful CVE-2019-13272 port
|
||
(Jann Horn / bcoles: `PTRACE_TRACEME` + setuid execve + registered polkit
|
||
agent) is still required to land root. (commit `59cc2be`)
|
||
- **`cgroup_release_agent`** — two real bugs fixed (commit `8c45b2b`): it read
|
||
`getuid()` **after** `unshare(CLONE_NEWUSER)` (→ `65534`, so `uid_map` write
|
||
was `"0 65534 1"` → EPERM), and it omitted `CLONE_NEWCGROUP` (→ cgroup-v1
|
||
mount EPERM). Now the userns+cgroupns+mount setup is correct. It still can't
|
||
root a **bare** unprivileged user on a stock systemd host: every v1 controller
|
||
is pre-mounted (its `release_agent` is init-owned → EACCES from the userns)
|
||
and a fresh named hierarchy is refused. Reachable in a **container** context
|
||
(CAP_SYS_ADMIN / an ownable cgroup) — matches its "host root from rootless
|
||
container" framing. The `getuid()`-after-`unshare` bug is a pattern to grep
|
||
for across the other userns modules.
|
||
|
||
## Needs a faithful PoC port (genuinely vulnerable target, exploit doesn't land)
|
||
|
||
| module | CVE | target tested | what's wrong |
|
||
|---|---|---|---|
|
||
| `ptrace_traceme` | CVE-2019-13272 | Ubuntu 18.04.2 / 4.15.0-50 | placeholder technique (now honest); needs the real cred-transfer PoC (polkit agent) — substantial port |
|
||
| `overlayfs_setuid` | CVE-2023-0386 | Ubuntu 22.04.0 / 5.15.0-25 | genuinely vulnerable target. Investigated deeply (this session): the non-FUSE `chown` copy-up produces `upper/file` owned by **uid 1000, not root** here, so it doesn't escalate — the CVE needs the FUSE-reported-uid-0 lower. But **overlay refuses a userns-mounted FUSE lowerdir with `ENOSYS`** (plain overlay-in-userns works; FUSE-lower does not). A working port must mount FUSE in the **init ns** via the setuid `fusermount` helper (implement its fd-passing unix-socket protocol, or link libfuse), then overlay in the userns. A raw `/dev/fuse` server was written and reverted (hit the overlay-on-userns-FUSE `ENOSYS`). Substantial dedicated port. |
|
||
| `sudoedit_editor` | CVE-2023-22809 | Ubuntu 22.04.0 / sudo 1.9.9 | vulnerable sudo version + sudoers `sudoedit` grant present; module returns `EXPLOIT_FAIL` — the `SUDO_EDITOR`/`--` arg-injection reaches sudoedit's writable-dir guard. Needs a target-file whose dir the injection can satisfy (e.g. `/etc/passwd`), and module debugging. Structural, tractable next. |
|
||
| `sudo_samedit` | CVE-2021-3156 | Ubuntu 18.04.2 + 20.04.0 | honest `EXPLOIT_FAIL`; Baron Samedit is heap/libc-version-specific, needs a per-target tuned PoC. Hardest. |
|
||
|
||
## Inconclusive (detect version-blind vs vendor backport)
|
||
|
||
| module | CVE | note |
|
||
|---|---|---|
|
||
| `dirty_pipe` | CVE-2022-0847 | Ubuntu 22.04.0's 5.15.0-25.25 almost certainly carries the backported fix (USN-5317); `detect()` is version-only so says VULNERABLE. Needs a genuinely pre-fix kernel (e.g. 5.13.0-19, or mainline 5.16.10) to verify the exploit. |
|
||
|
||
## Not yet exploit-tested (the bulk — ~30 modules)
|
||
|
||
- **🟡 kernel primitives** (`nf_tables`, `nft_set_uaf`, `nft_payload`,
|
||
`nft_fwd_dup`, `netfilter_xtcompat`, `af_packet`, `af_packet2`, `af_unix_gc`,
|
||
`cls_route4`, `fuse_legacy`, `stackrot`, `sequoia`, `nft_pipapo`, `vsock_uaf`,
|
||
`pintheft`): return `EXPLOIT_FAIL` by design; landing root needs a per-kernel
|
||
`--dump-offsets` + `--full-chain` (modprobe_path finisher) pass on a vulnerable
|
||
kernel.
|
||
- **Structural userspace** (`sudoedit_editor`, `sudo_chwoot`, `sudo_host`):
|
||
need specific sudo versions + sudoers config; likely tractable.
|
||
- **2026 CVEs** (`copy_fail` ×5, `dirtydecrypt`, `fragnesia`, `cifswitch`,
|
||
`nft_catchall`, `ptrace_pidfd`): need vulnerable 2026 kernels; the reconstructed
|
||
race triggers (`bad_epoll`, `ghostlock`, `nft_catchall`) are deliberately
|
||
under-driven and won't pop root by design.
|
||
- **Environment-blocked**: `vmwgfx` (VMware guest only), `dirty_cow` (needs ≤4.4),
|
||
`mutagen_astronomy` (CentOS 6 / Debian 7).
|
||
- **D-Bus/desktop** (`pack2theroot`, `udisks_libblockdev`): need the polkit/D-Bus
|
||
stack + a provisioner rule.
|
||
|
||
## Method notes for continuation
|
||
|
||
- Frozen images: `cloud-images-archive.ubuntu.com/releases/<name>/release-<date>/`
|
||
are unpatched and vulnerable-by-default for CVEs disclosed after that date — far
|
||
easier than downgrading packages on current images.
|
||
- gcc must be present *in* the VM (several exploits compile payloads at runtime);
|
||
on EOL LTS, point apt at the archive main pocket.
|
||
- **Always verify root out of band.** The module self-report is not trustworthy
|
||
(two flagships lied). `witness.sh` is the reference check.
|