Stack Canaries 前置知识
原理
Stack canaries(取名自地下煤矿地金丝雀,因为它能提前发现煤气泄漏,有预警的作用)。用于对抗栈溢出攻击,即SSP安全机制,也叫Stack Cookie。Canary是栈上的一个随机数(大小与程序位数一样),当栈溢出攻击从低地址向高地址覆盖意图控制函数的返回指针时,就一定会先覆盖到Canary,这样程序只需在函数返回前检查Canary是否被篡改即可达到保护目的。
Canary通常分三类:
- Terminator canaries:低位设置为
"\x00"
,一定程度上防止字符串操作溢出泄露canary - Random canaries:程序初始化时随机生成一个值作为canary
- Random XOR canarie:上面的random多个XOR操作,无论时canary还是XOR的数据被篡改都会报错
Linux下的TLS及canary
fs寄存器一般用于指向TLS,TLS的结构体tcbhead_t(64位)中偏移0x28正指向stack_guard,一般检测栈溢出的过程就是,程序加载时glibc先初始化TLS,包括为其分配内存及设置fs寄存器指向TLS(这一部分由系统调用arch_prcl完成
),然后调用security_init()
函数生成Canary的值stack_chk_guard
,并放入fs:0x28,检测的时候对比这个值是否发生变化。
攻击Canarie
核心思路就是避免程序崩溃抛错,有两种方式:
- 将canaries的值泄露出来,栈溢出的时候覆盖上去使其保持不变(PS:Canaries的值一般在存放返回函数地址之前的8/4个字节上)
- 同时篡改TLS和栈上的Canaries
实例一:2017 NJCTF messager
查看基本信息
程序有个地方打开了flag文件,存放到一个变量中,查看交叉引用又找到了回送flag的函数(溢出返回的地址get)
自己写一个flag文件,修改一下messager的权限,打本地。
再看看主函数的一个循环
1 | while ( 1 ) |
知识补充
当一个进程调用
fork()
复刻子进程时,系统会给子进程分配资源,并将父进程的所有值复制到子进程中,相当于克隆父进程。父进程中调用fork()
返回子进程的pid,而子进程中调用fork()
时返回值是0,失败则返回负值。一般来说canarie的值是没法直接爆破的,一是因为canarie的值范围大,二是因为爆破导致程序崩溃重启后的Canarie值可能又会重新随机生成。但是同一个进程包括复刻的子进程里的Canaries是不变的,而子进程的崩溃也不会影响父进程,这就有了可乘之机。
溢出点在函数sub_400Be9()
中,向0x64大小的变量存放至多0x400大小的数据
1 | __int64 sub_400BE9() |
综合分析下来exp就出来了
1 | from pwn import * |
参考资料
《CTF竞赛权威指南(PWN篇)》
Comments