PWN-6

安全保护机制的绕过——来自金丝雀与沙箱的“拳打脚踢”

在啃了CTFpwn这么久,强化了栈、初步入门堆章节后,可以逐步了解沙箱与金丝雀保护机制了,这俩是比较常见的保护机制,作用发挥巨大,当然学完这些不能直接让你去实战进行绕过多层保护,但是能让你有一个基础去学习当今更多的基于之前而衍生的出的保护机制的绕过。

在本章中,博主有参考了看雪学苑的学习资料。(其实我也不是全能的...)

文章比较短,大佬们选择性食用。

Canary绕过

泄露canary

金丝雀保护(Canary Protection)是一种安全机制,主要用于检测和防止缓冲区溢出攻击。它的核心原理是在栈帧中放置一个特殊的 值(称为"金丝雀值"),在函数返回前检查这个值是否被修改。

工作原理:

1. 放置金丝雀值:在函数调用时,在栈上返回地址之前放置一个随机值;
2. 检查金丝雀值:在函数返回前,验证这个值是否保持不变;
3. 检测溢出:如果值被修改,说明发生了缓冲区溢出,程序会立即终止。

金丝雀保护是纵深防御策略中的重要一环,虽然不能完全阻止所有攻击,但能显著提高攻击难度。

怎么泄露?

  • 利用栈溢出泄露canary

Canary\x00 结尾,通过栈溢出覆盖canary 最低字节,之后输出输入内容时会连带将canary一同输出。

  • 利用格式化字符串漏洞泄露canary。

由于canary 存储在栈上,因此很容易就可以利用格式化字符串漏洞泄露。

这里是粗略说明,具体怎么泄露,或者对栈溢出、FMT有所遗忘的可以返回PWN-2PWN-3

逐字节爆破

例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>

// 存在缓冲区溢出漏洞的函数
void vuln() {
    char buf[0x100];  // 定义256字节大小的缓冲区
    puts("please input:");
    read(0, buf, 0x200);  // 危险操作:读取512字节数据,远超缓冲区大小
}

int main() {
    setbuf(stdin, NULL);   // 关闭标准输入缓冲
    setbuf(stdout, NULL);  // 关闭标准输出缓冲
    
    while (1) {
        pid_t pid = fork();  // 创建子进程
        
        if (pid < 0) {
            // 创建进程失败,退出循环
            break;
        } 
        else if (pid > 0) {
            // 父进程:等待子进程结束
            wait(0);
        } 
        else {
            // 子进程:执行漏洞函数
            vuln();
        }
    }
    return 0;
}

由于fork产生的子进程的与父进程相同,因此可以根据子进程是否打印报错信息来逐字节爆破canary。

最后更新于 2026-05-08