前言

第一次 打国际赛

只能说 太有意思啦(难死我吧):sob: :sob: :sob:

首先对师傅们 及 我自己 说句

image-20230306100919179

不管怎么样 我会好好努力学习的

:grin: :grin: :grin: :grin: :grin: :grin:

然后的话 不管怎么说都学到了一点东西

单拿题目来讲 队里师傅出了第一个CycleChaser

笔者呢 就对这道领悟的还算…

(我太菜辣 Orz Orz)

不瞎掰扯了 看题

有所错误, 望指正 诚心希望大家能指明是否有误

笔者万分感谢 (Orz)

CycleChaser

查壳 运行(不能运行)

拖入ida分析

image-20230306103937516

思路

这就是 关键部分

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
v16 = malloc(0x4009uLL);                      // malloc分配0x4009空间来存放上面所作的操作 - 理解位初始化也可以
if ( !v16 )
{
puts("Error.");
exit(6);
}
if ( fread(v16, 1uLL, 0x4009uLL, stdin) != 0x4009 )
{
puts("Error.");
exit(7);
}
v17 = calloc(0x40uLL, 1uLL); // calloc分配64空间 作为true_flag
for ( j = 0; j <= 0x2003F; ++j )
{
if ( j > 0x1FFFF )
{
v5 = *(_BYTE *)((j & 0x3F) + v15); // v5 为 下面异或key
// v15 为 {}中间 - input
}
else
{
LOWORD(n_4) = rand() & 0x3FF;
n_4 = (unsigned __int16)n_4;
v5 = *((_BYTE *)v12 + (unsigned __int16)n_4);// v5是随机出来的
}
if ( (unsigned __int8)step(v16, 0x4009LL) ) // step函数作为关键call
*((_BYTE *)v17 + (j & 0x3F)) ^= v5;
}
for ( k = 0; k <= 0x3F; ++k )
printf("%0X ", *((unsigned __int8 *)v17 + k));// 输出true_flag - v17

好的 引用队内是师傅的思路就是

应该是用符号执行找到一个input使得可以在循环的前0x20000次中都让step返回0,再后续的0x3F次中都返回1

意思就是 说 下面那个 异或的 关键call

让true_flag ^ 1 = 不可控的数

而前面空间 ^ 0 = 可控的数(这个数本身)

example

1
2
3
4
5
6
7
8
9
10
>>> a = 10
>>> a ^ 0
10
>>> a ^ 1
11
>>> b = 1
>>> b ^ 0
1
>>> b ^ 1
0

image-20230306104245640

然后的话 我想用angr跑一下 试试

但笔者学到的都是皮毛

并没有什么结果

后面看师傅的angr 脚本 (只能看懂 我写不出来 Orz)

也没有跑出来结果 大概是 少加了什么约束条件吧

image-20230306110203932

贴一下(以后仿写 嘿嘿)

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
import angr, claripy
import sys, time

def main(argv):
#project
path_to_binary = "cyclechaser"
p = angr.Project(path_to_binary)

#state
start_address = 0x4019D7
initial_state = p.factory.blank_state(
addr = start_address,
add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS }
)

#stack's construct & layout
initial_state.regs.rbp = initial_state.regs.rsp
initial_state.regs.rsp -= 0xF0

#input's symbolic express
input_size = 0x4009
input = claripy.BVS('input', input_size * 8)
pointer_to_input = initial_state.regs.rsp + 0x40
fake_heap_addr_input = 0x30000000
initial_state.memory.store(fake_heap_addr_input, input)
initial_state.memory.store(pointer_to_input, fake_heap_addr_input)

#other's symbolic express
flag_size = 64
out_size = 64
buf_size = 0x400
flag = claripy.BVV(0, flag_size * 8)
out = claripy.BVV(0, out_size * 8)
buf = claripy.BVV(0, buf_size * 8)
fake_heap_addr_flag = 0x40000000
fake_heap_addr_out = 0x50000000
fake_heap_addr_buf = 0x60000000
pointer_to_flag = initial_state.regs.rsp + 0x38
pointer_to_out = initial_state.regs.rsp + 0x48
pointer_to_buf = initial_state.regs.rsp + 0x20
initial_state.memory.store(fake_heap_addr_flag, flag)
initial_state.memory.store(fake_heap_addr_out, out)
initial_state.memory.store(fake_heap_addr_buf, buf)
initial_state.memory.store(pointer_to_flag, fake_heap_addr_flag)
initial_state.memory.store(pointer_to_out, fake_heap_addr_out)
initial_state.memory.store(pointer_to_buf, fake_heap_addr_buf)

# cnt = claripy.BVV(0, 32)
# initial_state.memory.store(initial_state.regs.rsp + 0x10, cnt)

#define some func here
def found(simgr):
if simgr.found:
solution_state = simgr.found[0]
print('success')
solution = solution_state.solver.eval(input, cast_to=bytes).decode()
solution = ' '.join(map('{}'.format, [ solution]))
print(solution)
else:
raise Exception('not solution')

#define some addr here
find_addr = 0x4019E7
avoid_addr = [0x40192C, 0x401478, 0x401510]

#explore
simgr = p.factory.simulation_manager(initial_state)
simgr.explore(find=find_addr, avoid=avoid_addr)
found(simgr)

if __name__ == '__main__':
start = time.time()

main(sys.argv)

end = time.time()
total = end - start
print(total)

结果

然后 师傅写出来暴破的脚本

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

real_flag = bytearray([0] * 64)
for n in range(64):

r = remote('3.123.91.129', 13339)
# r = process('./cyclechaser')

seed = r.recvline()
print(seed)

r.sendline(b'\x00' * (0x4009 - n) + b'\x01' * n)

result = r.recvline()
result = result.split(b' ')
flag = bytearray(b'')
for res in result:
flag += bytes([int(res.decode(), 16)])

for i in range(len(flag)):
if real_flag[i] == 0 and flag[i] != 0:
real_flag[i] = flag[i]

print(flag)

print(real_flag)

比赛closed了 然后 就不贴flag了

需要的师傅自己去跑一下吧

总结

比赛挺好

好的 本文结束

感谢观看 Orz

Orz