作者:maldiohead@ 360 NirvanTeam
漏洞简述:
CVE-2018-4407是XNU内核的BSD网络模块的一个内核堆溢出漏洞,可以造成内核崩溃
受影响的系统有:
- macOS 10.13.6及以下
- iOS11 及以下
漏洞分析
twitter上的poc:
send(IP(dst=“Target IP“,options=[IPOption(“A”*8)])/TCP(dport=2323,options=[(19, “1"*18),(19, “2”*18)]))
本次分析以这个poc为说明。
通过wireshark抓包,根据ip头数据结构,发现ip头数据是没问题的,然后根据options的结构体发现ip Options的数据格式不合法。Ip options主要是用来测试,调试等目的用的。
IP options 的结构说明
公开的poc网络请求的数据包填充了8字节的options数据。下图是抓包得来的数据。
Poc中的ip options的数据
可以发现ip options的数据完全不合法,
通过分析XNU内核代码,我们找到了处理ip options的相关处理函数ip_dooptions
文件位置(darwin-xnu\bsd\netinet\ip_input.c),在函数ip_dooptions中会循环解析options中的数据,如果中间某次出错就会直接goto到bad流程中。结合poc我们会看到这里optlen的值是0x41, cnt是0x8所以这里会从3256行直接跳到bad流程中,而在bad流程中则会调用icmp_error函数(icmp_error的目的是构造一个类型错误的数据包,来响应来自远程的错误的ip数据包)。
解析ip option数据
在函数icmp_error中在下面这句导致了溢出:
m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
这是一个内存拷贝函数,会拷贝大小为icmplen长度的对象n中数据到icp->icmp_ip这个缓冲区中。所以对于这个内存拷贝函数,需要确定icmplen和目的缓冲区大小,就明确了为什么会产生这个漏洞。首先我们看一下icmplen的长度,通过分析会发现icmplen由下面这句代码确定:
icmplen = min(oiphlen + icmpelen, min(nlen, oip->iplen));
这里oiphlen是ip头与ipoptions之和即28字节,nlen是原始packet的长度,这里必然是大于oip->ip_len的,而oip->ip_len的长度是88字节,由于这个包是TCP包。所以icmpelen由281行代码确定(如下图)。
icmplen相关代码
通过分析数据包及代码,可以知道tcphlen长度为60字节 ,icmp_datalen等于8,oip->ip_len等于88,所以icmpelen的值是60。分析完了所有与icmplen值相关的数据,最终确定icmplen这里的值是88。
所以接下来就是分析icp->icmp_ip缓冲区的大小,在294或296初始化一个mbuf,而icp就是属于mbuf对象的m_data成员。所以这里首先要判断m到底是由哪一行决定的。
分配m对象
根据前面的判断,我们可以知道sizeof(struct ip) + ICMP_MINLEN + icmplen)
大小是88,所以对于到底值调用294行的函数初始化mbuf还是296行,主要是看MHLEN的大小,查看了MHLEN的宏定义,由于m_hdr ,pkthdr的结构有点复杂
MHLEN定义
所以想直接知道MHLEN的准确值比较麻烦。于是我进行了内核调试,获取了这个值。
MHLEN得值
很明显MHLEN的值是0x57也就是87,所以mbuf的初始化就在296行这里进行的。
也就是调用m_getcl函数,对于这个函数,可以看到在3732行进行了mbuf对象内存的申请,mcache_alloc这个函数也是相当复杂的,这里对于分析这个漏洞没多大关系,就不再关注具体是怎么分配对象了。。
初始化mbuf
重点是MBUF_INIT这个宏代码(如下图),这里首先在888行判断pkthdr的值是否为0,结合上图的3726行代码,就会发现mbuf->m_data指针指向的是m_pktdat.
MBUF_INIT代码
对于m_ pktdat 定义:
#define m_pktdat M_dat.MH.MH_dat.MH_databuf
和mbuf的定义:
mbuf的定义
所以我们知道了m->m_data的大小是87字节。在这里icp指向的地址是m->m_data
对于代码:
m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
结合前面的计算,我们知道了icp->icmp_ip就等于 &m->m_data[7]
,而此刻icmplen的值是88,icp->icmp_ip的大小之后87-8=79 ,所以拷贝过程中就造成了堆内存溢出。
对于Twitter上的poc来说,只要构造出来的数据包大于79字节即可造成溢出,
同时对于ip options并不需要填充8字节,只要能够造成在调用到bad流程就可以,经过我的测试,这里ip options最小只需要1字节即可。总体的数据包大于79,就可以造成溢出。从而导致内核崩溃。
这个漏洞能利用吗?
通过分析,可以发现mbuf最大长度是2000字节,所以我们最大可以构造这么大的长度的数据包,来存放我们的shellcode,但是要想稳定利用,还得堆喷和内核信息泄露的漏洞结合起来,来达到远程代码执行的目的。
所以单个的这个漏洞很难实现稳定的远程代码执行的目的。
引用:
- CVE-2018-4407 poc:
https://twitter.com/ihackbanme/status/1057811965945376768
- Structure of the IP Datagram:
http://www.rhyshaden.com/ipdgram.htm
- Kernel RCE caused by buffer overflow in Apple’s ICMP packet-handling code
https://lgtm.com/blog/apple_xnu_icmp_error_CVE-2018-4407
- Memory Buffers, Socket Manipulation, and Socket Input/Output