攻防世界-re部分题解(五)

后面的题目也越来越难了,比较难比较复杂的题目会单拉出来写,这里就记录一些比较简单的题目。

easy_Maze

看名字就知道是个迷宫题,IDA打开看看

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
int v5[7]; // [rsp+0h] [rbp-270h]
int v6; // [rsp+C0h] [rbp-1B0h]
int v7[7]; // [rsp+D0h] [rbp-1A0h]
int v8; // [rsp+190h] [rbp-E0h]
int v9[7]; // [rsp+1A0h] [rbp-D0h]
int v10; // [rsp+1BCh] [rbp-B4h]
int v11; // [rsp+1C0h] [rbp-B0h]
int v12; // [rsp+1C4h] [rbp-ACh]
int v13; // [rsp+1C8h] [rbp-A8h]
int v14; // [rsp+1CCh] [rbp-A4h]
int v15; // [rsp+1D0h] [rbp-A0h]
int v16; // [rsp+1D4h] [rbp-9Ch]
int v17; // [rsp+1D8h] [rbp-98h]
int v18; // [rsp+1DCh] [rbp-94h]
int v19; // [rsp+1E0h] [rbp-90h]
int v20; // [rsp+1E4h] [rbp-8Ch]
int v21; // [rsp+1E8h] [rbp-88h]
int v22; // [rsp+1ECh] [rbp-84h]
int v23; // [rsp+1F0h] [rbp-80h]
int v24; // [rsp+1F4h] [rbp-7Ch]
int v25; // [rsp+1F8h] [rbp-78h]
int v26; // [rsp+1FCh] [rbp-74h]
int v27; // [rsp+200h] [rbp-70h]
int v28; // [rsp+204h] [rbp-6Ch]
int v29; // [rsp+208h] [rbp-68h]
int v30; // [rsp+20Ch] [rbp-64h]
int v31; // [rsp+210h] [rbp-60h]
int v32; // [rsp+214h] [rbp-5Ch]
int v33; // [rsp+218h] [rbp-58h]
int v34; // [rsp+21Ch] [rbp-54h]
int v35; // [rsp+220h] [rbp-50h]
int v36; // [rsp+224h] [rbp-4Ch]
int v37; // [rsp+228h] [rbp-48h]
int v38; // [rsp+22Ch] [rbp-44h]
int v39; // [rsp+230h] [rbp-40h]
int v40; // [rsp+234h] [rbp-3Ch]
int v41; // [rsp+238h] [rbp-38h]
int v42; // [rsp+23Ch] [rbp-34h]
int v43; // [rsp+240h] [rbp-30h]
int v44; // [rsp+244h] [rbp-2Ch]
int v45; // [rsp+248h] [rbp-28h]
int v46; // [rsp+24Ch] [rbp-24h]
int v47; // [rsp+250h] [rbp-20h]
int v48; // [rsp+254h] [rbp-1Ch]
int v49; // [rsp+258h] [rbp-18h]
int v50; // [rsp+25Ch] [rbp-14h]
int v51; // [rsp+260h] [rbp-10h]

v9[0] = 1;
v9[1] = 1;
v9[2] = -1;
v9[3] = 1;
v9[4] = -1;
v9[5] = 1;
v9[6] = -1;
v10 = 0;
v11 = 0;
v12 = 0;
v13 = 0;
v14 = 1;
v15 = -1;
v16 = 0;
v17 = 0;
v18 = 1;
v19 = 0;
v20 = 0;
v21 = 1;
v22 = 0;
v23 = -1;
v24 = -1;
v25 = 0;
v26 = 1;
v27 = 0;
v28 = 1;
v29 = -1;
v30 = 0;
v31 = -1;
v32 = 0;
v33 = 0;
v34 = 0;
v35 = 0;
v36 = 0;
v37 = 1;
v38 = -1;
v39 = -1;
v40 = 1;
v41 = -1;
v42 = 0;
v43 = -1;
v44 = 2;
v45 = 1;
v46 = -1;
v47 = 0;
v48 = 0;
v49 = -1;
v50 = 1;
v51 = 0;
memset(v7, 0, 0xC0uLL);
v8 = 0;
memset(v5, 0, 0xC0uLL);
v6 = 0;
Step_0((int (*)[7])v9, 7, (int (*)[7])v7);
Step_1((int (*)[7])v7, 7, (int (*)[7])v5);
v3 = std::operator<<<std::char_traits<char>>(&_bss_start, "Please help me out!");
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
Step_2((int (*)[7])v5, 7);
system("pause");
return 0;
}

首先新建了三个地图,初始化了其中一个,然后利用下面两步分别初始化另外两个图

