CTF-pwn 技术总结(3)
字数 3032 2025-08-07 08:22:15

Linux PWN 安全机制与绕过技术详解

一、Linux 安全机制概述

Linux 系统提供了多种安全机制来防止漏洞利用,理解这些机制及其绕过方法是 CTF PWN 比赛的基础。主要安全机制包括:

  1. NX (No-eXecute)
  2. ASLR (Address Space Layout Randomization)
  3. Stack Canary
  4. RELRO (Relocation Read-Only)
  5. PIE (Position Independent Executable)
  6. FORTIFY_SOURCE
  7. Seccomp

二、NX (No-eXecute) 保护机制

基本原理

  • 将数据区域(如栈和堆)标记为不可执行
  • 防止攻击者在栈或堆上执行shellcode
  • 通过ELF程序的PT_GNU_STACK段或内核的NX位实现

检查方法

checksec --file=target

查看输出中的"NX enabled"字段

绕过技术

1. ROP (Return Oriented Programming)

  • 利用程序中已有的代码片段(gadgets)构造攻击链
  • 每个gadget以ret指令结尾
  • 通过连续调用多个gadgets实现攻击目标

2. Ret2Libc

  • 返回到libc中的函数(如system、execve)
  • 需要泄露libc地址(当ASLR开启时)
  • 典型步骤:
    1. 泄露libc函数地址
    2. 计算libc基址
    3. 构造system("/bin/sh")调用

3. JIT Spraying

  • 在可执行内存区域(如JIT编译区域)注入代码
  • 适用于浏览器等支持JIT的应用

4. mprotect

  • 使用mprotect修改内存页属性为可执行
  • 需要先泄露地址信息

三、ASLR (Address Space Layout Randomization)

基本原理

  • 随机化内存布局(栈、堆、库等地址)
  • 内核参数/proc/sys/kernel/randomize_va_space控制:
    • 0:关闭ASLR
    • 1:栈、库随机化
    • 2:栈、库、堆随机化

检查方法

cat /proc/sys/kernel/randomize_va_space

绕过技术

1. 信息泄露

  • 通过格式化字符串、UAF等漏洞泄露地址
  • 计算基址偏移
  • 典型目标:
    • 泄露libc地址计算libc基址
    • 泄露程序地址计算程序基址(PIE情况下)

2. 暴力破解

  • 适用于32位系统(地址空间小)
  • 对可能的地址进行尝试

3. Return-to-plt

  • 在PIE未开启时使用
  • PLT地址固定,可直接调用

4. 部分覆盖

  • 在已知部分地址的情况下(如栈地址后12位固定)
  • 覆盖地址的低字节

四、Stack Canary

基本原理

  • 在栈帧的返回地址前放置随机值(canary)
  • 函数返回前检查canary是否被修改
  • 三种类型:
    1. Terminator canary(含终止字符)
    2. Random canary(完全随机)
    3. Random XOR canary(与部分控制数据异或)

检查方法

checksec --file=target

查看输出中的"Canary found"字段

绕过技术

1. 泄露Canary

  • 通过格式化字符串漏洞泄露
  • 通过缓冲区溢出部分覆盖泄露(逐字节爆破)
  • 通过侧信道攻击获取

2. 劫持__stack_chk_fail

  • 修改GOT表中__stack_chk_fail的地址
  • 需要能够写GOT表(RELRO partial或关闭)

3. 不触发Canary检查

  • 覆盖SEH链(Windows)
  • 覆盖其他关键数据而非返回地址

4. 多线程爆破

  • 在多线程程序中,子线程的canary可能与主线程相同
  • 通过子线程泄露主线程canary

五、RELRO (Relocation Read-Only)

基本原理

  • 控制ELF重定位区域的读写权限
  • 两种级别:
    1. Partial RELRO(部分保护)
      • GOT表可写
      • 重定位段只读
    2. Full RELRO(完全保护)
      • 所有重定位区域只读
      • GOT表变为PLT的一部分且只读

