mcpField
B
binary-protection-bypass

binary-protection-bypass

github.com/yaklang安全2.6k3.7k 次安装6 周前更新
代码仓库

关于 binary-protection-bypass

面向二进制分析与漏洞利用的安全技能,讲解如何识别各类防护及其绕过方法和所需原语。内容覆盖常见编译防护与硬件防护。

主要功能

  1. 01识别 ASLR、PIE、NX、RELRO 和 Canary
  2. 02将防护与绕过方法对应
  3. 03列出方法所需的条件与利用原语
  4. 04涵盖 FORTIFY_SOURCE、CET 和 ARM MTE

适用场景

  1. 01检查 checksec 报告的防护
  2. 02根据已启用的防护规划利用路径
  3. 03比较绕过方法及其前提

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill binary-protection-bypass

安装后在 Claude Code 中输入/binary-protection-bypass确认已加载。

附带文件PROTECTION_BYPASS_MATRIX.md

详细介绍

技能:二进制保护绕过——专家攻击手册

AI 加载说明:专家级二进制保护识别与绕过技术。涵盖 ASLR、PIE、NX、RELRO、canary、FORTIFY_SOURCE、栈冲突、CET shadow stack 和 ARM MTE。每种保护都配有其绕过方法和所需原语。内容摘编自 ctf-wiki 的缓解措施章节和真实世界的漏洞利用案例。基础模型经常混淆哪些保护会阻止哪些攻击,也会忽略多种保护组合产生的影响。

0. 相关路由

高级参考

加载 PROTECTION_BYPASS_MATRIX.md,查看全面的保护 × 绕过方法 × 原语矩阵。


1. 保护识别

$ checksec ./binary
[*] '/path/to/binary'
    Arch:     amd64-64-little
    RELRO:    Full RELRO          ← GOT read-only
    Stack:    Canary found        ← stack canary enabled
    NX:       NX enabled          ← stack not executable
    PIE:      PIE enabled         ← position-independent code
    FORTIFY:  Enabled             ← fortified libc functions
快速识别表
保护检查命令二进制特征
ASLRcat /proc/sys/kernel/randomize_va_space操作系统级(0=关闭,1=部分,2=完全)
PIEchecksec 或 readelf -h(Type: DYN)使用 -pie 编译的二进制文件
NXchecksec 或 readelf -l(没有 RWE 段)gcc -z noexecstack(默认开启)
Canarychecksec 或查找 __stack_chk_fail@pltgcc -fstack-protector-all
部分 RELROreadelf -l(GNU_RELRO 段,.got.plt 可写)gcc -Wl,-z,relro
完全 RELROreadelf -l + .got 段只读gcc -Wl,-z,relro,-z,now
FORTIFY存在 __printf_chk、__memcpy_chk 等gcc -D_FORTIFY_SOURCE=2

2. 绕过 ASLR

ASLR 会在每次执行时随机化栈、堆、libc 和 mmap 区域的基地址。

绕过方法所需原语说明
信息泄露任意读取原语(格式化字符串、越界读取、UAF)泄露 libc/栈/堆地址 → 计算基地址
部分覆盖写入原语(长度有限)覆盖最后 1-2 个字节(页偏移固定)
暴力破解(32 位)能够重新连接/重试约 256–4096 次尝试(8-12 位熵)
Return-to-PLT栈溢出PLT 地址相对于二进制基地址的偏移固定(无 PIE 时)
ret2dlresolve栈溢出 + 写入原语无需知道 libc 基地址即可解析任意函数
格式化字符串泄露格式化字符串漏洞使用 %N$p 获取栈/libc/堆地址
读取栈内容逐字节读取(fork 服务端)通过崩溃预言机逐字节读取栈内容
ASLR 熵(x86-64 Linux)
区域熵(位)位置数
栈22约 4M
mmap / libc28约 256M
堆(brk)13约 8K
PIE 二进制文件28约 256M

3. 绕过 PIE

PIE(位置无关可执行文件)会随机化二进制文件自身代码/数据的基地址。

