才学习了基本的ROP流程,到处找题练,不过也没做出来几道题,以这道32位的题作为例题吧。
这道题是BUUCTF上pwn练习题里的[OGeek2019]babyrop。
代码审计
老规矩先checksec一下:

没有canary保护,nx保护开启排除shellcode可能性,FULL RELEO为地址随机化。
观察主函数,先设定了一个闹铃,到时间就会强制退出程序,解除闹铃的方法在上一篇博客中提到过了,
这道题中闹铃函数依然对我们解题起不到什么干扰作用。

主函数的思路大概是:生成一个随机数,把这个随机数作为参数传进sub_804871F()函数里,然后将该函数返回的结果作为参数再传进sub_80487D0()里
sub_804871F()

sprintf()函数将生成的随机数a1加到了s[32]的数组中。这里题目有read函数,但是没有栈溢出的可能,读入buf之后,读取buf的长度,然后比较buf和s字符串的大小(比较长度为前v1个字符)。
此时如果strncmp()的结果不为0,则直接退出程序。因此我们第一个目的:使strncmp结果为0
sub_80487D0()

sub_804871F()函数会将buf[7]作为参数传进来,将它的ASCII码比对,看到全程序中唯一一个存在栈溢出漏洞可能性的地方。但是必须满足a1的ASCII码值能达到栈溢出的大小。第二个目的:使a1的ASCII码值(sub_804871F()函数里的buf[7]的ASCII码值尽量大)
解题思路
题目中我们最终能利用的一个漏洞即为最终的栈溢出漏洞,而将题目扔进ida里找不到system函数和/bin/sh,则明显要构造ROP链寻找libc解题了。
First:让strncmp结果为0

当buf与s数组完全相同时,strncmp结果会为0,但是s为系统生成的随机数,而buf是我们输入的数据,两者显然不可能相等。
另一种办法就是使v1等于0,这样strncmp的结果仍为0。
而v1是strlen函数读取buf的长度大小,使他为0就很简单了,标准的长度检测绕过,让buf数组的第一位为‘\x00’即可。此时程序不会退出。
Second:让buf[7]的值尽可能大
前面讲到,要实现栈溢出,buf[7]元素的ASCII码值必须大于两百四十多才行。
ASCII码对照表:
https://blog.youkuaiyun.com/wz947324/article/details/80076496
可以看出,在扩展的ASCII码中才有我们需要的250+的ASCII码值,而这些字符里,如果用键盘打出来,比如“≥”的ascii码值为242,但是在vscode里面可以看到,他的ASCII码值并没有242

因此我们需要用到转义字符。

\为转义字符,而’\xhh‘表示ASCII码值与’hh’这个十六进制数相等的符号,例如’\xff’表示ASCII码为255的符号。
奇怪的是,我把’\xff’和其他ASCII码大于128的符号放进vscode,只有用unsigned __int8转换出来的是他们的ASCII码值,而用unsigned int和int转换出来的都是负数,而ASCII码小于128的就不会出现这种情况。

本文详细介绍了如何分析一个32位的CTF题目,该题目涉及到无Canary保护、NX保护开启、地址随机化等安全机制。作者通过审计代码发现了一个栈溢出漏洞,并利用该漏洞构造ROP链来绕过安全机制。首先通过使strncmp结果为0来避免程序提前退出,然后通过设置buf[7]的ASCII码值来触发栈溢出。最终,作者展示了如何泄露libc地址并找到system函数,以实现远程代码执行。整个过程涉及到了栈溢出、ROP、write函数利用和libc搜索等技术。
最低0.47元/天 解锁文章
1057