检查方法

checksec --file=target

查看输出中的"RELRO"字段

绕过技术

1. Partial RELRO

  • 可修改GOT表
  • 技术:
    • GOT表劫持
    • 修改free@got为system等

2. Full RELRO

  • 无法直接修改GOT表
  • 替代方法:
    • 使用ROP
    • 使用其他可写区域(如.dynamic)
    • 利用FILE结构体攻击

六、PIE (Position Independent Executable)

基本原理

  • 程序代码段地址随机化
  • 类似ASLR,但作用于主程序而非共享库
  • 所有地址为相对偏移

检查方法

checksec --file=target

查看输出中的"PIE enabled"字段

绕过技术

1. 信息泄露

  • 泄露程序地址计算基址
  • 常见泄露点:
    • 栈地址
    • 堆地址
    • 已知指针内容

2. 部分覆盖

  • 在已知部分地址的情况下
  • 覆盖指针的低位字节

3. 非PIE段利用

  • 利用程序中的非PIE段(如.data、.bss)
  • 如果存在固定地址的可写区域

七、FORTIFY_SOURCE

基本原理

  • 编译时对危险函数(如memcpy、strcpy)添加检查
  • 检查缓冲区大小是否足够
  • 需要-O2优化和定义_FORTIFY_SOURCE

检查方法

nm -D target | grep _chk

绕过技术

1. 不使用受保护函数

  • 寻找未受保护的替代函数
  • 如使用read代替strcpy

2. 精确控制长度

  • 确保缓冲区大小"看似"足够
  • 避免触发长度检查

3. 其他漏洞组合

  • 结合其他类型漏洞绕过
  • 如格式化字符串、UAF等

八、Seccomp

基本原理

  • Linux内核的沙箱机制
  • 限制进程可用的系统调用
  • 常见于CTF的pwn题目中

检查方法

seccomp-tools dump ./target

绕过技术

1. 允许的系统调用

  • 分析允许的系统调用
  • 组合可用系统调用完成攻击
  • 如仅允许open/read/write时构造ORW(Open-Read-Write)链

2. 文件描述符重用

  • 重用已打开的文件描述符
  • 避免需要受限的系统调用

3. 信号处理

  • 通过信号处理机制绕过
  • 如sigreturn-oriented programming (SROP)

4. 内核漏洞

  • 利用内核漏洞突破限制
  • 需要题目环境存在内核漏洞

九、综合绕过示例

场景:64位程序,开启NX、ASLR、Canary、PIE

攻击步骤:

  1. 泄露Canary

    • 通过格式化字符串或缓冲区溢出部分覆盖泄露
    payload = b'A' * (canary_offset)  # 填满到canary前
    p.send(payload)
    p.recvuntil(payload)
    canary = u64(b'\x00' + p.recv(7))  # canary第一个字节通常是\x00
    
  2. 泄露程序地址

    • 通过GOT表泄露函数地址计算PIE基址
    puts_got = elf.got['puts']
    payload = flat([
        b'A' * canary_offset,
        canary,
        b'B' * 8,  # 覆盖rbp
        pop_rdi,
        puts_got,
        elf.plt['puts'],
        elf.sym['main']  # 返回main重新利用
    ])
    p.send(payload)
    puts_addr = u64(p.recvline()[:-1].ljust(8, b'\x00'))
    libc.address = puts_addr - libc.sym['puts']
    
  3. 构造ROP链

    • 使用泄露的地址构造system("/bin/sh")
    binsh = next(libc.search(b'/bin/sh'))
    system = libc.sym['system']
    payload = flat([
        b'A' * canary_offset,
        canary,
        b'B' * 8,
        pop_rdi,
        binsh,
        system
    ])
    

十、防护检测与调试技巧

1. 检查程序保护