绕过方法所需原语说明
信息泄露从栈中读取返回地址PIE 基址 = 泄露地址 - 已知偏移
部分覆盖单字节或双字节写入页偏移的最后 12 位固定
格式化字符串泄露格式化字符串漏洞使用 %N$p,其中 N 指向 .text 返回地址
相对寻址了解二进制文件布局如果知道相对偏移,只需一次泄露
部分覆盖详情
PIE binary loaded at: 0x555555554000 (example)
Function at offset 0x1234: 0x555555555234

Overwrite return address last 2 bytes: 0x?234 → 0x?XXX
Unknown: bits 12-15 (one nibble = 4 bits = 16 possibilities)
Success rate: 1/16 per attempt

4. NX / DEP 绕过

NX(No-eXecute)/ DEP(数据执行保护)会阻止在栈/堆上执行代码。

绕过方法详情
ROP(面向返回的编程)将以 ret 结尾的现有代码片段串联起来
ret2libc直接调用 libc 函数(system、execve)
ret2csu使用 __libc_csu_init 代码片段进行受控函数调用
ret2dlresolve伪造动态链接器结构以解析任意函数
SROP使用 sigreturn 从伪造的信号帧设置所有寄存器
mprotect ROP串联 mprotect(addr, size, PROT_RWX) → 将页面设为可执行 → 跳转到 shellcode
JIT 喷射在 JIT 环境(V8 等)中,通过 JIT 编译器创建可执行代码
mprotect 链
# Make stack executable, then jump to shellcode
rop = b'A' * offset
rop += p64(pop_rdi) + p64(stack_page)     # page-aligned address
rop += p64(pop_rsi) + p64(0x1000)         # size
rop += p64(pop_rdx) + p64(7)              # PROT_READ|PROT_WRITE|PROT_EXEC
rop += p64(mprotect_addr)
rop += p64(shellcode_addr)                 # jump to shellcode on now-executable stack

5. RELRO 绕过

RELRO 级别GOT 状态绕过方法
无 RELROGOT 完全可写直接覆盖 GOT
部分 RELRO.got.plt 可写(延迟绑定)仍可覆盖 GOT
完全 RELRO加载时解析所有 GOT 条目,GOT 只读无法写入 GOT → 攻击其他结构
完全 RELRO 的替代目标
目标适用情况方法
__malloc_hookglibc < 2.34使用 one_gadget 覆盖
__free_hookglibc < 2.34使用 system 覆盖,触发 free("/bin/sh")
_IO_FILE vtable任意 glibcFSOP / vtable 劫持
__exit_funcs任意 glibc覆盖退出处理函数列表
TLS_dtor_listglibc ≥ 2.34线程局部析构函数列表(需要指针保护)
.fini_array可写时覆盖析构函数指针
栈返回地址直接写入栈覆盖返回地址以进行 ROP

参见 arbitrary-write-to-rce,了解完整的目标列表。


6. CANARY 绕过

方法条件详情
格式字符串泄露printf(user_input)使用 %N$p 从栈上读取 canary
暴力破解fork() 服务(canary 在子进程中保持不变)逐字节尝试:256 × (canary_size-1) 次
栈读取部分覆盖 / 信息泄露覆盖 canary 的空字节,通过输出泄露
线程 canary 覆盖溢出到达 TLScanary 位于 fs:[0x28];缓冲区溢出到 TLS 后,将 canary 覆盖为已知值
相对于 canary 覆盖溢出发生在 canary 之后、返回地址之前跳过 canary,仅覆盖返回地址(少见布局)
基于堆的攻击漏洞位于堆上,而非栈上canary 只保护栈
__stack_chk_fail GOT 覆盖部分 RELRO将 __stack_chk_fail@GOT 覆盖为指向无害函数 → canary 检查通过
Canary 格式
x86:    0x00XXXXXX (4 bytes, leading null byte)
x86-64: 0x00XXXXXXXXXXXXXX (8 bytes, leading null byte)

开头的 \x00 可防止字符串操作意外读取 canary。


7. FORTIFY_SOURCE 绕过

_FORTIFY_SOURCE=2 会增加缓冲区大小检查,并限制格式字符串操作。

