-
-
[原创][分享]Pwn从入门到放弃(二)
-
发表于: 2019-12-28 22:15 9069
-
该题目是AliCTF 2016中一道题,vss
第一步:
checksec看一下该程序开了哪些保护:
同样也是64位小端,只开启了RELOR和NX两项保护。
第二步:
运行该程序看看:
让输入一段password,随便输入了几个字母,没有任何正确和错误的提示
*第三步:
用gdb调试看看:
发现崩溃在了0x401124处,movzx eax,BYTE PTR [rbp+rax*1-0x40],但似乎无法计算溢出位置。
第四步:
将该程序丢到IDA看一下:
发现函数无法识别,应该是使用了strip将符号信息做了剔除。程序定位在了start处。
知识点1:strip,简单的说就是给文件脱掉外衣,具体就是从特定文件中剥掉一些符号信息和调试信息,使文件变小。
第五步:
寻找main函数入口,这里有两种方法,一种是通过经验判断,在start末尾处的call,应该是libc_start_main函数,而其上方处offset sub_4011B1应该就是main函数了。另一种是,直接shift+F12通过字符串查找“password”,找到main函数。
第六步:
进入main函数后,F5查看伪代码:
其中sub_473EA0应为read函数,猜测应该是用于读取password的输入。
在进入sub_40108E函数时,发现了对于读取输入值后的逻辑判断:
如果是以“py”开头,则直接返回,后面的循环判断看的懵,没办法,C/C++功底太差,@_@
另外,在40108E函数中看到疑似strncpy的函数。
知识点2:strncpy函数是将输入内容的指定长度字符串复制给一个字符串数组中,代码举例:
第七步:
动态调试看看吧,因为我使用的是linux的虚拟机,因此需要使用IDA来远程动态调试。
在sub437EA0和sub40108E处下个断,输入70个"A"和10个"1",然后动态跟一下栈状态:
输入70个"A"和10个"1"时的,栈帧状态:
当进入sub40108E后,完成strncpy后的栈帧状态:
发现RBP和返回地址已被覆盖,因此可以得知73~80个字符可以覆盖返回地址,在完成strcpy后,会将所输入的内容逐个字符与66h进行异或,然后最终报错:
RBP+RAX的值刚好位于了只读的区域:
第八步:
由于可控可执行的栈空间73~80(8个字节),因此需要利用stack pivot技术将栈顶上移到main栈帧空间中利用(因为main函数申请了400h的空间),然后再构造ropchain:
第九步:
程序由于没有引入libc.so,因此只能考虑使用程序中的syscall,利用syscall来调用所需的函数。
知识点3:关于syscall的调用方法,可以参看syscall调用表
第十步:
栈溢出布局思路(自带画图工具凑合画的):
另外,由于需要使用syscall来调用所需函数,因此需要为syscall调用时的参数进行布局,上篇文章已经提过了,关于64位寄存器,依次是rdi、rsi、rdx、rcx、r8、r9,而read和sys_execve都是需要三个参数的,所以我们们要找到类似pop rdi、pop rsi、pop rdx的命令来控制三个参数。
代码一:
代码二:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创][分享]Pwn从入门到放弃(五) 11930
- [原创][分享]Pwn从入门到放弃(四) 16395
- [原创][分享]Pwn从入门到放弃(三) 7620
- [原创][分享]Pwn从入门到放弃(二) 9070
- [原创][分享]Pwn从入门到放弃(一) 13623