0.前言
这题是一个比较典型的栈溢出类题,整体思路不难,我查了一下好像是当时比赛的第二题。
这题在NSSCTF上做的时候有一个点比较坑(后面讲),我不清楚是当时比赛环境就是这样还是收入时环境没有完全一致。不过还是解决了就是。
写这题的wp的原因有几个:
一是我认为这题解法比较经典,能起到一个复习的作用;
二是这题会涉及一些我之前博客中忘了写的东西,相当于做一个补充;
三是解决那个小问题时用到了LibcSearcher,我个人觉得这是个不错且简单好用的Python库,一并说了。
这道题的exp优化参考了一些wp,但主体逻辑还是我自己写的。
1.题解过程
这题我会写的较为详细一些。
首先拿到ELF文件老规矩,先checksec一下,结果如下图所示:
可以看到开了NX保护,所以shellcode先别想了。
再尝试交互一下,发现只要一个可输入的地方,如图:
再老规矩丢到IDA里看看,发现主函数中只有一个主逻辑的函数,改名为mian_func()便于辨认。
查看这个函数,发现存在明显的栈溢出:
由于溢出字节足够,不考虑栈转移。
再进一步查看发现IDA中找不到与libc相关的函数的地址,由此推测开了ASLR保护。
又由于main_func()中调用了两次puts函数:
因此可考虑泄露puts函数的地址,由此获取libc的基地址,进而获取system函数的基地址。
用ropper查找可用的gadgets,锁定了两个目标:
那么总体的思路就很简单了:先通过栈溢出泄露system函数的地址和/bin/sh的地址,然后返回主函数起始位置,再通过栈溢出构建rop达成执行system(“/bin/sh”)的效果。
因此我最先的exp如下:
1 | from pwn import * |
这种exp很遗憾,我只能在本地打通,如果是远程则会报如下错误:
那么,这是为什么呢?
按道理说,靶机是Ubuntu18,我用的也是Ubuntu18,题目没有特别说明,那应该是默认2.27版本的libc没错。那么为什么会到最后一步出错?
是因为payload写错了?还是本身逻辑的问题?……这个问题我当时想了有些久。
然后,我注意到了一件事:k: not found,这个奇怪的k是哪里冒出来的?我当时突然意识到了一个东西,于是将binsh_addr做了一些偏移,然后发现返回的都是xxx : not found的这种格式,但xxx各不相同。
于是我猜测:会不会是这个binsh_addr本身就是一个错误的地址?如果是这样的话,那就是libc的问题了。
于是我用了LibcSearcher,因为这样搜索出来的一定是靶机上的libc,新的exp如下:
1 | from pwn import * |
然后,果然,靶机用的是libc6。
选择了正确的libc版本后就可以正常getshell了:
2.结语
这题其实也没什么很难的地方,算是补充了一下之前libc地址泄露的例题没法写出的遗憾吧。
也做了一些题目,发现栈类的题最搞人心态的应该就是libc和寄存器的问题吧……