binary-protection-bypass

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SKILL: Binary Protection Bypass — Expert Attack Playbook

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

AI LOAD INSTRUCTION: Expert binary protection identification and bypass techniques. Covers ASLR, PIE, NX, RELRO, canary, FORTIFY_SOURCE, stack clash, CET shadow stack, and ARM MTE. Each protection is paired with its bypass methods and required primitives. Distilled from ctf-wiki mitigation sections and real-world exploitation. Base models often confuse which protections block which attacks and miss the combinatorial effect of multiple protections.
AI加载说明:专家级二进制防护识别与绕过技术,覆盖ASLR、PIE、NX、RELRO、金丝雀、FORTIFY_SOURCE、栈冲突、CET影子栈以及ARM MTE。每种防护都对应了绕过方法和所需原语,内容提炼自ctf-wiki的防护绕过章节和真实场景漏洞利用。基础大模型通常会混淆不同防护对应的拦截攻击类型,也会忽略多种防护组合生效的叠加效果。

0. RELATED ROUTING

0. 相关路由

  • stack-overflow-and-rop — ROP chains to bypass NX, ret2libc for ASLR bypass
  • format-string-exploitation — primary method for leaking canary, PIE, libc addresses
  • heap-exploitation — heap attacks for RELRO bypass (when GOT is read-only)
  • arbitrary-write-to-rce — what to overwrite when GOT is protected by RELRO
  • stack-overflow-and-rop — 用于绕过NX的ROP链,用于绕过ASLR的ret2libc
  • format-string-exploitation — 泄露金丝雀、PIE、libc地址的主要方法
  • heap-exploitation — 用于绕过RELRO的堆攻击(当GOT为只读时)
  • arbitrary-write-to-rce — 当GOT受RELRO保护时的覆写目标参考

Advanced Reference

高级参考

Load PROTECTION_BYPASS_MATRIX.md for comprehensive protection × bypass × primitive matrix.

加载 PROTECTION_BYPASS_MATRIX.md 可查看完整的防护×绕过×原语矩阵。

1. PROTECTION IDENTIFICATION

1. 防护识别

bash
$ 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
bash
$ checksec ./binary
[*] '/path/to/binary'
    Arch:     amd64-64-little
    RELRO:    Full RELRO          ← GOT只读
    Stack:    Canary found        ← 已启用栈金丝雀
    NX:       NX enabled          ← 栈不可执行
    PIE:      PIE enabled         ← 位置无关代码
    FORTIFY:  Enabled             ← 已启用libc函数加固

Quick Identification Table

快速识别表

ProtectionCheck CommandBinary Indicator
ASLR
cat /proc/sys/kernel/randomize_va_space
OS-level (0=off, 1=partial, 2=full)
PIE
checksec
or
readelf -h
(Type: DYN)
Binary compiled with
-pie
NX
checksec
or
readelf -l
(no RWE segment)
gcc -z noexecstack
(default on)
Canary
checksec
or look for
__stack_chk_fail@plt
gcc -fstack-protector-all
Partial RELRO
readelf -l
(GNU_RELRO segment,
.got.plt
writable)
gcc -Wl,-z,relro
Full RELRO
readelf -l
+
.got
section read-only
gcc -Wl,-z,relro,-z,now
FORTIFYPresence of
__printf_chk
,
__memcpy_chk
etc.
gcc -D_FORTIFY_SOURCE=2

防护机制检查命令二进制标识
ASLR
cat /proc/sys/kernel/randomize_va_space
操作系统级别(0=关闭,1=部分开启,2=完全开启)
PIE
checksec
readelf -h
(Type: DYN)
二进制编译时添加
-pie
参数
NX
checksec
readelf -l
(无RWE段)
gcc -z noexecstack
(默认开启)
金丝雀
checksec
或查找
__stack_chk_fail@plt
符号
gcc -fstack-protector-all
部分RELRO
readelf -l
(存在GNU_RELRO段,
.got.plt
可写)
gcc -Wl,-z,relro
完全RELRO
readelf -l
+
.got
段只读
gcc -Wl,-z,relro,-z,now
FORTIFY存在
__printf_chk
__memcpy_chk
等符号
gcc -D_FORTIFY_SOURCE=2

