如何利用缓冲区溢出调用CTF中地址004011e9的print flag函数
缓冲区溢出利用方案(针对给定CTF代码)
核心分析
目标函数FUN_00401350中,char Input1[16]是栈上的16字节缓冲区,最后一次输入调用了不安全的gets()——这个函数不会限制输入长度,完全可以用来覆盖栈帧的返回地址,直接跳转到0x004011e9的print flag函数。
步骤拆解
计算缓冲区到返回地址的偏移量
- 以32位程序为例,栈结构为:
Input1[16]→ 保存的EBP(4字节) → 返回地址(4字节),因此从缓冲区起始到返回地址的偏移是16(缓冲区大小) + 4(EBP) = 20字节。 - 若是64位程序,保存的RBP占8字节,偏移则为
16+8=24字节。不确定位数时,用gdb等调试工具确认:在gets()处下断点,查看Input1的地址与当前EBP/RBP的差值,再加EBP/RBP到返回地址的长度即可。
- 以32位程序为例,栈结构为:
构造Payload
- 前两次输入由
fgets()读取,后续还有getchar()吃掉换行符,随便输入内容即可(比如第一次输abc回车,第二次输def回车),不影响溢出操作。 - 第三次输入(
gets())的Payload格式:
32位示例:地址[填充缓冲区的字节] + [覆盖EBP/RBP的字节(可随意填充)] + [小端序的print flag函数地址]0x004011e9的小端序为\xE9\x11\x40\x00,完整Payload是'a'*20 + '\xE9\x11\x40\x00'。
64位示例:地址0x004011e9的小端序为\xE9\x11\x40\x00\x00\x00\x00\x00,完整Payload是'a'*24 + '\xE9\x11\x40\x00\x00\x00\x00\x00'。
- 前两次输入由
处理换行符问题
gets()会自动将输入末尾的换行符替换为\0,但只要\0出现在返回地址之后,就不会影响跳转逻辑。输入Payload时直接一次性输入所有字符,最后按回车即可,回车被gets()处理成\0,不会覆盖已写入的返回地址。
常见问题排查
- 若之前尝试无效,大概率是偏移量计算错误:必须用调试工具确认栈布局,比如在gdb中打印
&Input1和$ebp(32位)的差值,才能得到准确的填充字节数。 - 注意字节序:x86架构为小端序,地址必须倒序写入,比如
0x004011e9不能直接写\x00\x40\x11\xe9,必须是\xe9\x11\x40\x00。
内容的提问来源于stack exchange,提问作者Wynn Berry
相关产品推荐
相关产品推荐

