在看关于pwn的书时学到了 栈帧劫持stack pivot 利用这个例题练习一下。
基本思想:
stack pivot利用到的gadget是在函数退出时需要的两条指令:leave(mov esp,ebp;pop ebp);ret;
。这两条指令基本都会有。
可以利用这两条指令,通过栈溢出的方式,实现可以完全控制栈。
stack pivot实现的基本方法
(我的理解
- 通过栈溢出的方式将 我们之后要实现的完全可控的栈的地址写到EBP的地方
- 写入之后 ,程序第一次
leave;ret;
,将写入的地址赋给esp。
写入地址及第一次leave 图解:
此时 ebp的值 变成了我们写入的地址,指向了新栈,esp还是在原来的栈上。
3. 之后执行ret,程序继续按原来的执行。继续执行,执行到下一个leave;ret
的时候,esp也指向了新的栈上,此时就得到了一个完全可控的栈
图解:
进而就可以控制新栈的eip
分析例题:
-
执行文件
-
file一下,查看文件信息
32位文件 -
checksec 查看文件的保护情况
开了canaru和栈不可执行 -
拖进ida里分析
main函数:
先是要输入一个字符串,然后将字符串进行base64解密结果保存在v4里 ,v6保存v4的长度,对长度进行限制,不可以大于0xC。
之后将v4的值拷贝到input参数里,input为.bss段的值。
之后通过auth函数判断输入的内容的base64的值和题目给出的base64一不一样,若一样,则调用下面的correct函数,然后调用system函数。
不可能碰撞出跟题目给出的哈希值一样的东西的,所以只能通过漏洞触发这个system函数。
correct函数:
call system的地址:
0x08049284,执行system(“bin/sh”)
auth函数:
有一个栈溢出漏洞,此时将输入的内容拷贝到v4z中,v4的位置 :ebp-8h,input的长度在上面已经进行了限制,不大于0xC。所以在这里可以有4个字节的溢出
栈上的情况:
根据上面 stack pivot的方法,可以将我们想要控制的栈的地址写到 EBP的位置。
因为我们输入的东西都被保存在了input上,并且是通过input进行栈溢出的,所以我们可以把这个地址设置成为input的地址,执行到新栈上的时候,就可以继续执行写入的内容。
示意图:
所以可以将“bbbb”搞成调用system的地址。
- 分析的差不多了,exp:
from pwn import *
from base64 import*
p = process("./login")
sys_addr = 0x8049284
bss_addr = 0x811eb40
payload = "aaaa" + p32(sys_addr) +p32(bss_addr)
print(payload)
payload = b64encode(payload)
print(payload)
# gdb.attach(p)
p.sendline(payload)
p.interactive()