CVE-2020-14386: Linux kernel权限提升漏洞 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

CVE-2020-14386: Linux kernel权限提升漏洞

ang010ela 资讯 2020-10-12 10:26:40
652040
收藏

导语:Unit 42研究人员在Linux kernel源代码中发现了一个内存破坏漏洞,漏洞CVE编号为CVE-2020-14386。

Unit 42研究人员在Linux kernel源代码中发现了一个内存破坏漏洞,漏洞CVE编号为CVE-2020-14386。攻击者利用该漏洞可以从特权用户提权到Linux 系统的root用户。

技术细节

该漏洞来源于net/packet/af_packet.c 文件的tpacket_rcv 函数中,是由于算术问题引发的内存破坏。该漏洞是2008年7月引入的(commit 8913336),从2016年2月开始触发内存破坏(commit 58d19b19cd99),很多开发者都尝试修复该漏洞,但提出的补丁都不足以预防内存破坏。

为触发该漏洞需要创建一个含有TPACKET_V2 ring缓存和 PACKET_RESERVE为特定值的原始包(AF_PACKET domain, SOCK_RAW type )。

image.png

headroom 是用户指定大小的缓存,会在ring 缓存接收每个包的真实数据之前分配。该值可以通过setsockopt 系统调用在用户空间来设置: 

image.png

图 1. Setsockopt设置 – PACKET_RESERVE

如图 1所示,会检查该值是否小于INT_MAX。该值是在补丁(https://lore.kernel.org/patchwork/patch/784412/)中新加的以防packet_set_ring 中最小帧大小计算溢出。然后回验证页面是否是为接收或者传输的ring缓存分配的。这么做的目的是预防tp_reserve 域和ring buffer之间的不连续。

在设置了tp_reserve 值后,就可以通过含有PACKET_RX_RING的setsockopt系统调用来触发ring缓存的分配:

image.png图 2. From manual packet – PACKET_RX_RING option.

这是在packet_set_ring函数中实现的。在ring缓存分配之前,会有许多对从用户空间接收的 tpacket_req结构的检查:

image.png

图 3. packet_set_ring 函数中的安全检查

从图 3中可以看出,首先会计算最小的帧大小,然后与从用户空间接收到的值进行对比验证。检查确保了在 tpacket 头结构的每个帧和tp_reserve 字节数之间的有空间。

在做完所有检查之后,ring缓存本身就会通过 alloc_pg_vec调用来分配:

image.png

图 4. packet_set_ring 函数中调用ring缓存分配函数

如上图所示,block size(区块大小)是由用户空间控制的。alloc_pg_vec函数会分配 pg_vec数组,然后通过alloc_one_pg_vec_page 函数分配给每一个区块链:

image.png

图 5. alloc_pg_vec实现

alloc_one_pg_vec_page 函数会用 __get_free_pages 来分配区块页:

image.png

图 6. alloc_one_pg_vec_page 实现

区块分配后,pg_vec 数组就会保存在嵌入在 packet_sock结构中的packet_ring_buffer结构。

当接口接收到包后,与tpacket_rcv函数绑定的socket、包数据、TPACKET 元数据都会写入到ring缓存中。

漏洞

图7是 tpacket_rcv 函数的实现。首先,会调用skb_network_offset 来提取接收到的包的网络头的偏移值到maclen中。在本例中,大小为14字节,即以太网header的大小。之后,会根据TPACKET header、 maclen 和tp_reserve值来计算netoff。

但是计算的过程可能会溢出,因为 tp_reserve的类型是 unsigned int ,netoff的类型是unsigned short,而对tp_reserve 值的唯一限制是小于INT_MAX。

image.png

图 7. tpacket_rcv中的算术计算

如图 7所示,如果包中设置了PACKET_VNET_HDR ,就会加入sizeof(struct virtio_net_hdr) 。最后,以太网header的偏移量会计算会保存到macoff中。

如图 8所示, virtio_net_hdr结构会用 virtio_net_hdr_from_skb函数下入ring缓存中。 h.raw 指向ring 缓存中当前空闲的帧。

image.png

图 8. 调用tpacket_rcv中的 virtio_net_hdr_from_skb函数

研究人员设想有可能利用该溢出将netoff变成一个更小的值,所以macoff 可以接收一个大于block size的值,并尝试写入缓存中。

但是存在以下检查,所以无法实现:

image.png

图 9. tpacket_rcv 函数中的另一个检查

但是该检查并不足以预防内存破坏,因为仍然可以通过溢出netoff 将macoff变成一个小一点的值。比如,将macoff变成小于10字节的 sizeof(struct virtio_net_hdr),然后用 virtio_net_hdr_from_skb 写入缓存的边界。

原语

通过控制macoff的值,就可以在控制的偏移量中初始化 virtio_net_hdr 结构。 virtio_net_hdr_from_skb 函数会首先将整个struct 零化,然后根据skb结构初始化结构内的所有域。

image.png

图 10. virtio_net_hdr_from_skb 函数的实现

但可以设置skb 只让零写入结构中。因此,就可以在__get_free_pages 分配中零化1-10个字节。无需任何堆操作技巧就可以立刻引发kernel 奔溃。

POC

触发该漏洞的PoC代码参见:https://www.openwall.com/lists/oss-security/2020/09/03/3

漏洞利用

漏洞利用过程参见:https://unit42.paloaltonetworks.com/cve-2020-14386/

补丁

研究人员提出的补丁参见:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=acf69c946233259ab4d64f8869d4037a198c7f06

The code shown represents the author's proposed patch for CVE-2020-14386. 图 11. 研究人员提出的补丁

补丁的思想是如果将netoff 的类型从unsigned short 修改为unsigned int,就可以检查是否会超过USHRT_MAX,如果超过的化就丢弃该包,以防进一步利用。

总结

研究人员其实也很奇怪Linux kernel中至今还会存在如此简单的算术安全问题,而且之前没有被发现过。同时,非特权的用户空间也暴露出了本地权限提升的巨大攻击面。

本文翻译自:https://unit42.paloaltonetworks.com/cve-2020-14386/如若转载,请注明原文地址:
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务