2. ASLR BYPASS

2. ASLR绕过

ASLR randomizes base addresses of stack, heap, libc, and mmap regions at each execution.
Bypass MethodRequired PrimitiveNotes
Information leakAny read primitive (format string, OOB read, UAF)Leak libc/stack/heap address → calculate base
Partial overwriteWrite primitive (limited length)Overwrite last 1-2 bytes (page offset fixed)
Brute force (32-bit)Ability to reconnect/retry~256–4096 attempts (8-12 bits entropy)
Return-to-PLTStack overflowPLT addresses are at fixed offset from binary base (if no PIE)
ret2dlresolveStack overflow + write primitiveResolve arbitrary function without knowing libc base
Format string leakFormat string vulnerability
%N$p
for stack/libc/heap addresses
Stack readingByte-by-byte (fork server)Read stack byte-by-byte via crash oracle
ASLR会在每次程序执行时随机化栈、堆、libc和mmap区域的基地址。
绕过方法所需原语说明
信息泄露任意读原语(格式化字符串、越界读、UAF)泄露libc/栈/堆地址 → 计算基地址
部分覆写有限长度的写原语覆写最后1-2字节(页偏移固定)
暴力破解(32位)支持重连/重试约256–4096次尝试(8-12位熵)
返回PLT栈溢出PLT地址相对于二进制基地址偏移固定(无PIE时)
ret2dlresolve栈溢出 + 写原语无需知道libc基地址即可解析任意函数
格式化字符串泄露格式化字符串漏洞
%N$p
获取栈/libc/堆地址
栈读取逐字节读取(fork服务场景)通过崩溃预言机逐字节读取栈内容

ASLR Entropy (x86-64 Linux)

ASLR熵值(x86-64 Linux)

RegionEntropy (bits)Positions
Stack22~4M
mmap / libc28~256M
Heap (brk)13~8K
PIE binary28~256M

内存区域熵值(位)可能位置数
22~4M
mmap / libc28~256M
堆(brk)13~8K
PIE二进制28~256M

3. PIE BYPASS

3. PIE绕过

PIE (Position Independent Executable) randomizes the binary's own code/data base address.
Bypass MethodRequired PrimitiveNotes
Information leakRead return address from stackPIE base = leaked_addr - known_offset
Partial overwriteOne-byte or two-byte writeLast 12 bits of page offset are fixed
Format string leakFormat string vulnerability
%N$p
where N points to .text return address
Relative addressingKnowledge of binary layoutIf you know relative offsets, only need one leak
PIE(位置无关可执行文件)会随机化二进制自身的代码/数据基地址。
绕过方法所需原语说明
信息泄露从栈读取返回地址PIE基地址 = 泄露地址 - 已知偏移
部分覆写1字节或2字节写权限页偏移的最后12位固定
格式化字符串泄露格式化字符串漏洞用指向.text段返回地址的
%N$p
泄露
相对寻址已知二进制布局如果知道相对偏移,仅需一次泄露即可

Partial Overwrite Details

部分覆写细节

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

PIE二进制加载地址示例:0x555555554000
偏移0x1234处的函数地址:0x555555555234

覆写返回地址最后2字节:0x?234 → 0x?XXX
未知部分:12-15位(1个半字节=4位=16种可能)
单次尝试成功率:1/16

4. NX / DEP BYPASS

4. NX / DEP绕过