1
2
Step_0((int (*)[7])v9, 7, (int (*)[7])v7);
Step_1((int (*)[7])v7, 7, (int (*)[7])v5);

具体的操作在Step_2((int (*)[7])v5, 7)里,可以看到只用了最后的一个图,可以直接动态调试dump出地图来,然后看一下具体操作

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
__int64 __fastcall Step_2(int (*a1)[7])
{
int v1; // eax
__int64 v2; // rax
__int64 v3; // rax
__int64 result; // rax
__int64 v5; // rax
char v6[35]; // [rsp+10h] [rbp-30h]
char v7; // [rsp+33h] [rbp-Dh]
int v8; // [rsp+34h] [rbp-Ch]
int v9; // [rsp+38h] [rbp-8h]
int v10; // [rsp+3Ch] [rbp-4h]

v10 = 0;
v9 = 0;
v8 = 0;
while ( v8 <= 29 && (*a1)[7 * v10 + v9] == 1 )
{
std::operator>><char,std::char_traits<char>>(&std::cin, &v7);
v1 = v8++;
v6[v1] = v7;
if ( v7 == 100 )
{
++v9;
}
else if ( v7 > 100 )
{
if ( v7 == 115 )
{
++v10;
}
else
{
if ( v7 != 119 )
goto LABEL_14;
--v10;
}
}
else if ( v7 == 97 )
{
--v9;
}
else
{
LABEL_14:
v2 = std::operator<<<std::char_traits<char>>(&_bss_start, "include illegal words.");
std::ostream::operator<<(v2, &std::endl<char,std::char_traits<char>>);
}
}
if ( v10 != 6 || v9 != 6 )
{
v5 = std::operator<<<std::char_traits<char>>(&_bss_start, "Oh no!,Please try again~~");
std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
result = 0LL;
}
else
{
v3 = std::operator<<<std::char_traits<char>>(&_bss_start, "Congratulations!");
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
output(v6, v8);
result = 1LL;
}
return result;
}

难度不是很大,经典的wasd,只能经过1的位置,走到最后就可以了,整个路径的操作就是flag,格式为UNCTF{}

dump出的地图为

1
2
3
4
5
6
7
1 0 0 1 1 1 1
1 0 1 1 0 0 1
1 1 1 0 1 1 1
0 0 0 1 1 0 0
1 1 1 1 0 0 0
1 0 0 0 1 1 1
1 1 1 1 1 0 1

走出来就可以了

1
ssddwdwdddssaasasaaassddddwdds

验证一下

1
2
3
4
5
6
root@rycbar17th:~# ./easy_Maze 
Please help me out!
ssddwdwdddssaasasaaassddddwdds
Congratulations!
Thanks! Give you a flag: UNCTF{ssddwdwdddssaasasaaassddddwdds}
sh: 1: pause: not found

得到flag

1
UNCTF{ssddwdwdddssaasasaaassddddwdds}

ReverseMe-120