checksec --file=target
readelf -l target | grep GNU_STACK  # 检查NX
readelf -d target | grep RELRO      # 检查RELRO级别

2. 调试技巧

  • GDB插件
    • pwndbg:canary命令查看canary
    • gef:checksec命令检查保护
  • ASLR临时关闭
    setarch `uname -m` -R /bin/bash
    
  • 查看内存映射
    cat /proc/$(pidof target)/maps
    

十一、总结与练习建议

1. 学习路线建议

  1. 从无保护程序开始练习
  2. 逐步增加保护机制:
    • 先NX → 然后ASLR → 接着Canary → 最后PIE+Full RELRO
  3. 掌握信息泄露技巧
  4. 熟练ROP构造

2. 常见题目类型

  1. 栈溢出 + NX → Ret2Libc/ROP
  2. 栈溢出 + Canary → 泄露Canary
  3. PIE程序 → 泄露程序地址
  4. 堆题目 → 结合堆利用技巧

3. 必备工具

  • pwntools
  • ROPgadget/ropper
  • one_gadget
  • seccomp-tools
  • checksec

通过系统学习这些保护机制及其绕过方法,可以逐步提高CTF PWN的解题能力。建议在实际题目中反复练习每种技术的应用。

Linux PWN 安全机制与绕过技术详解 一、Linux 安全机制概述 Linux 系统提供了多种安全机制来防止漏洞利用,理解这些机制及其绕过方法是 CTF PWN 比赛的基础。主要安全机制包括: NX (No-eXecute) ASLR (Address Space Layout Randomization) Stack Canary RELRO (Relocation Read-Only) PIE (Position Independent Executable) FORTIFY_ SOURCE Seccomp 二、NX (No-eXecute) 保护机制 基本原理 将数据区域(如栈和堆)标记为不可执行 防止攻击者在栈或堆上执行shellcode 通过ELF程序的PT_ GNU_ STACK段或内核的NX位实现 检查方法 查看输出中的"NX enabled"字段 绕过技术 1. ROP (Return Oriented Programming) 利用程序中已有的代码片段(gadgets)构造攻击链 每个gadget以ret指令结尾 通过连续调用多个gadgets实现攻击目标 2. Ret2Libc 返回到libc中的函数(如system、execve) 需要泄露libc地址(当ASLR开启时) 典型步骤: 泄露libc函数地址 计算libc基址 构造system("/bin/sh")调用 3. JIT Spraying 在可执行内存区域(如JIT编译区域)注入代码 适用于浏览器等支持JIT的应用 4. mprotect 使用mprotect修改内存页属性为可执行 需要先泄露地址信息 三、ASLR (Address Space Layout Randomization) 基本原理 随机化内存布局(栈、堆、库等地址) 内核参数 /proc/sys/kernel/randomize_va_space 控制: 0:关闭ASLR 1:栈、库随机化 2:栈、库、堆随机化 检查方法 绕过技术 1. 信息泄露 通过格式化字符串、UAF等漏洞泄露地址 计算基址偏移 典型目标: 泄露libc地址计算libc基址 泄露程序地址计算程序基址(PIE情况下) 2. 暴力破解 适用于32位系统(地址空间小) 对可能的地址进行尝试 3. Return-to-plt 在PIE未开启时使用 PLT地址固定,可直接调用 4. 部分覆盖 在已知部分地址的情况下(如栈地址后12位固定) 覆盖地址的低字节 四、Stack Canary 基本原理 在栈帧的返回地址前放置随机值(canary) 函数返回前检查canary是否被修改 三种类型: Terminator canary(含终止字符) Random canary(完全随机) Random XOR canary(与部分控制数据异或) 检查方法 查看输出中的"Canary found"字段 绕过技术 1. 泄露Canary 通过格式化字符串漏洞泄露 通过缓冲区溢出部分覆盖泄露(逐字节爆破) 通过侧信道攻击获取 2. 劫持__ stack_ chk_ fail 修改GOT表中__ stack_ chk_ fail的地址 需要能够写GOT表(RELRO partial或关闭) 3. 不触发Canary检查 覆盖SEH链(Windows) 覆盖其他关键数据而非返回地址 4. 多线程爆破 在多线程程序中,子线程的canary可能与主线程相同 通过子线程泄露主线程canary 五、RELRO (Relocation Read-Only) 基本原理 控制ELF重定位区域的读写权限 两种级别: Partial RELRO(部分保护) GOT表可写 重定位段只读 Full RELRO(完全保护) 所有重定位区域只读 GOT表变为PLT的一部分且只读 检查方法 查看输出中的"RELRO"字段 绕过技术 1. Partial RELRO 可修改GOT表 技术: GOT表劫持 修改free@got为system等 2. Full RELRO 无法直接修改GOT表 替代方法: 使用ROP 使用其他可写区域(如.dynamic) 利用FILE结构体攻击 六、PIE (Position Independent Executable) 基本原理 程序代码段地址随机化 类似ASLR,但作用于主程序而非共享库 所有地址为相对偏移 检查方法 查看输出中的"PIE enabled"字段 绕过技术 1. 信息泄露 泄露程序地址计算基址 常见泄露点: 栈地址 堆地址 已知指针内容 2. 部分覆盖 在已知部分地址的情况下 覆盖指针的低位字节 3. 非PIE段利用 利用程序中的非PIE段(如.data、.bss) 如果存在固定地址的可写区域 七、FORTIFY_ SOURCE 基本原理 编译时对危险函数(如memcpy、strcpy)添加检查 检查缓冲区大小是否足够 需要-O2优化和定义_ FORTIFY_ SOURCE 检查方法 绕过技术 1. 不使用受保护函数 寻找未受保护的替代函数 如使用read代替strcpy 2. 精确控制长度 确保缓冲区大小"看似"足够 避免触发长度检查 3. 其他漏洞组合 结合其他类型漏洞绕过 如格式化字符串、UAF等 八、Seccomp 基本原理 Linux内核的沙箱机制 限制进程可用的系统调用 常见于CTF的pwn题目中 检查方法 绕过技术 1. 允许的系统调用 分析允许的系统调用 组合可用系统调用完成攻击 如仅允许open/read/write时构造ORW(Open-Read-Write)链 2. 文件描述符重用 重用已打开的文件描述符 避免需要受限的系统调用 3. 信号处理 通过信号处理机制绕过 如sigreturn-oriented programming (SROP) 4. 内核漏洞 利用内核漏洞突破限制 需要题目环境存在内核漏洞 九、综合绕过示例 场景:64位程序,开启NX、ASLR、Canary、PIE 攻击步骤: 泄露Canary : 通过格式化字符串或缓冲区溢出部分覆盖泄露 泄露程序地址 : 通过GOT表泄露函数地址计算PIE基址 构造ROP链 : 使用泄露的地址构造system("/bin/sh") 十、防护检测与调试技巧 1. 检查程序保护 2. 调试技巧 GDB插件 : pwndbg: canary 命令查看canary gef: checksec 命令检查保护 ASLR临时关闭 : 查看内存映射 : 十一、总结与练习建议 1. 学习路线建议 从无保护程序开始练习 逐步增加保护机制: 先NX → 然后ASLR → 接着Canary → 最后PIE+Full RELRO 掌握信息泄露技巧 熟练ROP构造 2. 常见题目类型 栈溢出 + NX → Ret2Libc/ROP 栈溢出 + Canary → 泄露Canary PIE程序 → 泄露程序地址 堆题目 → 结合堆利用技巧 3. 必备工具 pwntools ROPgadget/ropper one_ gadget seccomp-tools checksec 通过系统学习这些保护机制及其绕过方法,可以逐步提高CTF PWN的解题能力。建议在实际题目中反复练习每种技术的应用。