NX (No-eXecute) / DEP (Data Execution Prevention) prevents execution of code on the stack/heap.
Bypass MethodDetail
ROP (Return-Oriented Programming)Chain existing code gadgets ending in
ret
ret2libcCall libc functions (system, execve) directly
ret2csuUse
__libc_csu_init
gadgets for controlled function calls
ret2dlresolveForge dynamic linker structures to resolve arbitrary functions
SROPUse sigreturn to set all registers from fake signal frame
mprotect ROPChain mprotect(addr, size, PROT_RWX) → make page executable → jump to shellcode
JIT sprayIn JIT environments (V8, etc.), create executable code via JIT compiler
NX(不可执行)/ DEP(数据执行防护)会阻止栈/堆上的代码执行。
绕过方法详情
ROP(面向返回编程)串联以
ret
结尾的现有代码gadget
ret2libc直接调用libc函数(system、execve)
ret2csu
__libc_csu_init
gadget实现可控函数调用
ret2dlresolve伪造动态链接器结构解析任意函数
SROP用sigreturn从伪造信号帧设置所有寄存器
mprotect ROP串联调用mprotect(addr, size, PROT_RWX) → 使页可执行 → 跳转到shellcode
JIT喷射在JIT环境(V8等)中,通过JIT编译器生成可执行代码

mprotect Chain

mprotect链示例

python
undefined
python
undefined

Make stack executable, then jump to shellcode

使栈可执行,然后跳转到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

---
rop = b'A' * offset rop += p64(pop_rdi) + p64(stack_page) # 页对齐地址 rop += p64(pop_rsi) + p64(0x1000) # 大小 rop += p64(pop_rdx) + p64(7) # PROT_READ|PROT_WRITE|PROT_EXEC rop += p64(mprotect_addr) rop += p64(shellcode_addr) # 跳转到现在可执行栈上的shellcode

---

5. RELRO BYPASS

5. RELRO绕过

RELRO LevelGOT StatusBypass
No RELROGOT fully writableDirect GOT overwrite
Partial RELRO
.got.plt
writable (lazy binding)
GOT overwrite still works
Full RELROAll GOT entries resolved at load, GOT read-onlyCannot write GOT → target other structures
RELRO级别GOT状态绕过方法
无RELROGOT完全可写直接覆写GOT
部分RELRO
.got.plt
可写(延迟绑定)
仍可使用GOT覆写
完全RELRO所有GOT条目加载时就完成解析,GOT只读无法写GOT → targeting其他结构

Full RELRO Alternative Targets

完全RELRO替代目标

TargetWhenHow
__malloc_hook
glibc < 2.34Overwrite with one_gadget
__free_hook
glibc < 2.34Overwrite with
system
, trigger
free("/bin/sh")
_IO_FILE vtable
Any glibcFSOP / vtable hijack
__exit_funcs
Any glibcOverwrite exit handler list
TLS_dtor_list
glibc ≥ 2.34Thread-local destructor list (needs pointer guard)
.fini_array
If writableOverwrite destructor function pointers
Stack return addressDirect stack writeOverwrite return address for ROP
See arbitrary-write-to-rce for comprehensive target list.

目标适用场景方法
__malloc_hook
glibc < 2.34覆写为one_gadget
__free_hook
glibc < 2.34覆写为
system
,触发
free("/bin/sh")
_IO_FILE vtable
所有glibc版本FSOP / vtable劫持
__exit_funcs
所有glibc版本覆写退出处理程序列表
TLS_dtor_list
glibc ≥ 2.34线程局部析构函数列表(需要指针防护)
.fini_array
可写时覆写析构函数指针
栈返回地址可直接写栈时覆写返回地址实现ROP
查看 arbitrary-write-to-rce 获取完整目标列表。

6. CANARY BYPASS

6. 金丝雀绕过

MethodConditionDetail
Format string leakprintf(user_input)
%N$p
to read canary from stack
Brute-forcefork() server (canary persists in child)Byte-by-byte: 256 × (canary_size-1) attempts
Stack readingPartial overwrite / info leakOverwrite canary's null byte, leak via output
Thread canary overwriteOverflow reaches TLSCanary at
fs:[0x28]
; overflow past buffer to TLS → overwrite canary with known value
Canary-relative overwriteOverflow after canary but before return addrSkip canary, only overwrite return address (rare layout)
Heap-basedVulnerability is on heap, not stackCanary only protects stack
__stack_chk_fail GOT overwritePartial RELROOverwrite
__stack_chk_fail@GOT
to point to harmless function → canary check passes
方法条件详情
格式化字符串泄露存在printf(user_input)
%N$p
从栈读取金丝雀值
暴力破解fork()服务(金丝雀在子进程中保持不变)逐字节破解:256 × (金丝雀大小-1)次尝试
栈读取部分覆写 / 信息泄露覆写金丝雀的空字节,通过输出泄露
线程金丝雀覆写溢出可以到达TLS金丝雀位于
fs:[0x28]
;溢出到TLS → 用已知值覆写金丝雀
金丝雀相对覆写溢出发生在金丝雀之后、返回地址之前跳过金丝雀,仅覆写返回地址(罕见布局)
堆-based漏洞漏洞在堆上而非栈上金丝雀仅保护栈
__stack_chk_fail GOT覆写部分RELRO覆写
__stack_chk_fail@GOT
指向无害函数 → 金丝雀检查通过

