CVE-2020-14386 POC复现

CVE-2020-14386 POC复现

0x1 测试环境

记录一些调试和编译时期的坑:

  • 需要准备编译环境:

    wget http://archive.ubuntu.com/ubuntu/pool/universe/d/dwarves-dfsg/dwarves_1.17-1_amd64.deb
    dpkg -i dwarves_1.17-1_amd64.deb
    
    [BTF: .tmp_vmlinux.btf: pahole version v1.15 is too old, need at least v1.16](https://askubuntu.com/questions/1280414/btf-tmp-vmlinux-btf-pahole-version-v1-15-is-too-old-need-at-least-v1-16)
    

0x2 漏洞分析 & 动态调试

Patch:

Using tp_reserve to calculate netoff can overflow as tp_reserve is unsigned int and netoff is unsigned short.

This may lead to macoff receving a smaller value then sizeof(struct virtio_net_hdr), and if po->has_vnet_hdr is set, an out-of-bounds write will occur when calling virtio_net_hdr_from_skb.

 net/packet/af_packet.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 29bd405adbbd..d37435906859 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2168,7 +2168,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 	int skb_len = skb->len;
 	unsigned int snaplen, res;
 	unsigned long status = TP_STATUS_USER;
-	unsigned short macoff, netoff, hdrlen;
+	unsigned short macoff, hdrlen;
+	unsigned int netoff;
 	struct sk_buff *copy_skb = NULL;
 	struct timespec64 ts;
 	__u32 ts_status;
@@ -2237,6 +2238,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 		}
 		macoff = netoff - maclen;
 	}
+	if (netoff > USHRT_MAX) {
+		atomic_inc(&po->tp_drops);
+		goto drop_n_restore;
+	}
 	if (po->tp_version <= TPACKET_V2) {
 		if (macoff + snaplen > po->rx_ring.frame_size) {
 			if (po->copy_thresh &&

Patch中描述的很详细,在tpacket_rcv中,由于netofftp_reservesize不一致导致整数溢出漏洞,从而越界读写。

整数溢出

// /net/packet/af_packet.c:2231
	netoff = TPACKET_ALIGN(po->tp_hdrlen +
				       (maclen < 16 ? 16 : maclen)) +
				       po->tp_reserve;

这个地方,po->tp_reserve值为0xffb4,得到的maclen0xe,经过(maclen < 16 ? 16 : maclen) 计算,maclen值变成0x10po->tp_hdrlen的值为0x43,经计算,netoff0x10004,由于netoffunsigned short类型,所以截断导致netoff值为0x4

pwndbg> p $eax
$1 = 65540

➜  ~ rax2 65540
0x10004

截断:

然后经过一个计算,通过netoff设置maclen的值为0

if (po->has_vnet_hdr) {
      netoff += sizeof(struct virtio_net_hdr);
      do_vnet = true;
}

macoff = netoff - maclen;

越界访问

前期设置netoffmaclen都是为了越界访问做准备:

	if (do_vnet &&
	    virtio_net_hdr_from_skb(skb, h.raw + macoff -
				    sizeof(struct virtio_net_hdr),
				    vio_le(), true, 0))

virtio_net_hdr_from_skb是个inline函数,h.raw为存储一个内核地址0xffffc90000269000maclean的值为0sizeof(struct virtio_net_hdr)0xa,计算的值存在rdx中,rdx=0xffffc90000268ff6

0xffffc90000268ff6:     Cannot access memory at address 0xffffc90000268ff6

此时进入virtio_net_hdr_from_skb

static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
					  struct virtio_net_hdr *hdr,
					  bool little_endian,
					  bool has_data_valid,
					  int vlan_hlen)
{
	memset(hdr, 0, sizeof(*hdr));   /* no info leak */

导致越界访问,内核Crash。

Crash

0x3 POC

POC

0x4 Reference

CVE-2020-14386:Linux内核AF_PACKET权限提升漏洞分析

oss-security - CVE-2020-14386: Linux kernel: af_packet.c

posted @ 2021-02-03 11:44  Yisumi  阅读(1102)  评论(1编辑  收藏  举报