抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

BlackBird的博客

这世界上所有的不利状况,都是当事者能力不足导致的

GUETCTF 2019 number game

爆破

看了一遍代码,不多,但逻辑感觉挺恶心的,所以我们要像神·RX学习,爆破!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
import os
def vio(tmp):
print("test_",": try_",tmp)

p = process("./number_game")
p.sendline(tmp)
re = p.recv()
if b'T' in re:
print("ans: ",tmp);
os.system('spd-say "Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh your program has finished"')
a=input()
p.close()
def fuck(cnt,tmp):
if cnt==10:
vio(tmp)
return
for i in range(48,53):
fuck(cnt+1,tmp+chr(i))

fuck(0,"")

这里用pwntools与程序进行交互。这个爆破程序感觉有很多地方可以优化,例如多线程,但是多线程又不太会……所以只能手动修改代码来跑,同时运行多个,也算是多线程了……(逃

挖个坑吧,抽空学学多线程……

但是好像pwntools的效率比较低……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import subprocess
from itertools import *

list = '01234'
j = 0
for i in product(list, repeat=10):
input = "".join(i)

obj = subprocess.Popen(["./number_game"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write(input)
obj.stdin.close()
cmd_out = obj.stdout.read()
obj.stdout.close()
print input
print cmd_out

if 'cxk' not in cmd_out :
print "bingo!!!!!! : ",input
exit()

这是网上嫖的wp,貌似效率很高……下来再学习以下这个。继续挖坑……

angr

md,我第一遍的angr脚本少了一个avoid导致没跑出来,后来瞅瞅树树的才发现……

1
2
3
4
5
6
7
import angr
p = angr.Project("./number_game",load_options={"auto_load_libs": False})
sta = p.factory.entry_state()
sim = p.factory.simulation_manager(sta)
sim.explore(find=0x400AC1,avoid=[0x400AFC,0x4006F4,0x400736,0x4009DF])
print(sim.found[0].posix.dumps(0))
#b'1134240024\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

硬刚

总之爆破交给虚拟机去跑,我们继续分析程序:

我们就一点一点分析函数(含树……,

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
unsigned __int64 __fastcall main(int a1, char **a2, char **a3)
{
char *v4; // [rsp+8h] [rbp-38h]
__int64 input; // [rsp+10h] [rbp-30h] BYREF
__int16 v6; // [rsp+18h] [rbp-28h]
__int64 v7; // [rsp+20h] [rbp-20h] BYREF
__int16 v8; // [rsp+28h] [rbp-18h]
char v9; // [rsp+2Ah] [rbp-16h]
unsigned __int64 v10; // [rsp+38h] [rbp-8h]

v10 = __readfsqword(0x28u);
input = 0LL;
v6 = 0;
v7 = 0LL;
v8 = 0;
v9 = 0;
__isoc99_scanf("%s", &input);
if ( !(unsigned int)sub_4006D6((const char *)&input) )// 48<= input <=52
{
v4 = (char *)sub_400758((char *)&input, 0, 0xAu);// 根据输入形成了一个类似链表或者树一样的东西……
sub_400807(v4, (int *)&v7); // 把输入换了一个顺序,存储到dword_601080里面,同时改变了v7,,但是哪里变得没看出来……
v9 = 0;
sub_400881((char *)&v7);
if ( (unsigned int)sub_400917() )
{
puts("TQL!");
printf("flag{");
printf("%s", (const char *)&input);
puts("}");
}
else
{
puts("your are cxk!!");
}
}
return __readfsqword(0x28u) ^ v10;
}

那我们能不能这样,我们把校验输入的sub_4006D6patch掉,然后将0123456789作为输入,反正程序没有修改输入,只是换了一个顺序:

image-20210218114711072

然后再通过sub_400881函数进行修改sub_601062~sub_601077的值,下来就是看sub_400917的内容,来看看他的判断条件:

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
0X601060 != 0X601061    0X601065 != 0X601066    0X60106A != 0X60106B
0X601060 != 0X601062 0X601065 != 0X601067 0X60106A != 0X60106C
0X601060 != 0X601063 0X601065 != 0X601068 0X60106A != 0X60106D
0X601060 != 0X601064 0X601065 != 0X601069 0X60106A != 0X60106E
0X601061 != 0X601062 0X601066 != 0X601067 0X60106B != 0X60106C
0X601061 != 0X601063 0X601066 != 0X601068 0X60106B != 0X60106D
0X601061 != 0X601064 0X601066 != 0X601069 0X60106B != 0X60106E
0X601062 != 0X601063 0X601067 != 0X601068 0X60106C != 0X60106D
0X601062 != 0X601064 0X601067 != 0X601069 0X60106C != 0X60106E
0X601063 != 0X601064 0X601068 != 0X601069 0X60106D != 0X60106E

0X60106F != 0X601070 0X601074 != 0X601075 0X601060 != 0X601065
0X60106F != 0X601071 0X601074 != 0X601076 0X601060 != 0X60106A
0X60106F != 0X601072 0X601074 != 0X601077 0X601060 != 0X60106F
0X60106F != 0X601073 0X601074 != 0X601078 0X601060 != 0X601074
0X601070 != 0X601071 0X601075 != 0X601076 0X601065 != 0X60106A
0X601070 != 0X601072 0X601075 != 0X601077 0X601065 != 0X60106F
0X601070 != 0X601073 0X601075 != 0X601078 0X601065 != 0X601074
0X601071 != 0X601072 0X601076 != 0X601077 0X60106A != 0X60106F
0X601071 != 0X601073 0X601076 != 0X601078 0X60106A != 0X601074
0X601072 != 0X601073 0X601077 != 0X601078 0X60106F != 0X601074

0X601061 != 0X601066 0X601062 != 0X601067 0X601063 != 0X601068
0X601061 != 0X60106B 0X601062 != 0X60106C 0X601063 != 0X60106D
0X601061 != 0X601070 0X601062 != 0X601071 0X601063 != 0X601072
0X601061 != 0X601075 0X601062 != 0X601076 0X601063 != 0X601077
0X601066 != 0X60106B 0X601067 != 0X60106C 0X601068 != 0X60106D
0X601066 != 0X601070 0X601067 != 0X601071 0X601068 != 0X601072
0X601066 != 0X601075 0X601067 != 0X601076 0X601068 != 0X601077
0X60106B != 0X601070 0X60106C != 0X601071 0X60106D != 0X601072
0X60106B != 0X601075 0X60106C != 0X601076 0X60106D != 0X601077
0X601070 != 0X601075 0X601071 != 0X601076 0X601072 != 0X601077

0X601064 != 0X601069
0X601064 != 0X60106E
0X601064 != 0X601073
0X601064 != 0X601078
0X601069 != 0X60106E
0X601069 != 0X601073
0X601069 != 0X601078
0X60106E != 0X601073
0X60106E != 0X601078
0X601073 != 0X601078

这里先简述一下他的规律:从0x601060开始到0x601078,每五个分成一组,每组不能有重复的,仅为01234;每一组的第n个数字不能相同;以下受输入影响:

1
2
3
4
5
6
7
8
9
10
byte_601062 = a1[0];
byte_601067 = a1[1];
byte_601069 = a1[2];
byte_60106B = a1[3];
byte_60106E = a1[4];
byte_60106F = a1[5];
byte_601071 = a1[6];
byte_601072 = a1[7];
byte_601076 = a1[8];
byte_601077 = a1[9];

那我们根据规律排除出受输入影响的几个数字应该是多少(有数独内味了~),好吧,就是数独,一个5*5的数独。然后再按照顺序还原成输入:

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
0x601060 = 31h ; 1
0x601061 = 34h ; 4
0x601062 = a1[0] = 30h ; 0
0x601063 = 32h ; 2
0x601064 = 33h ; 3

0x601065 = 33h ; 3
0x601066 = 30h ; 0
0x601067 = a1[1] = 34h ; 4
0x601068 = 31h ; 1
0x601069 = a1[2] = 32h ; 2

0x60106A = 30h ; 0
0x60106B = a1[3] = 31h ; 1
0x60106C = 32h ; 2
0x60106D = 33h ; 3
0x60106E = a1[4] = 34h ; 4

0x60106F = a1[5] = 32h ; 2
0x601070 = 33h ; 3
0x601071 = a1[6] = 31h ; 1
0x601072 = a1[7] = 34h ; 4
0x601073 = 30h ; 0

0x601074 = 34h ; 4
0x601075 = 32h ; 2
0x601076 = a1[8] = 33h ; 3
0x601077 = a1[9] = 30h ; 0
0x601078 = 31h ; 1

再按照image-20210218114711072

这个顺序还原成输入就好了~

HITCTF 2020 Node

好难,先鸽着……

GKCTF 2020 BabyDriver

DIE,IDA64,F12。怎么像一个maze题……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
****************
o.*..*......*..*
*.**...**.*.*.**
*.****.**.*.*.**
*...**....*.*.**
***..***.**.*..*
*.**.***.**.**.*
*.**.******.**.*
*.**....***.**.*
*.*****.***....*
*...***.********
**..***......#**
**.*************
****************

起点和终点明了,主要是上下左右。

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
__int64 __fastcall sub_140001380(__int64 a1, __int64 a2)
{
__int64 v3; // rdi
__int64 v4; // rax
int v5; // ecx
__int16 *v6; // rsi
__int64 v7; // rbp
__int16 v8; // dx
char v9; // dl
const CHAR *v10; // rcx

if ( *(int *)(a2 + 48) >= 0 )
{
v3 = *(_QWORD *)(a2 + 24);
v4 = *(_QWORD *)(a2 + 56) >> 3;
if ( (_DWORD)v4 )
{
v5 = dword_1400030E4;
v6 = (__int16 *)(v3 + 2);
v7 = (unsigned int)v4;
while ( *(_WORD *)(v3 + 4) )
{
LABEL_28:
v6 += 6;
if ( !--v7 )
goto LABEL_29;
}
aO[v5] = '.';
v8 = *v6;
if ( *v6 == 23 )
{
if ( (v5 & 0xFFFFFFF0) != 0 )
{
v5 -= 16;
goto LABEL_21;
}
v5 += 208;
dword_1400030E4 = v5;
}
if ( v8 == 37 )
{
if ( (v5 & 0xFFFFFFF0) != 208 )
{
v5 += 16;
goto LABEL_21;
}
v5 -= 208;
dword_1400030E4 = v5;
}
if ( v8 == 36 )
{
if ( (v5 & 0xF) != 0 )
{
--v5;
goto LABEL_21;
}
v5 += 15;
dword_1400030E4 = v5;
}
if ( v8 != 38 )
goto LABEL_22;
if ( (v5 & 0xF) == 15 )
v5 -= 15;
else
++v5;
LABEL_21:
dword_1400030E4 = v5;
LABEL_22:
v9 = aO[v5];
if ( v9 == '*' )
{
v10 = "failed!\n";
}
else
{
if ( v9 != '#' )
{
LABEL_27:
aO[v5] = 111;
goto LABEL_28;
}
v10 = "success! flag is flag{md5(input)}\n";
}
dword_1400030E4 = 16;
DbgPrint(v10);
v5 = dword_1400030E4;
goto LABEL_27;
}
}
LABEL_29:
if ( *(_BYTE *)(a2 + 65) )
*(_BYTE *)(*(_QWORD *)(a2 + 184) + 3i64) |= 1u;
return *(unsigned int *)(a2 + 48);
}

其实很容易看出来哪些分支是上下左右,,,但是23,36,37,38明显不是常规的ASCII。上网查了一波才知道是键盘扫描码,对应着ijkl手动走一下迷宫:

LKKKLLKLKKKLLLKKKLLLLLL

flag{403950a6f64f7fc4b655dea696997851}

评论