luanch.sh shows there are two custom device named vdd.
1 2
$ ./qemu-system-x86_64 -device help 2>&1 | grep VDD name "VDD", bus PCI, desc "KeenLab virtualized Devices For Testing D"
we can use some commands to find these devices and their io port/memroy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# lspci 00:00.0 Class 0600: 8086:1237 00:01.3 Class 0680: 8086:7113 00:03.0 Class 0200: 8086:100e 00:01.1 Class 0101: 8086:7010 00:02.0 Class 0300: 1234:1111 00:05.0 Class 00ff: 1234:2333 00:01.0 Class 0601: 8086:7000 00:04.0 Class 00ff: 1234:2333 # cat /proc/iomem ... fe900000-fe9fffff : 0000:00:04.0 fea00000-feafffff : 0000:00:05.0 ... # cat /proc/ioports ... c000-c0ff : 0000:00:04.0 c100-c1ff : 0000:00:05.0 ...
OOBW
In vdd_mmio_write, there is a out-of-bound write vulnerability which copys QEMU heap memory to guset physical memory when we set dma_len larger than sizeof(dam_buf).
First, we allocate a buffer and get it’s physical address. Then we set dma_state->dst to our buffer and set dma_len larger than sizeof(dma_buf). Finally, we trigger phys_mem_write by writel(0, piomem + 32). By searching the output, we can find libc addresses and program addresses then calculate the base address of program/libc.
Becasue the QEMU is launched with --nographic -append 'console=ttyS0', so we can simply invoke system(cmd) to run a command in host machine and the output will show in console.
To invoke system(cmd), We need to:
set opaque->dma_state->phys_mem_read to system
set opaque->dma_buf to cmd
make sure opaque->dma_state->cmd != 0.
In vdd_linear_write, when addr == 0, a buffer will be allocated with size of opaque->dma_len. And the data in opaque->dma_state->src with length of opaque->dma_len will be copied to opaque->buf, then copied to opaque->dma_state->dst