将输入的字符串进行base64加密然后异或,和明文字符串进行对比

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
if ( v18 && *v19 >= v13 )
{
v21 = 3;
v14 = 0;
for ( lengtha = 0; v5; --v5 )
{
v15 = *v7;
if ( *v7 != 13 && v15 != 10 && v15 != 32 )
{
v16 = byte_414E40[v15];
v21 -= v16 == 64;
v14 = v16 & 0x3F | (v14 << 6);
if ( ++lengtha == 4 )
{
lengtha = 0;
if ( v21 )
*v12++ = BYTE2(v14);
if ( v21 > 1 )
*v12++ = BYTE1(v14);
if ( v21 > 2 )
*v12++ = v14;
}
}
++v7;
}

有很多的无用代码,这里是关键代码,可以看到每四个字节进行了拼接,输出为三个字节,很显然是base64。

Replace

湖湘杯2018的题目,当时还参加过,那时候连这道题都毫无头绪(真的菜

这就是个简单的换表题,先upx脱个壳

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // kr00_4
char Buf; // [esp+4h] [ebp-2Ch]
char Dst; // [esp+5h] [ebp-2Bh]

Buf = 0;
memset(&Dst, 0, 0x27u);
printf("Welcome The System\nPlease Input Key:");
gets_s(&Buf, 0x28u);
v3 = strlen(&Buf);
if ( (unsigned int)(v3 - 35) <= 2 )
{
if ( sub_401090((int)&Buf, v3) == 1 )
printf("Well Done!\n");
else
printf("Your Wrong!\n");
}
return 0;
}

signed int __fastcall sub_401090(int input, int length)
{
int _input; // ebx
int index; // edx
char tmp_char; // al
int v6; // esi
int v7; // edi
char v8; // al
int v9; // eax
char v10; // cl
int v11; // eax
int v12; // ecx

_input = input;
if ( length != 35 )
return -1;
index = 0;
while ( 1 )
{
tmp_char = *(_BYTE *)(index + _input);
v6 = (tmp_char >> 4) % 16;
v7 = (16 * tmp_char >> 4) % 16;
v8 = byte_402150[2 * index];
if ( v8 < '0' || v8 > '9' )
v9 = v8 - 'W';
else
v9 = v8 - '0';
v10 = byte_402151[2 * index];
v11 = 16 * v9;
if ( v10 < '0' || v10 > '9' )
v12 = v10 - 'W';
else
v12 = v10 - '0';
if ( (unsigned __int8)byte_4021A0[16 * v6 + v7] != ((v11 + v12) ^ 0x19) )
break;
if ( ++index >= 35 )
return 1;
}
return -1;
}

处理了半天,高四位低四位的处理来处理去,最后还要合在一起……

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
target = [
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01,
0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D,
0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4,
0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7,
0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E,
0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB,
0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB,
0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C,
0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C,
0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D,
0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A,
0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3,
0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A,
0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E,
0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9,
0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9,
0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99,
0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
]
var = [0x2a, 0x49, 0xf6, 0x9c, 0x38, 0x39, 0x5c, 0xde, 0x96, 0xd6, 0xde, 0x96, 0xd6, 0xf4, 0xe0, 0x25, 0x48, 0x49,
0x54, 0xd6, 0x19, 0x54, 0x48, 0xde, 0xf6, 0xe2, 0xda, 0xd6, 0x77, 0x86, 0xe2, 0x1d, 0x5a, 0xda, 0xe6]
flag = ''
for i in var:
tmp = target.index(i^0x19)
flag += chr(tmp)
print(flag)

输出flag

1
flag{Th1s_1s_Simple_Rep1ac3_Enc0d3}

babyRE

又是一道SMC,不知道为什么最近遇到的还是挺多的

没有任何加密,IDA打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+0h] [rbp-20h]
int v5; // [rsp+18h] [rbp-8h]
int i; // [rsp+1Ch] [rbp-4h]

for ( i = 0; i <= 181; ++i )
{
envp = (const char **)(*((unsigned __int8 *)judge + i) ^ 0xCu);
*((_BYTE *)judge + i) ^= 0xCu;
}
printf("Please input flag:", argv, envp);
__isoc99_scanf("%20s", &s);
v5 = strlen(&s);
if ( v5 == 14 && (unsigned int)judge((__int64)&s) )
puts("Right!");
else
puts("Wrong!");
return 0;
}

经典的输入然后验证,不过judge函数是打不开的,看前面的操作,典型的SMC,写个IDC脚本跑一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <idc.idc>

static main() {
auto judge, addr,tmp;
judge = 0x600B00;
auto i;
for ( i = 0; i <= 181; ++i )
{
addr=judge+i;
tmp=Byte(addr);
tmp=tmp^ 0xC;
PatchByte(addr,tmp);
}

Message("Down!");
}

然后改一下judge函数的结束位置,F5分析,逻辑很好懂

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
signed __int64 __fastcall judge(__int64 a1)
{
__int64 v2; // [rsp-8h] [rbp-8h]

*(&v2 - 5) = a1;
*((_BYTE *)&v2 - 32) = 0x66;
*((_BYTE *)&v2 - 31) = 0x6D;
*((_BYTE *)&v2 - 30) = 0x63;
*((_BYTE *)&v2 - 29) = 0x64;
*((_BYTE *)&v2 - 28) = 0x7F;
*((_BYTE *)&v2 - 27) = 0x6B;
*((_BYTE *)&v2 - 26) = 0x37;
*((_BYTE *)&v2 - 25) = 0x64;
*((_BYTE *)&v2 - 24) = 0x3B;
*((_BYTE *)&v2 - 23) = 0x56;
*((_BYTE *)&v2 - 22) = 0x60;
*((_BYTE *)&v2 - 21) = 0x3B;
*((_BYTE *)&v2 - 20) = 0x6E;
*((_BYTE *)&v2 - 19) = 0x70;
for ( *((_DWORD *)&v2 - 1) = 0; *((_DWORD *)&v2 - 1) <= 13; ++*((_DWORD *)&v2 - 1) )
*(_BYTE *)(*((signed int *)&v2 - 1) + *(&v2 - 5)) ^= *((_DWORD *)&v2 - 1);
for ( *((_DWORD *)&v2 - 1) = 0; *((_DWORD *)&v2 - 1) <= 13; ++*((_DWORD *)&v2 - 1) )
{
if ( *(_BYTE *)(*((signed int *)&v2 - 1) + *(&v2 - 5)) != *((_BYTE *)&v2 + *((signed int *)&v2 - 1) - 32) )
return 0LL;
}
return 1LL;
}

