2020年2月,我们收到了一份提交文件,详细介绍了Oracle VirtualBox中的一个漏洞,该漏洞可能导致libalias数据包别名库中的越界访问。研究人员Vishnu Dev TJ向我们报告了此问题,并在打补丁时最终将其分配编号为CVE-2020-7454。在分析提交内容时,我发现该漏洞也存在于FreeBSD中。这篇文章分析了CVE-2020-7454在VirtualBox和FreeBSD上的影响,并说明为什么维护第三方或共享代码是一项艰巨的任务。
对于不熟悉的人,libalias是一个用于对IP数据包进行别名和去别名的库。它还用于网络地址转换(NAT)。凭借其NAT功能,可以理解为什么VirtualBox会将其用于各种功能。但是,libalias源自FreeBSD。VirtualBox维护它自己的库分支。不幸的是,此漏洞在各个版本之间都存在。它导致FreeBSD内核和用户模式下的出界(OOB)访问。该漏洞已在VirtualBox 6.1.6和FreeBSD-SA-20:12中修复。
0x01 Oracle VirtualBox
以下分析基于VirtualBox 6.1.4。该漏洞的根本原因在于AliasHandleUdpNbtNS()函数,该函数负责解析UDP端口137上的NetBIOS名称服务数据包。下面以简化形式显示了相关部分。
AliasHandleUdpNbtNS(...) { /* ... snip ... */ /* Calculate data length of UDP packet */ uh = (struct udphdr *)ip_next(pip); nsh = (NbtNSHeader *)udp_next(uh); p = (u_char *) (nsh + 1); pmax = (char *)uh + ntohs(uh->uh_ulen); /* ancount) != 0) { p = AliasHandleResource( ntohs(nsh->ancount), (NBTNsResource *) p, pmax, &nbtarg ); } /* ... snip ... */ } AliasHandleResource(..., char *pmax, ...) { /* ... snip ... */ switch (ntohs(q->type)) { case RR_TYPE_NB: q = (NBTNsResource *) AliasHandleResourceNB( q, pmax, nbtarg ); break; /* ... snip ... */ }
上面的代码片段中的(1)uh_ulen是UDP头长度字段,该字段是从不受信任的guest OS发送的。可能的最大值是0xFFFF。通过使用较大的uh_ulen值,攻击者可以生成过大的pmax 值.。接下来,如果UDP数据包包含应答记录,并且其类型指定为NetBIOS General Service,则执行将到达AliasHandleResourceNB()函数
AliasHandleResourceNB(..., char *pmax, ...) { /* ... snip ... */ while (nb != NULL && bcount != 0) { if ((char *)(nb + 1) > pmax) { /* oldaddr, &nb->addr, sizeof(struct in_addr))) { /* addr = nbtarg->newaddr; /* <--- (4) */ } /* ... snip ... */ nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB); } }
在上面的代码片段的(2)处,while循环尝试在数据包中查找旧地址,并将其替换为新地址,直到pmax。由于pmax该值较大,因此将在(3)处发生越界读取。此外,如果找到旧地址,它也可能在(4)处写OOB。
guest OS上的攻击者可以构造无效的UDP标头长度来触发主机OS上的OOB访问。UDP端口137在VirtualBox的默认配置中处于打开状态。为了解决此漏洞,Oracle 在上面的代码片段1中添加了对(1)所示UDP标头长度的验证。
0x02 FreeBSD 12.1
如上所述,libalias库源自FreeBSD。在分析Oracle VirtualBox中的提交时,我发现此漏洞在ipfw用于NAT 时也会影响FreeBSD 。所述ipfw分组过滤器包含完成NAT的两种不同的方法:一个在内核空间和一个在用户空间。两种实现都使用libalias提供的相同函数。这意味着可以natd根据NAT配置在内核或用户态程序()中触发该漏洞。
这是触发内核中的漏洞所需的FreeBSD 12.1 Release的相关配置:
/boot/loader.conf alias_nbt_load="YES" /etc/rc.conf gateway_enable="YES" firewall_enable="YES" firewall_nat_enable="YES" firewall_nat_interface="em0" firewall_type="OPEN"
OOB访问发生在中alias_nbt.ko,这是已加载的内核模块。
如果NAT配置基于用户域,则OOB访问libalias_nbt.so将在natd进程的上下文中发生。两种情况都可以在不进行身份验证的情况下远程触发。
在分析过程中,我发现了另一个惊喜。FreeBSD中的libalias库包含CuSeeMe协议处理中同一漏洞的另一个变体,该协议默认情况下侦听UDP端口7648。
AliasHandleCUSeeMeIn(...) { /* ... snip ... */ end = (char *)ud + ntohs(ud->uh_ulen); /* <--- untrusted UDP header length */ if ((char *)oc data_type) == 101) /* Find and change our address */ for (i = 0; (char *)(ci + 1) <= end && i < oc->client_count; i++, ci++) if (ci->address == (u_int32_t) alias_addr.s_addr) { /* address = (u_int32_t) original_addr.s_addr; /* <--- OOBW */ break; } } }
但是,该漏洞在VirtualBox中不存在,这意味着FreeBSD 的补丁与VirtualBox的补丁不同。在UdpAliasIn()和UdpAliasOut()函数中都添加了一个验证,这是处理UDP数据包的适当级别。它可以有效地修补任何包含此类漏洞的协议。
0x03 分析总结
此研究表明,维护第三方或共享代码是一项艰巨的任务。即使对源代码进行了修补或更新,也必须对上游产品进行这些更改。甚至当你是在与第三方同步,共享代码漏洞具有双倍的影响,因为它影响其他的产品,Oracle VirtualBox在用户和安全研究人员中越来越受欢迎。
本文翻译自:https://www.zerodayinitiative.com/blog/2020/6/29/cve-2020-7454-killing-two-systems-with-one-bug-in-libalias如若转载,请注明原文地址: