VirtualBox NAT DHCP / BOOTP服务器漏洞
字数 1354 2025-08-27 12:33:37
VirtualBox NAT DHCP/BOOTP服务器漏洞分析
漏洞概述
本文详细分析VirtualBox NAT网络模式中DHCP/BOOTP服务器存在的两个高危漏洞:CVE-2016-5610(堆溢出漏洞)和CVE-2016-5611(越界读取漏洞)。这两个漏洞存在于VirtualBox 5.0.28和5.1.8之前的版本中,可导致虚拟机逃逸攻击。
0x001 技术背景
VirtualBox在NAT模式下会为每个虚拟机启用一个DHCP服务器,该服务器为guest虚拟机分配IP地址。默认配置下:
- Guest虚拟机IP地址范围:10.0.2.15
- 伪造的DHCP服务器IP:10.0.2.2
- DHCP服务器监听UDP端口68
# Guest虚拟机中查看网络配置
renorobert@ubuntuguest:~$ ifconfig enp0s3
enp0s3 Link encap:Ethernet HWaddr 08:00:27:b8:b7:4c
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feb8:b74c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:119 errors:0 dropped:0 overruns:0 frame:0
TX packets:94 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:11737 (11.7 KB) TX bytes:12157 (12.1 KB)
0x002 漏洞分析
1. DHCP数据包结构
漏洞存在于src/Vbox/Devices/Network/slirp/bootp.c文件中,DHCP数据包定义如下:
#define DHCP_OPT_LEN 312
/* RFC 2131 */
struct bootp_t {
struct ip ip; /**< header: IP header */
struct udphdr udp; /**< header: UDP header */
uint8_t bp_op; /**< opcode (BOOTP_REQUEST, BOOTP_REPLY) */
uint8_t bp_htype; /**< hardware type */
uint8_t bp_hlen; /**< hardware address length */
uint8_t bp_hops; /**< hop count */
uint32_t bp_xid; /**< transaction ID */
uint16_t bp_secs; /**< numnber of seconds */
uint16_t bp_flags; /**< flags (DHCP_FLAGS_B) */
struct in_addr bp_ciaddr; /**< client IP address */
struct in_addr bp_yiaddr; /**< your IP address */
struct in_addr bp_siaddr; /**< server IP address */
struct in_addr bp_giaddr; /**< gateway IP address */
uint8_t bp_hwaddr[16]; /** client hardware address */
uint8_t bp_sname[64]; /** server host name */
uint8_t bp_file[128]; /** boot filename */
uint8_t bp_vend[DHCP_OPT_LEN]; /**< vendor specific info */
};
2. BOOTP客户端管理
DHCP服务器维护一个BOOTPClient结构数组来跟踪所有分配的IP地址:
/** Entry in the table of known DHCP clients. */
typedef struct {
uint32_t xid;
bool allocated;
uint8_t macaddr[6];
struct in_addr addr;
int number;
} BOOTPClient;
/** Number of DHCP clients supported by NAT. */
#define NB_ADDR 16
int bootp_dhcp_init(PNATState pData) {
pData->pbootp_clients = RTMemAllocZ(sizeof(BOOTPClient) * NB_ADDR);
if (!pData->pbootp_clients)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
}
0x003 CVE-2016-5611 - 越界读取漏洞
漏洞位置
dhcp_find_option()函数中存在越界读取漏洞:
static uint8_t *dhcp_find_option(uint8_t *vend, uint8_t tag) {
uint8_t *q = vend;
uint8_t len;
while(*q != RFC1533_END) { // expects END tag in an untrusted input
if (*q == RFC1533_PAD) {
q++; // incremented without validation
continue;
}
if (*q == tag)
return q; // returns pointer if tag found
q++;
len = *q;
q += 1 + len; // length and pointer not validated
}
return NULL;
}
漏洞利用
- 攻击者发送特制的
DHCPDECLINE数据包,其中bp_vend字段填充RFC1533_PAD - 服务器调用
dhcp_find_option()寻找RFC2132_REQ_ADDR选项 - 由于缺少边界检查,函数可能返回指向DHCP缓冲区外的指针
- 服务器将外部数据当作IP地址处理,导致信息泄露
static void dhcp_decode(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size) {
case DHCPDECLINE:
pu8RawDhcpObject = dhcp_find_option(&bp->bp_vend[0], RFC2132_REQ_ADDR);
req_ip.s_addr = *(uint32_t *)(pu8RawDhcpObject + 2);
rc = bootp_cache_lookup_ether_by_ip(pData, req_ip.s_addr, NULL);
if (RT_FAILURE(rc)) {
bc->addr.s_addr = req_ip.s_addr;
slirp_arp_who_has(pData, bc->addr.s_addr);
LogRel(("NAT: %RTnaipv4 has been already registered\n", req_ip));
}
break;
}
泄露效果
通过伪造的ARP请求泄露主机内存数据:
renorobert@guest:~$ sudo tcpdump -vv -i eth0 arp
15:51:34.557995 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 45.103.99.109 (Broadcast) tell 10.0.2.2, length 46
0x004 CVE-2016-5610 - 堆溢出漏洞
漏洞位置
dhcp_decode_request()函数中缺少对bp_hlen字段的验证:
static int dhcp_decode_request(PNATState pData, struct bootp_t *bp, struct mbuf *m) {
switch (dhcp_stat) {
case RENEWING:
Assert((bp->bp_hlen == ETH_ALEN));
memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
bc->addr.s_addr = bp->bp_ciaddr.s_addr;
break;
case INIT_REBOOT:
Assert((bp->bp_hlen == ETH_ALEN));
memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
bc->addr.s_addr = ui32;
break;
}
}
漏洞利用
bp_hlen是1字节字段,最大可设置为255- 断言语句
Assert在release版本中不编译 - 攻击者可发送特制的
DHCPREQUEST数据包,控制bp_hlen和bp_hwaddr - 当复制
bp_hwaddr到BOOTPClient结构的macaddr字段时,导致堆缓冲区溢出
利用步骤
- 发送14个合法的
DHCPREQUEST数据包填充pbootp_clients数组 - 发送第15个特制的
DHCPREQUEST数据包,设置bp_hlen为较大值触发溢出 - 溢出会覆盖相邻的
uma_zone结构,控制函数指针
struct uma_zone {
uint32_t magic;
PNATState pData;
RTCRITSECT csZone;
const char *name;
size_t size;
ctor_t pfCtor; // 可被覆盖的函数指针
dtor_t pfDtor; // 可被覆盖的函数指针
zinit_t pfInit; // 可被覆盖的函数指针
zfini_t pfFini; // 可被覆盖的函数指针
uma_alloc_t pfAlloc; // 可被覆盖的函数指针
uma_free_t pfFree; // 可被覆盖的函数指针
// ... 其他字段
};
崩溃现场
Thread 11 "EMT" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fd20e4af700 (LWP 27148)]
0x00007fd1df22308e in ?? () from /usr/lib/virtualbox/VBoxDD.so
=> 0x7fd1df22308e: call QWORD PTR [rbx+0x70]
0x005 漏洞修复
Oracle在2016年10月的重要补丁更新中修复了这两个漏洞:
- 在
dhcp_find_option()中添加边界检查 - 在
dhcp_decode_request()中严格验证bp_hlen字段
0x006 总结
这两个漏洞展示了VirtualBox NAT网络实现中的严重安全问题:
- CVE-2016-5611:由于缺乏输入验证导致的越界读取,可泄露主机内存信息
- CVE-2016-5610:堆溢出漏洞结合特定内存布局可实现代码执行
建议用户升级到VirtualBox 5.0.28或5.1.8及以上版本以修复这些漏洞。