Canary Format

金丝雀格式

x86:    0x00XXXXXX (4 bytes, leading null byte)
x86-64: 0x00XXXXXXXXXXXXXX (8 bytes, leading null byte)
The leading
\x00
prevents string operations from accidentally reading the canary.

x86:    0x00XXXXXX (4字节,前导空字节)
x86-64: 0x00XXXXXXXXXXXXXX (8字节,前导空字节)
前导的
\x00
可以防止字符串操作意外读取金丝雀值。

7. FORTIFY_SOURCE BYPASS

7. FORTIFY_SOURCE绕过

_FORTIFY_SOURCE=2
adds buffer size checking and restricts format string operations.
Fortified FunctionRestrictionBypass
__printf_chk
%n
with positional args (
%N$n
) forbidden
Use non-positional
%n
or
%hn
chain
__memcpy_chk
Destination buffer size checkedUse heap overflow instead of stack
__strcpy_chk
Same
__read_chk
Read size checked against buffer
_FORTIFY_SOURCE=2
添加了缓冲区大小检查,限制格式化字符串操作。
加固函数限制绕过方法
__printf_chk
禁止使用带位置参数的
%n
%N$n
用非位置型
%n
%hn
__memcpy_chk
检查目标缓冲区大小用堆溢出替代栈溢出
__strcpy_chk
同上
__read_chk
对照缓冲区检查读取大小

Format String with FORTIFY_SOURCE

FORTIFY_SOURCE下的格式化字符串利用

python
undefined
python
undefined

%1$n is blocked by __printf_chk

%1$n会被__printf_chk拦截

But sequential (non-positional) %n may still work:

但顺序(非位置型)%n可能仍然有效:

Print exact byte count, then %hn — must be very precise

打印精确字节数,然后用%hn — 必须非常精确

Or: find unfortified printf in binary/libc via ROP

或者:通过ROP找到二进制/libc中未加固的printf


---

---

8. CET (Control-flow Enforcement Technology)

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

Intel CET adds two mechanisms:
Intel CET添加了两种机制:

Shadow Stack

影子栈

  • Hardware-maintained copy of return addresses
  • On
    ret
    , CPU checks shadow stack matches actual stack
  • Mismatch →
    #CP
    fault (control protection exception)
ImpactDetail
ROP blockedReturn address overwrite detected on
ret
JOP possible
jmp [reg]
not checked by shadow stack
COP possible
call [reg]
pushes to shadow stack but target validated by IBT
  • 硬件维护的返回地址副本
  • 执行
    ret
    时,CPU检查影子栈与实际栈是否匹配
  • 不匹配 → 触发
    #CP
    故障(控制保护异常)
影响详情
ROP被阻断
ret
时会检测到返回地址被覆写
JOP仍可行影子栈不检查
jmp [reg]
COP仍可行
call [reg]
会推送到影子栈,但目标会被IBT验证

Indirect Branch Tracking (IBT)

间接分支跟踪(IBT)

  • Indirect
    jmp
    /
    call
    must land on
    ENDBR64
    instruction
  • Non-ENDBR landing →
    #CP
    fault
