安卓

首页 » 常识 » 常识 » Linux内核入门CVE
TUhjnbcbe - 2020/12/12 12:23:00
太原最好的白癜风医院 http://m.39.net/pf/a_4603784.html

本文为看雪论精华文章

看雪论坛作者ID:ChicWalk

一、漏洞情况分析看一下比较权威的网站关于这个漏洞的描述:Linux内核UFO到非UFO路径转换时的内存崩溃问题,在构建一个UFO数据包时,内核会使用MSG_MORE__ip_append_data()函数来调用ip_ufo_append_data()并完成路径的添加。但是在这两个send()调用的过程中,添加的路径可以从UFO路径转换为非UFO路径,而这将导致内存崩溃的发生。为了防止UFO数据包长度超过MTU,非UFO路径的copy=maxfraglen–skb-len将会变成false,并分配新的skb。这将会出发程序计算fraggap=skb_prev-len–maxfraglen的值,并将copy=datalen–transhdrlen–fraggap设置为false。我们把这段话的流程步骤来分一下:Linux内核UFO到非UFO路径转换时的内存崩溃问题,在构建一个UFO数据包时,内核会使用MSG_MORE__ip_append_data()函数来调用ip_ufo_append_data()并完成路径的添加。但是在这两个send()调用的过程中,添加的路径可以从UFO路径转换为非UFO路径,而这将导致内存崩溃的发生。为了防止UFO数据包长度超过MTU,非UFO路径的copy=maxfraglen–skb-len将会变成false,并分配新的skb。这将会出发程序计算fraggap=skb_prev-len–maxfraglen的值,并将copy=datalen–transhdrlen–fraggap设置为false。、Linux内核UFO到非UFO路径转换时的内存崩溃问题,在构建一个UFO数据包时,内核会使用MSG_MORE__ip_append_data()函数来调用ip_ufo_append_data()并完成路径的添加。但是在这两个send()调用的过程中,添加的路径可以从UFO路径转换为非UFO路径,而这将导致内存崩溃的发生。首先来分析这个第一句话。UFO和非UFO:UFO是修改传统的udp包在传输层的传输方式,传统的udp包在网络上传输的数据包不能大于mtu,当用户发送大于mtu的数据报文时,通常会在传输层(或者在特殊情况下在IP层分片,比如ip转发或ipsec时)就会按mtu大小进行分段,防止发送出去的报文大于mtu,为提升该操作的性能,新的网卡硬件基本都实现了UFO功能,可以使分段(或分片)操作在网卡硬件完成,此时用户态就可以发送长度大于mtu的包,而且不必在协议栈中进行分段(或分片)。UFO到非UFO路径转换:这句话,是漏洞利用的描述。看一下漏洞利用代码:

