CVE-2015-7504
此漏洞算是CVE-2015-5165
的扩展。
前置知识
CRC
的用法作用及其逆向构造。
搭建环境
和CVE-2015-5165
一起搭建即可。
http://codemx.cn/2016/04/30/Understand01/
漏洞分析
漏洞点,pcnet.c:1082
,pcnet_receive
函数中,src
数组的下标size
未上限检测,进而导致的数组越界,p
初始为src
,while
循环会不断p++
直到p == &src[size]
才会停止,所以当size == 0x1000
时(也是最大时),跳出while
循环的p
已经指向了s->buffer
的后面那个元素,查看得知其为一个结构体指针:
1 | typedef struct PCNetState_st PCNetState; |
查找qemu_irq
的定义,为IRQState
的结构体指针:
1 | //typedef.h |
再查看IRQState
的元素结构,看到qemu_irq_handler
元素带有handler
字样,猜测其为函数指针:
1 | // /hw/core/irq.c:31 |
查看qemu_irq_handler
定义,确认其的确为函数指针:
1 | // /hw/xtensa/irq.h:10 |
由于IRQState
中存在一个函数指针,使劫持执行流成为可能。
查找其引用发现在qemu_set_irq
中被调用:
1 | // /hw/core/irq.c |
在查找qemu_set_irq
的引用,发现在qemu_update_irq
中被引用,再查找qemu_update_irq
的引用,发现在pcnet_reveive
的结束末尾处恰好调用了pcnet_update_irq
:
1 | ... |
所以漏洞触发链:pcnet_ioport_write
=>pcnet_ioport_writew
=>pcnet_csr_writew
=>pcnet_transmit
=>pcnet_receive
因为结构体跨越文件较多,所以这里可以用Understand
等源码阅读器来搜索阅读结构体。
主要分为几个步骤:
- 配置
pcnet
网卡的各项数据。(我觉得最难理解的地方。。。我复现完对这一块仍然很疑惑,有的地方不知其原因) patch crc
,构造数据包,原理在前置知识中给出。- 将数据包地址填入
tx_desc
中并发送触发pcnet_transmit
。
调试与poc
poc.c
1 |
|
漏洞利用
因为我们只能覆盖irq
这个结构体指针的后四个字节,所以我们没办法完全将其劫持到fake_struct
上,只能在其原来位于的地址附近伪造,其原地址是main_arena
上的堆地址,所以我们必须泄露出heap_base
,这个是有概率的,且不像phy_base & text_base
这么稳定,其次因为设备的PCNetState
也是在main_arena
的堆上的,所以我们可以在s->buffer
中伪造fake_IRQState
,然后将irq
劫持到fake_IRQState
上。
在实际调试时遇到的两个问题:
触发链的问题,经过审源码发现,
pcnet_transmit
并非只有上面所提到的那一条链,在pcnet_poll_timer
=>pcnet_poll
=>pcnet_transmit
这条链中也可触发,pcnet_poll_timer
像是一个定时检查txpoll
,判断tx_desc
的buf
中是否存在未发送的数据的函数,但是由于调试时的时间很不稳定,所以我自己在尝试时有时在这里可以直接触发,无需再在pcnet_writew
里构造触发,有时又需要自己构造触发。pcnet_buffer
与heap_base
的偏移不稳定,也就是设备结构体的地址与heap_base
的地址之间的偏移经常不固定,但是我看别人的exp
都没有提这个问题,但是我自己是真的遇到了这个问题,所以我自己打的时候不是很稳定。
1 |
|
参考
https://www.giantbranch.cn/2019/07/17/VM%20escape%20%E4%B9%8B%20QEMU%20Case%20Study/
https://kirin-say.top/2019/12/01/QEMU-Escape-Learning/#0x02-Set-Environment