一.前言
CVE-2019-15890是QEMU (quick emulator)的SLIRP模块的UAF漏洞,目前未披露POC,这里针对它进行分析和构造测试POC。
二.背景知识
QEMU(quick emulator)是一款由Fabrice Bellard等人编写的免费的可执行硬件虚拟化的(hardware virtualization)开源托管虚拟机(VMM)。
QEMU内部网络分为两部分:
提供给客户的虚拟网络设备(例如,PCI网卡)。
与模拟NIC交互的网络后端(例如,将数据包放入主机的网络)。
SLIRP模块是与模拟NIC交互的网络后端,默认情况下,QEMU会为该guest虚拟机创建一个SLiRP用户网络后端和一个适当的虚拟网络设备。
三.漏洞成因与细节
1.漏洞位置
漏洞发生在/slirp/src/ip_input.c的ip_reass函数,SLIRP在接收数据包,处理IP分片的组合,修剪重叠的数据片段时,在line-303 free掉指针后,又在line-304继续引用,造成UAF漏洞。
2.代码逻辑和数据结构
通常发送的IP包可以采用分片机制,ip_ress函数就是SLIRP模块内对分片进行组合的函数,内部还会修剪分片重叠的数据片段。
结构ip是目前收到需要组合的IP分片(fragment)。
结构ip的内存载体是结构mbuf的成员m_ext或m_dat。
(一般使用mbuf->m_dat,当数据包过大时,会扩展内存,动态申请改用mbuf->m_ext,
mbuf->m_data是操作数据的目前位置,mbuf->m_len是操作数据的剩余长度。)
结构mbuf以链表方式存储索引,结构ipq是头节点结构。
3.路径分析
(1).在m_free函数内,我们可以选定在line-107处,free掉m->m_ext内存。
所以需m->m_flags & M_EXT为真,即mbuf需以扩展内存存储数据。
在slirp_input函数接收数据包后,在line-775处会对mbuf的空闲内存大小和数据包的总大小进行比较,关系为M_FREEROOM(m)<pkt_len+TCPIPHDR_DELTA+2。
当pkt_len>M_FREEROOM(m)-(TCPIPHDR_DELTA+2)时,会调用m_inc函数,在line-157处改用mbuf->m_ext扩展内存存储数据。
所以第一个数据包的总大小需>M_FREEROOM(m)-(TCPIPHDR_DELTA+2)。
(2).在ip_reass函数的line-269处,这里灵活一下,选择让第一个分片,进行后面的数据片段修剪,即变量q指向第一个IP分片。
所以第一个IP分片的ip->frag_off需大于第二个IP分片的ip->frag_off。
(3).在修剪数据的代码块,line-296处,往下有修改内存大小和从队列删除两条路径,满足一定关系时,走第二条路径,选择从队列删除第一个ip分片。
(变量q为第一个包,变量ip为第二个包)
所以ip->ip_len >= q->ipf_len + q->ipf_off – ip->ip_off的关系需成立。
(4).总结
A.一共发送两个IP分片,ID字段值一致,触发SLIRP的ip_reass函数。
B.第一个数据包的总大小需>M_FREEROOM(m)-(TCPIPHDR_DELTA+2),即第一个IP分片的payload_len值>=0x5D0。
C.第一个IP分片的ip->frag_off需大于第二个IP分片的ip->frag_off。
D.满足关系ip->ip_len >= q->ipf_len + q->ipf_off – ip->ip_off。
4.POC构造
A.如下标记T4,两个分片的ID值为0x1122。
B.标记T1,第一IP分片的payload_len==0x5D0。
C.标记T2,第二IP分片的frag_off为0x5D0,第一IP包的frag_off为0x5D8。
D.标记T3,第二IP分片的payload_len==0x5D8。
5.触发效果
ip_deq函数从队列删除IP分片时,会引用free掉的内存。
触发前内存布局。
触发后内存布局。
qemu崩溃。
四.漏洞修复
漏洞的修复主要调换了m_free()和ip_deq()的位置。
补丁链接:
五.漏洞危害
六.参考文献
1.https://zh.wikipedia.org/wiki/QEMU
2.https://wiki.qemu.org/Documentation/Networking
3.https://github.com/vishnudevtj/exploits/tree/master/qemu/CVE-2019-14378
发表评论
您还未登录,请先登录。
登录