ints=socket(PF_INET,SOCK_DGRAM,0);intrv=send(s,buffer,size,MSG_MORE);//MSG_MORE标志位,表示发送的包使用的是ufo模式rv=setsockopt(s,SOL_SOCKET,SO_NO_CHECK,val,sizeof(val));通过修改标志位,导致系统如果再次发送的时候,ufo模式,变成了非ufo模式send(s,buffer,,0);这段代码,调用了两次send函数,第一次通过MSG_MORE,标志这个发送的包使用ufo模式,然后通过setsockopt,设置SO_NO_CHECK标志位,将socket的发包模式强行改为非ufo模式,从ufo变成了非ufo模式,然后发送了一个非ufo的包。、为了防止UFO数据包长度超过MTU,非UFO路径的copy=maxfraglen–skb-len将会变成false,并分配新的skb。第一张可能不太清楚,结合第二张看,这是别人画的,我直接拿来用了,怕大家看的麻烦上图是sk_buff的内存结构图,header的数据区是可以存储,frags

  • 里面的这些也是可以存储的,header的数据区很小,应该不是很大,如果一次发送很大的数据,应该是存储到fargs里面的。sk_buff,和skb_shared_info,虽然不是一个结构题,但是内存是相邻的。ufo是通过skb发送是不需要分包的,能发送超过mtu的数据。非ufo,每个skb的大小的数据,最大应该也只有当前网卡的mtu的大小,这个数值是可以动态设置的。超过这个mtu大小,就会在ip_ufo_append_data这个函数中被分包。

    while(length0){/*Checkiftheremainingdatafitsintocurrentpacket.*/copy=mtu-skb-len;//当前skb还可以copy多少数据skb-len=5if(copylength)copy=maxfraglen-skb-len;//copy=对齐的最大的拷贝字节-skb中已经存在的数据if(copy=0){//copy=0表示该分配一个新的sk_buff,因为最后一个已被完全填满char*data;//copy=0表明有些数据必须从当前ip片段中删除,并移至新片段unsignedintdatalen;unsignedintfraglen;unsignedintfraggap;unsignedintalloclen;structsk_buff*skb_prev;.......}copy=mtu-上一个传输数据进来的skb的数据大小,如果上一个传输进来的数据,大于mtu的大小,所以会被分包,进入copy=0,分配一个skb,将数据拷贝到新分配的数据中。如果上一个分配的是ufo,那么他的数据,是不会分包的,必然超过mtu的大小,然后再通过非ufo发送的时候,会去除原来ufo传输进来的数据,这个时候,会将ufo的包,当成非ufo,进行分包(重新分配一个skb,承载数据)。、这将触发程序计算fraggap=skb_prev-len–maxfraglen的值,并将copy=datalen–transhdrlen–fraggap设置为false。fraggap=ufo传输进来的skb的-对齐的最大的拷贝字节,如果fragga不等于0,就会触发拷贝逻辑,将ufoskb的数据拷贝到新分配的skb中。

    copy=datalen-transhdrlen-fraggap;//传输层首部和上个SKB多出的数据已复制,接着复制剩下的数据//copy=-0-0=-5if(copy0getfrag(from,data+transhdrlen,offset,copy,fraggap,skb)0){err=-EFAULT;kfree_skb(skb);gotoerror;}二、exp以及漏洞具体分析前面,指示分析了linux网络驱动出现问题的位置,可能不太好懂,我们结合漏洞利用代码来分析一下,就会很好理解了。这个漏洞,他的描述中没有写,但是,poc是通过ufo切换到非ufo,然后构造缓冲区溢出。覆盖了函数指针,然后触发这个被覆盖的函数的调用逻辑,进行提权。这里我们从后往前分析。、被覆盖的函数指针,和缓冲区溢出的位置。被覆盖的函数指针:

    structskb_shared_info{unsignedcharnr_frags;__u8tx_flags;unsignedshortgso_size;unsignedshortgso_segs;unsignedshortgso_type;structsk_buff*frag_list;structskb_shared_hwtstampshwtstamps;utskey;__beip_frag_id;atomic_tdataref;void*destructor_arg;//这个结构体的这个指针,这个指针会在skb被释放的时候,主动调用调用skb_frag_tfrags[MAX_SKB_FRAGS];};缓冲区溢出的位置(看名字,整个函数好像也只有这个一地方有copy)

    if(fraggap){skb-csum=skb_copy_and_csum_bits(skb_prev,maxfraglen,data+transhdrlen,fraggap,0);skb_prev-csum=csum_sub(skb_prev-csum,skb-csum);data+=fraggap;pskb_trim_unique(skb_prev,maxfraglen);}、如何造成溢出,如何溢出到函数指针的位置通过ufo到非uof的方式,来构造溢出环境。mtu为。第一次调用send(s,buffer,size,MSG_MORE);,会调用到__ip_append_data的ip_ufo_append_data函数,将传入的所有数据放到skb的缓冲区中。第二次调用send(s,buffer,,0);,由于已经设置过标志位了,所以直接越过了ip_ufo_append_data函数,接着往下走非ufo的逻辑了。poc中,传入的数据是,到ip_append_data后,upd头先加+8,ip头在+0,=5。下面的代码是__ip_append_data代码片段,在第二次发送send的时候,才会进入这里(下面代码包括注释摘自

  • 1
    查看完整版本: Linux内核入门CVE