Files
SKELETONKEY/modules/ptrace_traceme_cve_2019_13272/iamroot_modules.c
T
leviathan 102b117d4e Phase 7: PTRACE_TRACEME (CVE-2019-13272) + xt_compat (CVE-2021-22555)
Two famous 2017-2020-era LPEs to broaden 'THE tool for folks'
coverage. Both detect-only initially; exploit ports as follow-ups.

ptrace_traceme (CVE-2019-13272 — jannh @ Google P0, Jun 2019):
- Famous because works on default-config systems with no user_ns
  required — locked-down environments were still vulnerable.
- kernel_range thresholds: 4.4.182 / 4.9.182 / 4.14.131 / 4.19.58 /
  5.0.20 / 5.1.17 / mainline 5.2+
- Exploit shape (deferred): fork → child PTRACE_TRACEME → parent
  execve setuid binary → child ptrace-injects shellcode → root.
- Auditd: flag PTRACE_TRACEME (request 0) — false positives via
  gdb/strace; tune by exclusion.

netfilter_xtcompat (CVE-2021-22555 — Andy Nguyen @ Google P0):
- Bug existed since 2.6.19 (2006) — 15 years of latent vuln. Famous
  for that age + default-config reachability via unprivileged_userns.
- kernel_range thresholds: 4.4.266 / 4.9.266 / 4.14.230 / 4.19.185
  / 5.4.110 / 5.10.27 / 5.11.10 / mainline 5.12+
- detect() probes user_ns+net_ns clone; locked-down → PRECOND_FAIL.
- Exploit shape (deferred): heap massage via msg_msg + sk_buff cross-
  cache groom → kernel R/W → cred or modprobe_path overwrite. ~400
  lines port from Andy's public exploit.c.
- Auditd: unshare + iptables-style setsockopt + msgsnd — combined,
  the canonical exploit footprint.

Both wired into iamroot.c, core/registry.h, Makefile. CVES.md rows
added with detailed status.

Coverage by year now:
  2016: dirty_cow                              🟢
  2019: ptrace_traceme                         🔵
  2021: pwnkit, overlayfs, netfilter_xtcompat  🟢/🟢/🔵
  2022: dirty_pipe, cls_route4                 🟢/🔵
  2023: entrybleed                             🟢
  2024: nf_tables                              🔵
  2026: copy_fail family (×5)                  🟢

Module count: 14. Build clean (no warnings).
2026-05-16 20:47:24 -04:00

128 lines
4.7 KiB
C

