Ubuntu 24环境下缓冲区溢出复现失败:如何二次调用call_me_twice函数?
缓冲区溢出:二次调用
call_me_twice的问题排查与修复 你在练习缓冲区溢出时遇到的问题,主要是几个细节没处理到位——填充长度没算准、地址传递方式不对,还有编译/系统防护没关彻底。下面一步步帮你解决:
先说说你操作里的核心误区
- 盲目填充无效:你随便加一堆
#,但根本没算出缓冲区到返回地址的准确偏移量,覆盖不到EIP(指令指针寄存器)自然不会触发跳转。 - 命令行传十六进制字节的方式错了:直接输入
\x1c\x52\x40\x66,shell会把它当成普通字符串(反斜杠和字符都会被原样传递),根本不是你要的二进制字节。 - 没关ASLR和PIE:Ubuntu默认开启了地址空间随机化(ASLR),而且gcc默认编译会开启位置无关代码(PIE),这俩都会让函数地址每次运行都变化,你用的静态地址肯定无效。
分步解决步骤
1. 重新编译程序(关闭所有干扰防护)
先编译出一个完全可控的32位程序,关闭栈保护、PIE:
gcc -m32 -fno-stack-protector -no-pie bof.c -o bof
然后临时关闭当前终端的ASLR(重启终端会恢复,不影响系统全局):
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
2. 精准计算缓冲区到返回地址的偏移量
用gdb的pattern工具快速算偏移,比手动数栈方便得多:
- 启动gdb:
gdb ./bof - 生成200字节的测试pattern:
pattern create 200 - 运行程序传入这个pattern:
r '这里粘贴生成的pattern字符串' - 程序崩溃后,查看EIP寄存器的值:
info registers eip - 用pattern计算偏移:
pattern offset 0xXXXXXX(把刚才EIP的值填进去)
比如得到偏移是14字节(array[10]+ EBP的4字节,刚好14),那就是需要填14个字符才能覆盖到返回地址的位置。
3. 正确构造包含函数地址的输入
首先确认call_me_twice的真实地址:在gdb里输入p call_me_twice,比如得到$1 = {char (*)()} 0x8049186,那小端序的字节就是\x86\x91\x04\x08。
然后用printf来生成二进制字节(shell直接传不了十六进制字节,必须用printf转换):
# 这里的14是刚才算出的偏移量,替换成你自己的数值 ./bof $(printf '%.14s\x86\x91\x04\x08' '#')
%.14s会生成14个#填充,后面拼接小端序的函数地址,刚好覆盖return_input的返回地址。
4. 验证结果
运行上面的命令后,你应该会看到两次Example输出:第一次是main函数里的调用,第二次是缓冲区溢出后,return_input返回时跳转到call_me_twice执行,完美达到你的目标。
额外提醒
- 如果之后要练习更复杂的溢出,ASLR可以关闭也可以用ROP绕过,但这个练习里直接关闭最省事。
- 小端序一定不能搞反,32位地址的字节顺序是从低到高,比如地址
0x12345678要写成\x78\x56\x34\x12。 - 编译参数里的
-no-pie必须加,否则函数地址是随机的,固定地址完全没用。
内容的提问来源于stack exchange,提问作者Slimboy Fat
相关产品推荐
相关产品推荐

