all modules: wrap Linux-only code in #ifdef __linux__ — full macOS build works
Every kernel-LPE module that uses Linux-only headers (splice, posix_fadvise,
linux/netlink.h, sys/ptrace.h, etc.) now follows the same #ifdef __linux__
pattern the new modules already used: Linux body in the ifdef, stub
detect/exploit/cleanup returning SKELETONKEY_PRECOND_FAIL on non-Linux,
platform-neutral rule strings + module struct + register fn left outside.
14 modules wrapped:
dirty_pipe (already done above), af_packet, af_packet2,
cgroup_release_agent, cls_route4, dirty_cow, fuse_legacy,
netfilter_xtcompat, nf_tables, nft_fwd_dup, nft_payload,
overlayfs, overlayfs_setuid, ptrace_traceme.
Several modules previously had ad-hoc partial stubs (af_packet2 faked
SIOCSIFFLAGS/MAP_LOCKED, netfilter_xtcompat faked sysv-msg syscalls,
the nft_* modules had 3 partial __linux__ islands each, fuse_legacy /
nf_tables had inner-only ifdef blocks) — all replaced with the uniform
outer-wrap shape from dirty_pipe / dirtydecrypt / fragnesia / pack2theroot.
Where a module includes core/kernel_range.h, core/finisher.h, or
core/offsets.h, those are now inside the ifdef block as well — silences
clangd's "unused-includes" LSP warning on macOS while keeping them
present for the real Linux build.
No exploit logic, constant, struct, shellcode byte, or rule string was
modified — only include placement and ifdef markers.
Build verification:
macOS (local): make clean && make → Mach-O x86_64, 31 modules
registered, --scan reports each Linux-only module as
"Linux-only module — not applicable here".
Linux (docker gcc:latest + libglib2.0-dev): make clean && make →
ELF 64-bit, 31 modules. Exploit code paths unchanged.
This commit is contained in:
@@ -45,9 +45,6 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -55,13 +52,18 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -72,52 +74,6 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
/* ---------- macOS / non-linux build stubs ---------------------------
|
||||
* Modules in SKELETONKEY are dev-built on macOS and run-built on Linux.
|
||||
* Provide empty stubs so syntax checks pass without Linux headers.
|
||||
* The exploit path is gated at runtime on the kernel version anyway,
|
||||
* so the stubs are never reached on macOS targets. */
|
||||
#ifndef __linux__
|
||||
#define CLONE_NEWUSER 0x10000000
|
||||
#define CLONE_NEWNET 0x40000000
|
||||
#define ETH_P_ALL 0x0003
|
||||
#define ETH_P_8021Q 0x8100
|
||||
#define ETH_P_8021AD 0x88A8
|
||||
#define ETH_P_IP 0x0800
|
||||
#define ETH_ALEN 6
|
||||
#define ETH_HLEN 14
|
||||
#define VLAN_HLEN 4
|
||||
#define IFF_UP 0x01
|
||||
#define IFF_RUNNING 0x40
|
||||
#define SIOCSIFFLAGS 0x8914
|
||||
#define SIOCGIFINDEX 0x8933
|
||||
#define SIOCGIFFLAGS 0x8913
|
||||
#define SOL_PACKET 263
|
||||
#define PACKET_RX_RING 5
|
||||
#define PACKET_VERSION 10
|
||||
#define PACKET_QDISC_BYPASS 20
|
||||
#define TPACKET_V2 1
|
||||
#define PACKET_HOST 0
|
||||
struct sockaddr_ll { unsigned short sll_family; unsigned short sll_protocol; int sll_ifindex; int dummy; };
|
||||
struct ifreq { char name[16]; union { int ifr_ifindex; short ifr_flags; } u; };
|
||||
struct tpacket_req { unsigned int tp_block_size, tp_block_nr, tp_frame_size, tp_frame_nr; };
|
||||
struct tpacket2_hdr { unsigned int tp_status, tp_len, tp_snaplen; unsigned short tp_mac, tp_net; };
|
||||
struct pollfd { int fd; short events, revents; };
|
||||
#define POLLIN 0x001
|
||||
__attribute__((unused)) static int ioctl(int a, unsigned long b, ...) { (void)a; (void)b; errno=ENOSYS; return -1; }
|
||||
__attribute__((unused)) static void *mmap(void *a, size_t b, int c, int d, int e, long f) { (void)a;(void)b;(void)c;(void)d;(void)e;(void)f; errno=ENOSYS; return (void*)-1; }
|
||||
__attribute__((unused)) static int munmap(void *a, size_t b) { (void)a;(void)b; return -1; }
|
||||
__attribute__((unused)) static int setsockopt(int a, int b, int c, const void *d, unsigned int e) { (void)a;(void)b;(void)c;(void)d;(void)e; errno=ENOSYS; return -1; }
|
||||
__attribute__((unused)) static int poll(struct pollfd *a, unsigned long b, int c) { (void)a;(void)b;(void)c; errno=ENOSYS; return -1; }
|
||||
__attribute__((unused)) static unsigned short htons(unsigned short x) { return x; }
|
||||
#define MAP_SHARED 0x01
|
||||
#define MAP_LOCKED 0x2000
|
||||
#define PROT_READ 0x1
|
||||
#define PROT_WRITE 0x2
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
#endif
|
||||
|
||||
static const struct kernel_patched_from af_packet2_patched_branches[] = {
|
||||
{4, 9, 235},
|
||||
@@ -223,8 +179,6 @@ static skeletonkey_result_t af_packet2_detect(const struct skeletonkey_ctx *ctx)
|
||||
* the primitive. It does not land cred overwrite.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
/* sendmmsg spray helper — best-effort skb groom. Adjacent kernel slab
|
||||
* objects are sprayed so the OOB write lands on attacker bytes. */
|
||||
static void af_packet2_skb_spray(int n_iters)
|
||||
@@ -440,15 +394,6 @@ static int af_packet2_primitive_child(const struct skeletonkey_ctx *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !__linux__: provide a stub for macOS sanity builds */
|
||||
static int af_packet2_primitive_child(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] af_packet2: linux-only primitive — non-linux build\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---- Full-chain finisher (--full-chain, x86_64 only) ----------------
|
||||
*
|
||||
* Arb-write strategy (Or Cohen's sk_buff-data-pointer hijack):
|
||||
@@ -490,7 +435,7 @@ struct afp2_arb_ctx {
|
||||
int n_attempts; /* spray/fire rounds before giving up */
|
||||
};
|
||||
|
||||
#if defined(__x86_64__) && defined(__linux__)
|
||||
#if defined(__x86_64__)
|
||||
static int afp2_arb_write(uintptr_t kaddr, const void *buf, size_t len, void *vctx)
|
||||
{
|
||||
struct afp2_arb_ctx *c = (struct afp2_arb_ctx *)vctx;
|
||||
@@ -508,9 +453,7 @@ static int afp2_arb_write(uintptr_t kaddr, const void *buf, size_t len, void *vc
|
||||
* frame would then write our payload (the modprobe_path string)
|
||||
* into the forged ->data target. */
|
||||
for (int i = 0; i < c->n_attempts; i++) {
|
||||
#ifdef __linux__
|
||||
af_packet2_skb_spray(8);
|
||||
#endif
|
||||
pid_t p = fork();
|
||||
if (p < 0) return -1;
|
||||
if (p == 0) {
|
||||
@@ -535,9 +478,7 @@ static int afp2_arb_write(uintptr_t kaddr, const void *buf, size_t len, void *vc
|
||||
}
|
||||
int st;
|
||||
waitpid(p, &st, 0);
|
||||
#ifdef __linux__
|
||||
af_packet2_skb_spray(8);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* LAST-RESORT depth: we have fired the trigger + spray but cannot
|
||||
@@ -664,7 +605,7 @@ static skeletonkey_result_t af_packet2_exploit(const struct skeletonkey_ctx *ctx
|
||||
" skeletonkey intentionally does not embed per-kernel offsets.\n");
|
||||
}
|
||||
if (ctx->full_chain) {
|
||||
#if defined(__x86_64__) && defined(__linux__)
|
||||
#if defined(__x86_64__)
|
||||
/* --full-chain: resolve kernel offsets and run the Or-Cohen
|
||||
* sk_buff-data-pointer hijack via the shared modprobe_path
|
||||
* finisher. Per the verified-vs-claimed bar: if we can't
|
||||
@@ -703,6 +644,29 @@ static skeletonkey_result_t af_packet2_exploit(const struct skeletonkey_ctx *ctx
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: AF_PACKET + TPACKET_V2 + tpacket_rcv VLAN
|
||||
* underflow are Linux-only kernel surface. Stub out cleanly so the
|
||||
* module still registers and `--list` / `--detect-rules` work on
|
||||
* macOS/BSD dev boxes — and so the top-level `make` actually completes
|
||||
* there. */
|
||||
static skeletonkey_result_t af_packet2_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] af_packet2: Linux-only module "
|
||||
"(AF_PACKET TPACKET_V2 + user_ns) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t af_packet2_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] af_packet2: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
static const char af_packet2_auditd[] =
|
||||
"# AF_PACKET VLAN LPE (CVE-2020-14386) — auditd detection rules\n"
|
||||
"# Same syscall surface as CVE-2017-7308 — share the skeletonkey-af-packet\n"
|
||||
|
||||
@@ -60,17 +60,22 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -858,6 +863,30 @@ static skeletonkey_result_t af_packet_exploit(const struct skeletonkey_ctx *ctx)
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: AF_PACKET + unshare(CLONE_NEWUSER|CLONE_NEWNET)
|
||||
* + TPACKET_V3 ring are Linux-only kernel surface; the TPACKET_V3
|
||||
* integer-overflow primitive is structurally unreachable elsewhere.
|
||||
* Stub out cleanly so the module still registers and `--list` /
|
||||
* `--detect-rules` work on macOS/BSD dev boxes — and so the top-level
|
||||
* `make` actually completes there. */
|
||||
static skeletonkey_result_t af_packet_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] af_packet: Linux-only module "
|
||||
"(AF_PACKET TPACKET_V3 + user_ns) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t af_packet_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] af_packet: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
static const char af_packet_auditd[] =
|
||||
"# AF_PACKET TPACKET_V3 LPE (CVE-2017-7308) — auditd detection rules\n"
|
||||
"# Flag AF_PACKET socket creation from non-root via userns.\n"
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -46,6 +45,10 @@
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
@@ -303,6 +306,34 @@ static skeletonkey_result_t cgroup_ra_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: unshare(CLONE_NEWUSER|CLONE_NEWNS) + cgroup v1
|
||||
* mount are Linux-only kernel surface; the release_agent primitive is
|
||||
* structurally unreachable elsewhere. Stub out cleanly so the module
|
||||
* still registers and `--list` / `--detect-rules` work on macOS/BSD
|
||||
* dev boxes — and so the top-level `make` actually completes there. */
|
||||
static skeletonkey_result_t cgroup_ra_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] cgroup_release_agent: Linux-only module "
|
||||
"(user_ns + cgroup v1 release_agent) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t cgroup_ra_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] cgroup_release_agent: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t cgroup_ra_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
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"
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -50,6 +47,13 @@
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
@@ -412,8 +416,6 @@ static long slab_active_kmalloc_1k(void)
|
||||
* Honest scope: this is structurally-fires-on-vuln + sentinel-arbitrated,
|
||||
* not a deterministic R/W. Same shape and same depth as xtcompat. */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
struct cls_route4_arb_ctx {
|
||||
/* msg_msg queues kept hot inside the userns child. The arb-write
|
||||
* sprays additional kaddr-tagged payloads into these and re-fires
|
||||
@@ -544,8 +546,6 @@ static int cls4_arb_write(uintptr_t kaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ---- Exploit driver ----------------------------------------------- */
|
||||
|
||||
static skeletonkey_result_t cls_route4_exploit(const struct skeletonkey_ctx *ctx)
|
||||
@@ -565,11 +565,6 @@ static skeletonkey_result_t cls_route4_exploit(const struct skeletonkey_ctx *ctx
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
fprintf(stderr, "[-] cls_route4: linux-only exploit; non-linux build\n");
|
||||
(void)ctx;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
#else
|
||||
/* Full-chain pre-check: resolve offsets before forking. If
|
||||
* modprobe_path can't be resolved, refuse early — no point doing
|
||||
* the userns + tc + spray + trigger dance if we can't finish. */
|
||||
@@ -782,7 +777,6 @@ static skeletonkey_result_t cls_route4_exploit(const struct skeletonkey_ctx *ctx
|
||||
}
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
/* ---- Cleanup ----------------------------------------------------- */
|
||||
@@ -803,6 +797,34 @@ static skeletonkey_result_t cls_route4_cleanup(const struct skeletonkey_ctx *ctx
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: cls_route4 / tc / netlink / msg_msg are
|
||||
* Linux-only kernel surface; the route4 dead-UAF is structurally
|
||||
* unreachable elsewhere. Stub out cleanly so the module still
|
||||
* registers and `--list` / `--detect-rules` work on macOS/BSD dev
|
||||
* boxes — and so the top-level `make` actually completes there. */
|
||||
static skeletonkey_result_t cls_route4_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] cls_route4: Linux-only module "
|
||||
"(net/sched cls_route4 + msg_msg) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t cls_route4_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] cls_route4: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t cls_route4_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
static const char cls_route4_auditd[] =
|
||||
"# cls_route4 dead UAF (CVE-2022-2588) — auditd detection rules\n"
|
||||
"# Flag tc filter operations with route4 classifier from non-root.\n"
|
||||
|
||||
@@ -43,15 +43,18 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
@@ -318,6 +321,34 @@ static skeletonkey_result_t dirty_cow_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: the Dirty COW primitive (writer thread via
|
||||
* /proc/self/mem + madvise(MADV_DONTNEED)) is Linux-only kernel
|
||||
* surface. Stub out cleanly so the module still registers and
|
||||
* `--list` / `--detect-rules` work on macOS/BSD dev boxes — and so
|
||||
* the top-level `make` actually completes there. */
|
||||
static skeletonkey_result_t dirty_cow_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] dirty_cow: Linux-only module "
|
||||
"(/proc/self/mem + madvise race) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t dirty_cow_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] dirty_cow: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t dirty_cow_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ---- Embedded detection rules ---- */
|
||||
|
||||
static const char dirty_cow_auditd[] =
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
/* _GNU_SOURCE is passed via -D in the top-level Makefile; do not
|
||||
* redefine here (warning: redefined). */
|
||||
@@ -42,6 +41,10 @@
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h" /* used inside this block only */
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -407,6 +410,34 @@ static skeletonkey_result_t dirty_pipe_cleanup(const struct skeletonkey_ctx *ctx
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: splice() / F_GETPIPE_SZ / posix_fadvise() are
|
||||
* Linux-only kernel surface; the Dirty Pipe primitive is structurally
|
||||
* unreachable elsewhere. Stub out cleanly so the module still
|
||||
* registers and `--list` / `--detect-rules` work on macOS/BSD dev
|
||||
* boxes — and so the top-level `make` actually completes there. */
|
||||
static skeletonkey_result_t dirty_pipe_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] dirty_pipe: Linux-only module "
|
||||
"(splice + PIPE_BUF_FLAG_CAN_MERGE) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t dirty_pipe_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] dirty_pipe: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t dirty_pipe_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* Embedded detection rules — keep the binary self-contained so
|
||||
* `skeletonkey --detect-rules --format=auditd` works without a separate
|
||||
* data-dir install. */
|
||||
|
||||
@@ -59,15 +59,20 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@@ -378,7 +383,6 @@ struct fuse_arb_ctx {
|
||||
bool trigger_armed;
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
static int fuse_arb_write(uintptr_t kaddr, const void *buf, size_t len,
|
||||
void *ctx_void)
|
||||
{
|
||||
@@ -504,15 +508,6 @@ static int fuse_arb_write(uintptr_t kaddr, const void *buf, size_t len,
|
||||
(unsigned long)kaddr);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int fuse_arb_write(uintptr_t kaddr, const void *buf, size_t len,
|
||||
void *ctx_void)
|
||||
{
|
||||
(void)kaddr; (void)buf; (void)len; (void)ctx_void;
|
||||
fprintf(stderr, "[-] fuse_arb_write: linux-only primitive\n");
|
||||
return -1;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* exploit */
|
||||
@@ -732,7 +727,6 @@ static skeletonkey_result_t fuse_legacy_exploit(const struct skeletonkey_ctx *ct
|
||||
* runs because the arb_write primitive re-fires the trigger and
|
||||
* needs the live spray.
|
||||
* --------------------------------------------------------------- */
|
||||
#ifdef __linux__
|
||||
if (ctx->full_chain) {
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[*] fuse_legacy: --full-chain requested — resolving "
|
||||
@@ -792,7 +786,6 @@ static skeletonkey_result_t fuse_legacy_exploit(const struct skeletonkey_ctx *ct
|
||||
}
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* Clean up our IPC queues and mapping. The kernel slab state
|
||||
* after the overflow may be unstable; we exit cleanly on success
|
||||
@@ -826,6 +819,28 @@ static skeletonkey_result_t fuse_legacy_exploit(const struct skeletonkey_ctx *ct
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: fsopen/fsconfig + userns+mountns clone are
|
||||
* Linux-only kernel surface. Stub out cleanly so the module still
|
||||
* registers and `--list` / `--detect-rules` work on macOS/BSD dev
|
||||
* boxes — and so the top-level `make` actually completes there. */
|
||||
static skeletonkey_result_t fuse_legacy_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] fuse_legacy: Linux-only module "
|
||||
"(fsopen + fsconfig + userns mount) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t fuse_legacy_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] fuse_legacy: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* embedded detection rules */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
@@ -58,16 +58,20 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
@@ -76,8 +80,6 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -91,31 +93,6 @@
|
||||
#ifndef SOL_IP
|
||||
#define SOL_IP 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ---------- macOS / non-linux build stubs ---------------------------
|
||||
* SKELETONKEY modules are dev-built on macOS (clangd / syntax check) and
|
||||
* run-built on Linux. The Linux-only types and IPT_SO_SET_REPLACE
|
||||
* constants are absent on Darwin; stub them so the .c file compiles
|
||||
* cleanly under either toolchain. The actual exploit body is gated
|
||||
* by `#ifdef __linux__` at runtime entry. */
|
||||
#ifndef __linux__
|
||||
#define CLONE_NEWUSER 0x10000000
|
||||
#define CLONE_NEWNET 0x40000000
|
||||
#define IPPROTO_RAW 255
|
||||
#define SOL_IP 0
|
||||
#define IPT_SO_SET_REPLACE 64
|
||||
struct ipt_replace { char dummy; };
|
||||
__attribute__((unused)) static int msgget(int a, int b) { (void)a;(void)b; errno=ENOSYS; return -1; }
|
||||
__attribute__((unused)) static int msgsnd(int a, const void *b, size_t c, int d) { (void)a;(void)b;(void)c;(void)d; errno=ENOSYS; return -1; }
|
||||
__attribute__((unused)) static ssize_t msgrcv(int a, void *b, size_t c, long d, int e) { (void)a;(void)b;(void)c;(void)d;(void)e; errno=ENOSYS; return -1; }
|
||||
__attribute__((unused)) static int msgctl(int a, int b, void *c) { (void)a;(void)b;(void)c; errno=ENOSYS; return -1; }
|
||||
#define IPC_PRIVATE 0
|
||||
#define IPC_CREAT 01000
|
||||
#define IPC_NOWAIT 04000
|
||||
#define IPC_RMID 0
|
||||
#define MSG_COPY 040000
|
||||
#endif
|
||||
|
||||
/* ---- Kernel range ------------------------------------------------- */
|
||||
|
||||
@@ -202,8 +179,6 @@ static skeletonkey_result_t netfilter_xtcompat_detect(const struct skeletonkey_c
|
||||
|
||||
/* ---- Exploit: userns reach + trigger + groom ---------------------- */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
/* Write uid_map and gid_map after unshare so we're root in userns.
|
||||
* This is the standard setgroups=deny pattern; without it the uid_map
|
||||
* write is rejected on modern kernels for unprivileged callers. */
|
||||
@@ -471,8 +446,6 @@ static int xtcompat_fire_trigger(int *out_errno)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __linux__ — close original primitive block */
|
||||
|
||||
/* ---- Full-chain arb-write primitive --------------------------------
|
||||
*
|
||||
* Pattern (FALLBACK — see module top-comment): the xt_compat 4-byte OOB
|
||||
@@ -509,8 +482,6 @@ static int xtcompat_fire_trigger(int *out_errno)
|
||||
* patched kernel the trigger returns EINVAL on step 2 and arb_write
|
||||
* returns -1 without ever queueing the follow-up. */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
struct xtcompat_arb_ctx {
|
||||
/* Spray queues kept hot across multiple arb_write calls. The
|
||||
* msg_msg slots seeded here are what the finisher uses as
|
||||
@@ -636,8 +607,6 @@ static int xtcompat_arb_write(uintptr_t kaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ---- Exploit driver ---------------------------------------------- */
|
||||
|
||||
static skeletonkey_result_t netfilter_xtcompat_exploit(const struct skeletonkey_ctx *ctx)
|
||||
@@ -661,11 +630,6 @@ static skeletonkey_result_t netfilter_xtcompat_exploit(const struct skeletonkey_
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
fprintf(stderr, "[-] netfilter_xtcompat: linux-only exploit; non-linux build\n");
|
||||
(void)ctx;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
#else
|
||||
/* Full-chain pre-check: resolve offsets before forking. If
|
||||
* modprobe_path can't be resolved, refuse early with the manual-
|
||||
* workflow help — no point doing the userns + spray + trigger
|
||||
@@ -944,7 +908,6 @@ static skeletonkey_result_t netfilter_xtcompat_exploit(const struct skeletonkey_
|
||||
fprintf(stderr, "[-] netfilter_xtcompat: child exit %d unexpected\n", rc);
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
/* ---- Cleanup ----------------------------------------------------- */
|
||||
@@ -963,6 +926,33 @@ static skeletonkey_result_t netfilter_xtcompat_cleanup(const struct skeletonkey_
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: setsockopt(IPT_SO_SET_REPLACE) + nfnetlink +
|
||||
* userns is Linux-only kernel surface. Stub out cleanly so the module
|
||||
* still registers and `--list` / `--detect-rules` work on macOS/BSD
|
||||
* dev boxes — and so the top-level `make` actually completes there. */
|
||||
static skeletonkey_result_t netfilter_xtcompat_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] netfilter_xtcompat: Linux-only module "
|
||||
"(xt_compat_target_to_user via SET_REPLACE) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t netfilter_xtcompat_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] netfilter_xtcompat: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t netfilter_xtcompat_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ---- Detection rules --------------------------------------------- */
|
||||
|
||||
static const char netfilter_xtcompat_auditd[] =
|
||||
|
||||
@@ -57,16 +57,20 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@@ -618,7 +622,6 @@ static long slabinfo_active(const char *slab)
|
||||
* Factored out so --full-chain can re-fire the trigger between
|
||||
* msg_msg sprays without duplicating the batch-building logic.
|
||||
* ------------------------------------------------------------------ */
|
||||
#ifdef __linux__
|
||||
static size_t build_trigger_batch(uint8_t *batch, size_t cap, uint32_t *seq)
|
||||
{
|
||||
(void)cap;
|
||||
@@ -792,7 +795,6 @@ static int nft_arb_write(uintptr_t kaddr, const void *buf, size_t len, void *vct
|
||||
usleep(20 * 1000);
|
||||
return 0;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* The exploit body.
|
||||
@@ -825,7 +827,6 @@ static skeletonkey_result_t nf_tables_exploit(const struct skeletonkey_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
/* --- --full-chain path --------------------------------------- *
|
||||
* Resolve offsets BEFORE doing anything destructive so we can
|
||||
* refuse cleanly on hosts where we have no modprobe_path. We run
|
||||
@@ -906,7 +907,6 @@ static skeletonkey_result_t nf_tables_exploit(const struct skeletonkey_ctx *ctx)
|
||||
close(sock);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* --- primitive-only path: fork-isolated trigger -------------- *
|
||||
* Fork: child enters userns+netns and fires the bug. If the
|
||||
@@ -1070,6 +1070,28 @@ static skeletonkey_result_t nf_tables_exploit(const struct skeletonkey_ctx *ctx)
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: nfnetlink + nf_tables UAF + userns is
|
||||
* Linux-only kernel surface. Stub out cleanly so the module still
|
||||
* registers and `--list` / `--detect-rules` work on macOS/BSD dev
|
||||
* boxes — and so the top-level `make` actually completes there. */
|
||||
static skeletonkey_result_t nf_tables_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] nf_tables: Linux-only module "
|
||||
"(nft_verdict_init UAF via nfnetlink) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t nf_tables_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] nf_tables: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ----- Embedded detection rules ----- */
|
||||
|
||||
static const char nf_tables_auditd[] =
|
||||
|
||||
@@ -43,16 +43,20 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@@ -585,7 +589,6 @@ static int bring_lo_up(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static size_t build_trigger_batch(uint8_t *batch, uint32_t *seq)
|
||||
{
|
||||
size_t off = 0;
|
||||
@@ -596,7 +599,6 @@ static size_t build_trigger_batch(uint8_t *batch, uint32_t *seq)
|
||||
put_batch_end(batch, &off, (*seq)++);
|
||||
return off;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* --full-chain arb-write context. The technique:
|
||||
@@ -617,8 +619,6 @@ static size_t build_trigger_batch(uint8_t *batch, uint32_t *seq)
|
||||
* mismatches as SKELETONKEY_EXPLOIT_FAIL rather than fake success.
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#define SPRAY_QUEUES_ARB 32
|
||||
|
||||
struct fwd_arb_ctx {
|
||||
@@ -721,8 +721,6 @@ static int nft_fwd_dup_arb_write(uintptr_t kaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Exploit driver.
|
||||
* ------------------------------------------------------------------ */
|
||||
@@ -748,11 +746,6 @@ static skeletonkey_result_t nft_fwd_dup_exploit(const struct skeletonkey_ctx *ct
|
||||
return pre;
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
fprintf(stderr, "[-] nft_fwd_dup: linux-only exploit; non-linux build\n");
|
||||
(void)ctx;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
#else
|
||||
if (!ctx->json) {
|
||||
if (ctx->full_chain) {
|
||||
fprintf(stderr, "[*] nft_fwd_dup: --full-chain — trigger + OOB-write "
|
||||
@@ -946,7 +939,6 @@ static skeletonkey_result_t nft_fwd_dup_exploit(const struct skeletonkey_ctx *ct
|
||||
fprintf(stderr, "[-] nft_fwd_dup: unexpected child rc=%d\n", rc);
|
||||
}
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
@@ -958,7 +950,6 @@ static skeletonkey_result_t nft_fwd_dup_cleanup(const struct skeletonkey_ctx *ct
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[*] nft_fwd_dup: cleaning up sysv queues + log\n");
|
||||
}
|
||||
#ifdef __linux__
|
||||
/* Best-effort drain of any leftover msg queues with IPC_PRIVATE
|
||||
* key owned by us. SysV doesn't enumerate by key, but msgctl
|
||||
* IPC_STAT walks /proc/sysvipc/msg to find them. */
|
||||
@@ -979,13 +970,38 @@ static skeletonkey_result_t nft_fwd_dup_cleanup(const struct skeletonkey_ctx *ct
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
if (unlink("/tmp/skeletonkey-nft_fwd_dup.log") < 0 && errno != ENOENT) {
|
||||
/* harmless */
|
||||
}
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: nf_tables / NETLINK_NETFILTER / SysV msg_msg
|
||||
* groom — all Linux-only kernel surface. Stub out so the module still
|
||||
* registers and the top-level `make` completes on macOS/BSD dev boxes. */
|
||||
static skeletonkey_result_t nft_fwd_dup_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] nft_fwd_dup: Linux-only module "
|
||||
"(nf_tables HW-offload OOB) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t nft_fwd_dup_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] nft_fwd_dup: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t nft_fwd_dup_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Embedded detection rules.
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
@@ -49,16 +49,20 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
#include "../../core/finisher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@@ -71,13 +75,10 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Kernel-range table
|
||||
@@ -187,8 +188,6 @@ static skeletonkey_result_t nft_payload_detect(const struct skeletonkey_ctx *ctx
|
||||
return SKELETONKEY_VULNERABLE;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* userns + netns entry: become root in the new user_ns so subsequent
|
||||
* netlink writes carry CAP_NET_ADMIN over our private net_ns.
|
||||
@@ -801,8 +800,6 @@ static int nft_payload_arb_write(uintptr_t kaddr, const void *buf, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Exploit body.
|
||||
* ------------------------------------------------------------------ */
|
||||
@@ -838,11 +835,6 @@ static skeletonkey_result_t nft_payload_exploit(const struct skeletonkey_ctx *ct
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] nft_payload: linux-only exploit; non-linux build\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
#else
|
||||
/* --- --full-chain path: resolve offsets in parent before doing
|
||||
* anything destructive. */
|
||||
if (ctx->full_chain) {
|
||||
@@ -1074,7 +1066,6 @@ static skeletonkey_result_t nft_payload_exploit(const struct skeletonkey_ctx *ct
|
||||
fprintf(stderr, "[-] nft_payload: unexpected child rc=%d\n", rc);
|
||||
}
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
@@ -1092,6 +1083,32 @@ static skeletonkey_result_t nft_payload_cleanup(const struct skeletonkey_ctx *ct
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: nf_tables / NETLINK_NETFILTER / SysV msg_msg
|
||||
* groom — all Linux-only kernel surface. Stub out so the module still
|
||||
* registers and the top-level `make` completes on macOS/BSD dev boxes. */
|
||||
static skeletonkey_result_t nft_payload_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] nft_payload: Linux-only module "
|
||||
"(nf_tables regset OOB) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t nft_payload_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] nft_payload: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t nft_payload_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Detection rule corpus.
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
@@ -37,13 +37,16 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mount.h>
|
||||
@@ -446,6 +449,28 @@ fail_workdir:
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: overlayfs / unshare(CLONE_NEWUSER|CLONE_NEWNS) /
|
||||
* setxattr("security.capability") are all Linux-only. Stub out so the
|
||||
* module still registers and the top-level `make` completes on
|
||||
* macOS/BSD dev boxes. */
|
||||
static skeletonkey_result_t overlayfs_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] overlayfs: Linux-only module "
|
||||
"(Ubuntu userns-overlayfs) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t overlayfs_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] overlayfs: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/* ----- Embedded detection rules ----- */
|
||||
|
||||
static const char overlayfs_auditd[] =
|
||||
|
||||
@@ -40,14 +40,17 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
@@ -371,6 +374,32 @@ static skeletonkey_result_t overlayfs_setuid_cleanup(const struct skeletonkey_ct
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: overlayfs copy-up / unshare(CLONE_NEWUSER|CLONE_NEWNS)
|
||||
* / mount("overlay", ...) are Linux-only. Stub out so the module still
|
||||
* registers and the top-level `make` completes on macOS/BSD dev boxes. */
|
||||
static skeletonkey_result_t overlayfs_setuid_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] overlayfs_setuid: Linux-only module "
|
||||
"(overlayfs setuid copy-up) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t overlayfs_setuid_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] overlayfs_setuid: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t overlayfs_setuid_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
static const char overlayfs_setuid_auditd[] =
|
||||
"# overlayfs setuid copy-up (CVE-2023-0386) — auditd detection rules\n"
|
||||
"# Same surface as CVE-2021-3493; share the skeletonkey-overlayfs key.\n"
|
||||
|
||||
@@ -28,13 +28,16 @@
|
||||
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "../../core/kernel_range.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
@@ -277,6 +280,27 @@ static skeletonkey_result_t ptrace_traceme_exploit(const struct skeletonkey_ctx
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
/* Non-Linux dev builds: PTRACE_TRACEME / PTRACE_ATTACH / user_regs_struct
|
||||
* are Linux-only ABI surface. Stub out so the module still registers and
|
||||
* the top-level `make` completes on macOS/BSD dev boxes. */
|
||||
static skeletonkey_result_t ptrace_traceme_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json)
|
||||
fprintf(stderr, "[i] ptrace_traceme: Linux-only module "
|
||||
"(PTRACE_TRACEME cred-escalation) — not applicable here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
static skeletonkey_result_t ptrace_traceme_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] ptrace_traceme: Linux-only module — cannot run here\n");
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user