首先看一下程序的保护机制
保护全开,并且是一个32位程序
然后,我们用IDA分析一下
这里,有两个漏洞
第一个是在调用read之前,[没有调用memset对buf清空,因此,buf里可能之前会有一些残留的关键数据]{.mark}
第二个是,[输入的整数个数没有上限,可以造成数据溢出,其实也就是栈溢出。]{.mark}
我们在read断点,然后观察栈中的数据,发现数据还未输入时,栈里就有一些关键数据
我们可以输入7 * 4 = 28个字符,然后printf时,就会把接下来的数据打印出来,直到遇x00
泄露这个数据后(当前为0xF7797244),然后我们找到libc的基地址,当前为0xF75E9000
然后我,我们算的它们之间的偏移
Off = 0xF7797244 - 0xF75E9000 =
于是,我们就这样泄露libc地址
1 | #泄露地址并计算出libc的地址 |
接下来,我们来做一个实验,让我们先抛开本题,来看看这样的代码
1 |
|
然后,我们发现,[当我们输入+或-符号,scanf就直接跳过了对a的输入]{.mark}

经过测试,[%u、%x、%d等都有这种特性]{.mark}
然后,我们继续分析此题,
我们接下来会输入n个整数,存入v13的空间处,而v13在ebp-0x70处,v15存的是canary的值,它位于ebp-0x10处,[我们不能把canary的值给改了,我们需要保留它,因此,我们先输入(0x70-0x10)/4 = 24个整数,然后接下来输入+或-号,跳过当前输入]{.mark},然后我们到达ebp-0xC处,距离返回地址ebp+0x4还差0x10/4=4个,因此,我们继续输入4个整数,接下来,我们再输入ROP即可
注意,本题IDA分析出来的位置相对于ebp不准,但是各个变量之间的相对关系还是准的
[实际,距离返回地址ebp+0x4还差7个,调试调试就知道了]{.mark}
由于,我们输入的数据会做一遍升序排序,所以,为了保留我们输入的顺序,我们前24个数据都输入0,然后[输入+或-跳过canary]{.mark},然后输入(7 + 1 + 1)个system的地址整数值,然后输入一个binsh_addr的整数值,程序退出main后,便执行shell
因为system_addr总是小于binsh_addr,而这两个地址值一般大于canary的值,canary是个随机生成的数,如果有时不满足这个大小关系,只需重新执行程序,多试几次即可。
于是,我们最终的exp脚本是这样的
1 | #coding:utf8 |
本题告诉我们,
用read读取数据到缓冲区前,先对缓冲区初始化
数组要检查下标越界