强化函数限制绕过方法
__printf_chk禁止使用带位置参数的 %n(%N$n)使用非位置参数 %n 或 %hn 链
__memcpy_chk检查目标缓冲区大小改用堆溢出而非栈溢出
__strcpy_chk同上
__read_chk检查读取大小是否超过缓冲区
使用 FORTIFY_SOURCE 的格式字符串
# %1$n is blocked by __printf_chk
# But sequential (non-positional) %n may still work:
# Print exact byte count, then %hn — must be very precise
# Or: find unfortified printf in binary/libc via ROP

8. CET(控制流强制技术)

Intel CET 增加了两种机制:

影子栈
  • 由硬件维护的返回地址副本
  • 执行 ret 时,CPU 会检查影子栈是否与实际栈匹配
  • 不匹配 → #CP 故障(控制保护异常)
影响详情
阻止 ROP执行 ret 时会检测到返回地址覆盖
仍可使用 JOP影子栈不会检查 jmp [reg]
仍可使用 COPcall [reg] 会将地址压入影子栈,但目标由 IBT 验证
间接分支跟踪(IBT)
  • 间接 jmp/call 必须跳转到 ENDBR64 指令
  • 未落在 ENDBR 上 → #CP 故障

绕过方式:

  • 仅针对数据的攻击(不改变控制流)
  • 查找可链接至有用操作的有效 ENDBR 小工具
  • 使用带 ENDBR 前缀小工具的 JOP
  • 以超出 CFI 范围的目标结构为目标(modprobe_path、函数指针数组)

9. MTE(内存标记扩展,ARM)

ARM MTE 为内存指针和分配分配 4 位标记。标记不匹配 = 故障。

方面详情
标记位指针中的 4 位(第 56–59 位)= 16 种可能的标记
粒度16 字节(每个 16 字节粒度有一个标记)
检查加载/存储:指针标记必须与内存标记匹配
概率性随机标记 → 攻击者猜中的概率为 1/16
绕过方法
方法成功率
暴力破解每次尝试为 1/16(6.25%)
标记预言机使用侧信道确定标记(时序、错误消息)
界内利用保持在同一标记区域内(使用相对偏移量)
标记绕过小工具如果可访问,则使用 LDGM/STGM 指令
推测执行以 Spectre 风格绕过标记检查

10. 决策树

Binary analysis: checksec output
├── NX disabled?
│   └── Shellcode on stack/heap (simplest path)
│
├── NX enabled (standard modern binary)?
│   ├── Need code execution → ROP/ret2libc
│   │
│   ├── Canary enabled?
│   │   ├── fork server? → byte-by-byte brute-force
│   │   ├── Format string? → leak canary via %p
│   │   ├── Heap vuln? → canary doesn't protect heap
│   │   └── Partial RELRO? → overwrite __stack_chk_fail@GOT
│   │
│   ├── PIE enabled?
│   │   ├── Format string? → leak .text address → PIE base
│   │   ├── Partial overwrite → last 12 bits fixed (1/16 brute-force)
│   │   └── OOB read? → leak code pointer
│   │
│   ├── ASLR enabled?
│   │   ├── Info leak available → leak libc base
│   │   ├── No leak → ret2dlresolve or SROP
│   │   ├── 32-bit? → brute-force feasible (~4096 attempts)
│   │   └── Return-to-PLT (no libc base needed for PLT calls)
│   │
│   ├── RELRO level?
│   │   ├── None/Partial → GOT overwrite
│   │   └── Full → alternative targets:
│   │       ├── glibc < 2.34 → __malloc_hook / __free_hook
│   │       ├── glibc ≥ 2.34 → _IO_FILE / exit_funcs / TLS_dtor_list
│   │       ├── .fini_array (if writable)
│   │       └── Stack return address
│   │
│   └── FORTIFY_SOURCE?
│       ├── Blocks positional %n → use sequential %n or heap exploit
│       └── Blocks buffer overflows in fortified functions → use unfortified paths
│
├── CET (shadow stack)?
│   ├── ROP blocked → data-only attack or JOP
│   └── ENDBR-gadget chaining
│
└── MTE (ARM)?
    ├── 1/16 brute-force
    └── Stay in-bounds for relative corruption

评论

支持 Markdown