Bypass:
  • Data-only attacks (don't change control flow)
  • Find valid ENDBR gadgets that chain into useful operations
  • JOP with ENDBR-prefixed gadgets
  • Target structures outside CFI scope (modprobe_path, function pointer arrays)

  • 间接
    jmp
    /
    call
    必须落在
    ENDBR64
    指令上
  • 非ENDBR着陆 → 触发
    #CP
    故障
绕过方法
  • 纯数据攻击(不改变控制流)
  • 找到可以串联成有效操作的合法ENDBR gadget
  • 使用带ENDBR前缀的gadget实现JOP
  • targetingCFI范围外的结构(modprobe_path、函数指针数组)

9. MTE (Memory Tagging Extension, ARM)

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

ARM MTE assigns 4-bit tags to memory pointers and allocations. Tag mismatch = fault.
AspectDetail
Tag bits4 bits in pointer (bits 56-59) = 16 possible tags
Granule16 bytes (each 16-byte granule has one tag)
CheckLoad/store: pointer tag must match memory tag
ProbabilisticRandom tag → 1/16 chance attacker guesses correctly
ARM MTE为内存指针和内存分配分配4位标签,标签不匹配就会触发故障。
维度详情
标签位指针中的4位(56-59位)= 16种可能的标签
颗粒度16字节(每个16字节内存颗粒对应一个标签)
检查加载/存储时:指针标签必须与内存标签匹配
概率性随机标签 → 攻击者猜对的概率为1/16

Bypass Approaches

绕过方法

MethodSuccess Rate
Brute-force1/16 per attempt (6.25%)
Tag oracleSide-channel to determine tag (timing, error messages)
In-bounds exploitStay within same tagged region (use relative offsets)
Tag bypass gadgetUse
LDGM
/
STGM
instructions if accessible
Speculative executionSpectre-style bypass of tag check

方法成功率
暴力破解每次尝试1/16(6.25%)
标签预言机侧信道获取标签(时序、错误信息)
界内利用保持在同一标签区域内(使用相对偏移)
标签绕过gadget如果可以访问
LDGM
/
STGM
指令可利用
推测执行Spectre风格的标签检查绕过

10. DECISION TREE

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
二进制分析:checksec输出
├── NX未开启?
│   └── 栈/堆上直接放shellcode(最简单路径)
├── NX已开启(现代标准二进制)?
│   ├── 需要代码执行 → ROP/ret2libc
│   │
│   ├── 已启用金丝雀?
│   │   ├── 是fork服务器? → 逐字节暴力破解
│   │   ├── 有格式化字符串漏洞? → 通过%p泄露金丝雀
│   │   ├── 是堆漏洞? → 金丝雀不保护堆
│   │   └── 是部分RELRO? → 覆写__stack_chk_fail@GOT
│   │
│   ├── 已启用PIE?
│   │   ├── 有格式化字符串漏洞? → 泄露.text地址 → 计算PIE基地址
│   │   ├── 可部分覆写 → 最后12位固定(1/16概率暴力破解)
│   │   └── 有越界读? → 泄露代码指针
│   │
│   ├── 已启用ASLR?
│   │   ├── 有信息泄露 → 泄露libc基地址
│   │   ├── 无泄露 → ret2dlresolve或SROP
│   │   ├── 是32位? → 暴力破解可行(约4096次尝试)
│   │   └── 返回PLT(调用PLT函数不需要libc基地址)
│   │
│   ├── RELRO级别?
│   │   ├── 无/部分 → GOT覆写
│   │   └── 完全 → 替代目标:
│   │       ├── glibc < 2.34 → __malloc_hook / __free_hook
│   │       ├── glibc ≥ 2.34 → _IO_FILE / exit_funcs / TLS_dtor_list
│   │       ├── .fini_array(可写时)
│   │       └── 栈返回地址
│   │
│   └── 已启用FORTIFY_SOURCE?
│       ├── 拦截位置型%n → 用顺序型%n或堆漏洞
│       └── 拦截加固函数中的缓冲区溢出 → 用未加固路径
├── 已启用CET(影子栈)?
│   ├── ROP被阻断 → 纯数据攻击或JOP
│   └── ENDBR-gadget串联
└── 已启用MTE(ARM)?
    ├── 1/16概率暴力破解
    └── 保持界内实现相对篡改