canary绕过的五种姿势
Canary绕过的五种姿势
1.利用格式化字符串漏洞泄露canary
一般来说,碰到有格式化字符串漏洞且能多次输入的题目就可以用这种方法,比如下面这个题目有一个for循环,那么就可以第一次read后利用printf泄露canary,第二次read再构造rop链
我们需要知道canary的偏移是多少(这里设为k),然后再利用$k%p来泄露canary,这里找偏移的方法有两种。
第一种是gdb运行在printf设断点,ni跳过,然后查看栈空间,在ida中找到canary的位置,比如下面这道题的canary在ebp-0xc,那就找到输入点到canary的距离,这里找出来是15,注意这是32位的,所以偏移就是15,如果是64位的话,要考虑到寄存器,是从%6$p开始找的,简单说就是要把找到的这个距离加5,即20,之后就可以接收canary了。
第二种找偏移的方法是先用AAAA %p%p…找到格式化字符串的偏移,再看ida中buf到bp的距离,举一个例子:
偏移为7
发现buf距离ebp为0x2c,canary在ebp前面的0xc位置,那么计算方法就是(0x2c-0xc)/4+7=15
如果是64位的话就/8
所以,send一个‘%15$p’就可以接收到canary了,要注意接收方式,先把0x接收掉,然后在把后面的数据转换成16进制的int。
2.截断法泄露canary
先填充数据到canary之前,用sendline发送,然后接收canary
这里一定要特别注意在接收canary之前接收换行符,因为sendline填充最后跟着一个换行符(即0xa),因为小端序的原因,它把canary最后面的\x00填充掉了,这才能保证数据不会在\x00卡住,从而输出canary,举个简单的例子,如果canary的值为0x12345600,那么它的小端序存储为00 56 34 12,我们在sendline前面数据填满后,换行符0a会将00替换掉,所以我们要现在前面接收换行符,再接收后面三个字符,再补齐最后一个\x00。
如果不接收换行符的话,还有另一种方法,那就是先接收4个字符,现在得到的canary是0x1234560a,我们减去0xa也可以得到正确的canary。
3. 修改__stack_chk_fail_local的got表地址
感觉这个做法非常巧妙,而且简单易懂,当只有一次输入机会时,不能像之前那样第一次输入泄露canary,第二次输入构造rop,那我们可以想到这种做法。
原理是当canary识别错误后,程序会调用__stack_chk_fail_local函数,那我们则可以提前劫持这一函数,修改它的got表地址为后门函数的地址,那么当识别出来canary错误后就会调用我们的后门函数。
got劫持在之前的fmt博客里详细讲过,这里放个链接 https://zjnu-kong.github.io/2025/04/26/zb2/
把got劫持的payload后面填充到canary的位置之前即可。
4.逐字节爆破
以上三种方法貌似都要用到printf,当没有printf时,并且有fork函数的时候,就要意识到要用逐字节爆破法,fork函数可以理解成不断进入一个进程,虽然不同进程的canary是不同的,但是fork进入的进程canary都一样,于是我们可以循环对每个字节进行爆破。
例题:[CISCN 2023 初赛]funcanary https://www.nssctf.cn/problem/4057
查看保护发现是canary,pie,nx都开启了
下面是爆破canary的脚本
5.劫持索引指针
后面做l3h的题是这个做法,在这里加上吧,详见l3h第一题heack那篇博客