这里其实有三个变量,&v2-1的位置是一个整型,实际上是索引值,&v2-5是我们输入的字符串,&v2-19是最终的目标,只有一个异或操作,很简单就可以跑出来结果

1
2
3
4
5
target = [0x66, 0x6D, 0x63, 0x64, 0x7F, 0x6B, 0x37, 0x64, 0x3B, 0x56, 0x60, 0x3B, 0x6E, 0x70]
flag = ''
for i in range(14):
flag += chr(target[i] ^ i)
print(flag)

输出flag

1
flag{n1c3_j0b}

What-does-this-button-do

不知道为什么这题放在了这个位置,简单得不能再简单的一个mobile

jadx打开,很快就可以找到关键代码

1
2
3
4
5
6
7
8
9
10
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flag);
String flag = "";
int[] d = {102, 108, 97, 103, 123, 119, 52, 110, 110, 52, 95, 106, 52, 114, 95, 109, 121, 95, 100, 51, 120, 125};
for (int i = 0; i < 22; i++) {
flag = flag.concat(String.valueOf((char) d[i]));
}
((TextView) findViewById(R.id.flagText)).setText(flag);
}

然后直接输出把flag输出就可以了

不过这题要去掉外面的flag{}提交

1
w4nn4_j4r_my_d3x

76号

单字检测,pintools爆破,得到flag

直接滚轮子

1
flag{09vdf7wefijbk}

easy_go

这题根据名字也知道是go逆向,IDA打开是乱七八糟的函数,也没有任何的symbol,用go重命名的插件给函数重命名,发现一个base64的解码函数和奇怪的字符串,字母表不是很清楚,动态调试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[-------------------------------------code-------------------------------------]
0x4952dd: mov QWORD PTR [rsp],rax
0x4952e1: mov QWORD PTR [rsp+0x8],rcx
0x4952e6: mov QWORD PTR [rsp+0x10],rdx
=> 0x4952eb: call 0x47e620
0x4952f0: mov rax,QWORD PTR [rsp+0x38]
0x4952f5: mov rcx,QWORD PTR [rsp+0x30]
0x4952fa: mov rdx,QWORD PTR [rsp+0x18]
0x4952ff: mov rbx,QWORD PTR [rsp+0x20]
No argument
[------------------------------------stack-------------------------------------]
0000| 0xc000070e90 --> 0xc000074580 ("6789_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345", '\377' <repeats 45 times>, "\005\377\377:;<=>?")
0008| 0xc000070e98 --> 0xc000088040 ("tGRBtXMZgD6ZhalBtCUTgWgZfnkTgqoNsnAVsmUYsGtCt9pEtDEYsql3")
0016| 0xc000070ea0 --> 0x38 ('8')
0024| 0xc000070ea8 --> 0x40 ('@')
0032| 0xc000070eb0 --> 0xc000088040 ("tGRBtXMZgD6ZhalBtCUTgWgZfnkTgqoNsnAVsmUYsGtCt9pEtDEYsql3")
0040| 0xc000070eb8 --> 0x38 ('8')
0048| 0xc000070ec0 --> 0x1
0056| 0xc000070ec8 --> 0x1
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Thread 1 "easyGo" hit Breakpoint 3, 0x00000000004952eb in ?? ()

找到字母表和密文,解密得到flag

1
flag{92094daf-33c9-431e-a85a-8bfbd5df98ad}

easyCpp

这题有很多c++标准库的调用,整体来说不是很难,可以通过调试发现每一部分的作用,也不是很难

re5-packed-movement

极其无聊的一道题,硬生生用mov实现了所有操作,要求输入flag对比一下,直接objdump就能再汇编代码里找到逐字符将flag移入到某个地址,或者因为是逐字符验证,直接pintools爆破也可以

the_maya_society

大致意思就是对当前时间进行一个md5加密,然后和一个字符串连接成目标网址,如果这个目标是对的后面的通信就会得到正确的flag……

时间应该是2012-12-21

2ex1

mips,并且strip过,什么信息都没有,打开输出发现很像base64,但应该换过表,ghidra打开找找可疑字符串,发现奇怪的字符串

1
@,.1fgvw#`/2ehux$~"3dity%_;4cjsz^+{5bkrA&=}6alqB*-[70mpC()]89noD

试一试就得到了flag

1
flag{change53233}

对这个字符串表进行交叉引用查询到话也可以找到进行base64编码的函数

python_opcode IDA常用宏定义

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×