/*
* ptrace_traceme_cve_2019_13272 — IAMROOT module
*
* PTRACE_TRACEME on a parent that subsequently execve's a setuid
* binary results in the kernel granting ptrace privileges over the
* privileged process to the unprivileged child. Discovered by Jann
* Horn (Google Project Zero, June 2019).
*
* STATUS: 🔵 DETECT-ONLY. Exploit follows jannh's public PoC: fork
* a child that does PTRACE_TRACEME pointing at the parent, parent
* execve's a chosen setuid binary (e.g., su, pkexec), child then
* ptrace-injects shellcode into the now-elevated process.
*
* Affected: kernels < 5.1.17 mainline. Stable backports varied; the
* fix landed in stable as:
* 5.1.x : K >= 5.1.17
* 5.0.x : K >= 5.0.20 (older LTS — many distros stayed on 4.x)
* 4.19.x: K >= 4.19.58
* 4.14.x: K >= 4.14.131
* 4.9.x : K >= 4.9.182
* 4.4.x : K >= 4.4.182
*
* No exotic preconditions. Doesn't need user_ns. Works on
* default-config systems — that's part of why it's famous: even
* locked-down environments without unprivileged_userns_clone were
* vulnerable.
*/
#include "iamroot_modules.h"
#include "../../core/registry.h"
#include "../../core/kernel_range.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const struct kernel_patched_from ptrace_traceme_patched_branches[] = {
{4, 4, 182},
{4, 9, 182},
{4, 14, 131},
{4, 19, 58},
{5, 0, 20},
{5, 1, 17},
{5, 2, 0}, /* mainline (5.2-rc) */
};
static const struct kernel_range ptrace_traceme_range = {
.patched_from = ptrace_traceme_patched_branches,
.n_patched_from = sizeof(ptrace_traceme_patched_branches) /
sizeof(ptrace_traceme_patched_branches[0]),
};
static iamroot_result_t ptrace_traceme_detect(const struct iamroot_ctx *ctx)
{
struct kernel_version v;
if (!kernel_version_current(&v)) {
fprintf(stderr, "[!] ptrace_traceme: could not parse kernel version\n");
return IAMROOT_TEST_ERROR;
}
/* Bug existed since ptrace's inception (early 2.x); anything
* pre-LTS-backport is vulnerable. Anything < 4.4 in our range
* model defaults to vulnerable since no entry covers it. */
if (v.major < 4 || (v.major == 4 && v.minor < 4)) {
if (!ctx->json) {
fprintf(stderr, "[!] ptrace_traceme: ancient kernel %s — assume VULNERABLE\n",
v.release);
}
return IAMROOT_VULNERABLE;
}
bool patched = kernel_range_is_patched(&ptrace_traceme_range, &v);
if (patched) {
if (!ctx->json) {
fprintf(stderr, "[+] ptrace_traceme: kernel %s is patched\n", v.release);
}
return IAMROOT_OK;
}
if (!ctx->json) {
fprintf(stderr, "[!] ptrace_traceme: kernel %s in vulnerable range\n", v.release);
fprintf(stderr, "[i] ptrace_traceme: no exotic preconditions — works on default config "
"(no user_ns required)\n");
}
return IAMROOT_VULNERABLE;
}
static iamroot_result_t ptrace_traceme_exploit(const struct iamroot_ctx *ctx)
{
(void)ctx;
fprintf(stderr,
"[-] ptrace_traceme: exploit not yet implemented in IAMROOT.\n"
" Status: 🔵 DETECT-ONLY. Reference: jannh's PoC.\n"
" Exploit shape: fork() → child calls PTRACE_TRACEME → parent\n"
" execve's a setuid binary (su, pkexec, ping with cap_net_raw,\n"
" etc.) → child becomes tracer of the now-privileged process\n"
" → ptrace-inject shellcode → root.\n");
return IAMROOT_PRECOND_FAIL;
}
static const char ptrace_traceme_auditd[] =
"# PTRACE_TRACEME LPE (CVE-2019-13272) — auditd detection rules\n"
"# Flag PTRACE_TRACEME (request 0) followed by parent execve of\n"
"# a setuid binary. False positives: gdb, strace, debuggers.\n"
"-a always,exit -F arch=b64 -S ptrace -F a0=0 -k iamroot-ptrace-traceme\n"
"-a always,exit -F arch=b32 -S ptrace -F a0=0 -k iamroot-ptrace-traceme\n";
const struct iamroot_module ptrace_traceme_module = {
.name = "ptrace_traceme",
.cve = "CVE-2019-13272",
.summary = "PTRACE_TRACEME → setuid binary execve → cred-escalation via ptrace inject",
.family = "ptrace_traceme",
.kernel_range = "K < 5.1.17, backports: 5.0.20 / 4.19.58 / 4.14.131 / 4.9.182 / 4.4.182",
.detect = ptrace_traceme_detect,
.exploit = ptrace_traceme_exploit,
.mitigate = NULL, /* mitigation: upgrade kernel; OR set ptrace_scope sysctl */
.cleanup = NULL,
.detect_auditd = ptrace_traceme_auditd,
.detect_sigma = NULL,
.detect_yara = NULL,
.detect_falco = NULL,
};
void iamroot_register_ptrace_traceme(void)
{
iamroot_register(&ptrace_traceme_module);
}