原题文件
链接:https://pan.baidu.com/s/1XwbHEI2-HxOeXmu4vnGeGg
提取码:1111
拖入IDA并F5
fflush函数:等到stdout缓冲区读完输出内容后,一并输出缓冲区数据。
read函数:0代表标准输入,1代表标准输出,2代表标准错误。
此题要求输入数字,例如输入‘12’,是以ASCII码表示的,0x31代表数字‘1’,0x32代表数字‘2’。最后输入的回车表示为’0a’。
strtol函数:把字符串转化为长整型,存在v4里。
See_something函数:打印出指定地址的内容。
此程序的漏洞在strcpy函数中,dest只有0x38个长度,而src有0x100个长度,从src复制到dest会发生栈溢出。
思路
1.考虑ret2text->ret2shellcode->ret2syscall的解题思路,发现都不行。
2.此题既没有system函数,也没有/bin/sh。
3.已经执行过的函数,其真实地址一定是保存在got表里的,我们可以考虑泄漏这些函数的真实地址,再根据libc函数间的偏移关系算出system的真实地址。
从图中可以看到,puts函数已经执行过,got表中保存的是真实地址。(以0xf7打头的地址是libc中函数的地址,而以0x80打头的是elf文件本身的plt地址),因此我们可以泄漏puts函数地址。
(注:libc文件本来存在于磁盘上,当程序执行时会被载入到虚拟内存中,由于ASLR开着(远程主机),libc的地址会变动,但是libc中函数之间的偏移关系是不变的。)
解题
gdb调试,直接定位到第一个read处,要求输入一个地址,获得这个地址保存的内容。我们要输入got表项的地址,这个表项内存储的就是函数的真实地址。
找到puts的got表项地址:
转成10进制后在gdb里输入:
等执行到See_something时,puts的真实地址已经显露出来了:
可能你会问,前面got表不是已经找出puts真实地址吗?为什么还要特意把程序调试一遍通过See_something来显露地址呢?第一,远程是开着ASLR的,got表项的地址会变动,必须由程序本身得到。第二,前面的使用got一键获得函数地址是基于本地调试的,所以地址是本地libc的值。本地和远程的libc版本未必一样,因此不能直接拿来用。虽然本地调试有局限性,但是函数之间的偏移不变的。
溢出字符串长度
先生成200个字符