Canary基本介绍
在基本的栈溢出中,我们可以通过没有限制输入长度或限制不严格的函数等向栈中写入我们构造的数据,可写入的数据包括但不限于:
-
一段可执行的代码(关闭
NX防护的前提下) -
一段特意构造的返回地址等
-
…
传统的防御机制之一就是开启
Canary防护,该机制会向我们运行程序的栈底放入一串8字节的随机数据,在函数即将返回时会验证该数据是否发生改变,若发生改变则说明栈被改变了,直接call进__stack_chk_fail。验证成功则跳到leave 和 ret正常的返回。

如何绕过
直接获取栈中canary的值
若该程序会输出我们输入的字符串,则可以在输入数据时估计超出输入的限制1字节,由于C字符串是以'\0'结尾的,我们多输入的1字节就会覆盖'\0',在接下来的输出中,程序本身使用的输出函数没有限制输出的长度,就会将栈中位于所存数据高地址处的Canary值泄露出来,在接下来我们向栈中写入恶意返回地址的时候就可以将该值覆写回去,验证成功。
获取fs:28h中的canary值
通过观察汇编代码,我们可以发现每次运行程序产生的随机canary值都存在fs:28h中,接下来会将该值放入EAX中再mov进程序的栈空间内。
mov rax,fs:28h
mov [rbp-8],rax
所以若程序中存在任意读的功能的函数,就可以直接读取该地址中的值即可。
逐字节爆破canary值
其余的利用方式由于没有碰到,所以暂时不说,后续遇到了会进行补充。
准备环节
源程序
我们接下来用上述所说的第一种方式来尝试绕过一下canary值的校验。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_LENGTH 100
void init()
{
setvbuf(stdin,0,_IONBF,0);
setvbuf(stdout,0,_IONBF,0);
}
void backdoor()
{
system("/bin/sh");
}
int main()
{
char buf[10] = {0};
init();
printf("[DEBUGING] main: %p\n",main);
printf("Hello,What's Your name?\n");
read(0,buf,MAX_LENGTH);
printf("%s",buf);
printf("Welcom!\n");
printf("But wait,WHO ARE YOU?\n");
read(0,buf,MAX_LENGTH);
printf("I don't know you,so bye ;)\n");
return 0;
}
对应的makefile语句。
OBJS=pwn_1.c
CC=gcc # 默认就为gcc
CFLAGS+=-fstack-protector -no-pie -g
pwn_1:$(OBJS)
$(CC) $^ $(CFLAGS)

本文详细介绍了一种绕过Canary防护机制的方法,利用特定条件获取Canary值,并通过构造恶意返回地址实现对目标函数的调用。
最低0.47元/天 解锁文章
4426

被折叠的 条评论
为什么被折叠?



