逆向攻防世界CTF系列60-The_Maya_Society

64位无壳,zip下的其它文件浏览一遍,没发现什么线索,先看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
__int64 __fastcall main(int a1, char **a2, char **a3){
size_t v3; // rbx
size_t v4; // rax
size_t v6; // rax
size_t v7; // rax
__int64 v8; // rdi
time_t timer; // [rsp+18h] [rbp-128h] BYREF
char v10[32]; // [rsp+20h] [rbp-120h] BYREF
char src[32]; // [rsp+40h] [rbp-100h] BYREF
char s[104]; // [rsp+60h] [rbp-E0h] BYREF
__int64 v13; // [rsp+C8h] [rbp-78h] BYREF
char v14[9]; // [rsp+D4h] [rbp-6Ch] BYREF
char v15[9]; // [rsp+DDh] [rbp-63h] BYREF
char v16[9]; // [rsp+E6h] [rbp-5Ah] BYREF
char v17[9]; // [rsp+EFh] [rbp-51h] BYREF
void (__fastcall *v18)(__int64); // [rsp+F8h] [rbp-48h]
__int64 v19; // [rsp+100h] [rbp-40h]
char *v20; // [rsp+108h] [rbp-38h]
char *dest; // [rsp+110h] [rbp-30h]
int *v22; // [rsp+118h] [rbp-28h]
size_t v23; // [rsp+120h] [rbp-20h]
struct tm *tp; // [rsp+128h] [rbp-18h]

strcpy(v10, ".fluxfingers.net");
timer = time(0LL);
tp = localtime(&timer);
strftime(s, 0x63uLL, "%Y-%m-%d", tp);
v23 = strlen(s);
sub_B5A(s, v23);
v22 = &dword_2030B8;
snprintf(
v17,
9uLL,
"%02x%02x%02x%02x",
(unsigned __int8)dword_2030B8,
BYTE1(dword_2030B8),
BYTE2(dword_2030B8),
HIBYTE(dword_2030B8));
v22 = &dword_2030C0;
snprintf(
v16,
9uLL,
"%02x%02x%02x%02x",
(unsigned __int8)dword_2030C0,
BYTE1(dword_2030C0),
BYTE2(dword_2030C0),
HIBYTE(dword_2030C0));
v22 = &dword_2030B4;
snprintf(
v15,
9uLL,
"%02x%02x%02x%02x",
(unsigned __int8)dword_2030B4,
BYTE1(dword_2030B4),
BYTE2(dword_2030B4),
HIBYTE(dword_2030B4));
v22 = &dword_2030BC;
snprintf(
v14,
9uLL,
"%02x%02x%02x%02x",
(unsigned __int8)dword_2030BC,
BYTE1(dword_2030BC),
BYTE2(dword_2030BC),
HIBYTE(dword_2030BC));
snprintf(src, 0x21uLL, "%s%s%s%s", v17, v16, v15, v14);
v3 = strlen(src);
v4 = strlen(v10);
dest = (char *)malloc(v3 + v4 + 1);
if ( !dest )
return 1LL;
*dest = 0;
strcat(dest, src);
strcat(dest, v10);
v20 = (char *)sub_18A4(dest);
if ( !v20 )
return 1LL;
v6 = strlen(v20);
v19 = sub_15E0(v20, v6, &v13);
v7 = strlen(v20);
v18 = (void (__fastcall *)(__int64))sub_15E0(v20, v7, &v13);
if ( !v19 )
return 1LL;
v8 = v19;
sub_1858(v19, v13, v18);
v18(v8);
return 0LL;
}

两眼一黑 T.T,硬着看

看到s和v10,time获取本机时间给s。

跟进sub_B5A

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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
void __fastcall sub_B5A(const void *a1, size_t a2)
{
int v2; // kr00_4
int v3[64]; // [rsp+20h] [rbp-240h]
int v4[65]; // [rsp+120h] [rbp-140h]
int v5; // [rsp+224h] [rbp-3Ch]
__int64 v6; // [rsp+228h] [rbp-38h]
void *dest; // [rsp+230h] [rbp-30h]
unsigned int v8; // [rsp+23Ch] [rbp-24h]
int v9; // [rsp+240h] [rbp-20h]
unsigned int k; // [rsp+244h] [rbp-1Ch]
int v11; // [rsp+248h] [rbp-18h]
int v12; // [rsp+24Ch] [rbp-14h]
int v13; // [rsp+250h] [rbp-10h]
int v14; // [rsp+254h] [rbp-Ch]
int j; // [rsp+258h] [rbp-8h]
int i; // [rsp+25Ch] [rbp-4h]

dest = 0LL;
v4[0] = 7;
v4[1] = 12;
v4[2] = 17;
v4[3] = 22;
v4[4] = 7;
v4[5] = 12;
v4[6] = 17;
v4[7] = 22;
v4[8] = 7;
v4[9] = 12;
v4[10] = 17;
v4[11] = 22;
v4[12] = 7;
v4[13] = 12;
v4[14] = 17;
v4[15] = 22;
v4[16] = 5;
v4[17] = 9;
v4[18] = 14;
v4[19] = 20;
v4[20] = 5;
v4[21] = 9;
v4[22] = 14;
v4[23] = 20;
v4[24] = 5;
v4[25] = 9;
v4[26] = 14;
v4[27] = 20;
v4[28] = 5;
v4[29] = 9;
v4[30] = 14;
v4[31] = 20;
v4[32] = 4;
v4[33] = 11;
v4[34] = 16;
v4[35] = 23;
v4[36] = 4;
v4[37] = 11;
v4[38] = 16;
v4[39] = 23;
v4[40] = 4;
v4[41] = 11;
v4[42] = 16;
v4[43] = 23;
v4[44] = 4;
v4[45] = 11;
v4[46] = 16;
v4[47] = 23;
v4[48] = 6;
v4[49] = 10;
v4[50] = 15;
v4[51] = 21;
v4[52] = 6;
v4[53] = 10;
v4[54] = 15;
v4[55] = 21;
v4[56] = 6;
v4[57] = 10;
v4[58] = 15;
v4[59] = 21;
v4[60] = 6;
v4[61] = 10;
v4[62] = 15;
v4[63] = 21;
v3[0] = -680876936;
v3[1] = -389564586;
v3[2] = 606105819;
v3[3] = -1044525330;
v3[4] = -176418897;
v3[5] = 1200080426;
v3[6] = -1473231341;
v3[7] = -45705983;
v3[8] = 1770035416;
v3[9] = -1958414417;
v3[10] = -42063;
v3[11] = -1990404162;
v3[12] = 1804603682;
v3[13] = -40341101;
v3[14] = -1502002290;
v3[15] = 1236535329;
v3[16] = -165796510;
v3[17] = -1069501632;
v3[18] = 643717713;
v3[19] = -373897302;
v3[20] = -701558691;
v3[21] = 38016083;
v3[22] = -660478335;
v3[23] = -405537848;
v3[24] = 568446438;
v3[25] = -1019803690;
v3[26] = -187363961;
v3[27] = 1163531501;
v3[28] = -1444681467;
v3[29] = -51403784;
v3[30] = 1735328473;
v3[31] = -1926607734;
v3[32] = -378558;
v3[33] = -2022574463;
v3[34] = 1839030562;
v3[35] = -35309556;
v3[36] = -1530992060;
v3[37] = 1272893353;
v3[38] = -155497632;
v3[39] = -1094730640;
v3[40] = 681279174;
v3[41] = -358537222;
v3[42] = -722521979;
v3[43] = 76029189;
v3[44] = -640364487;
v3[45] = -421815835;
v3[46] = 530742520;
v3[47] = -995338651;
v3[48] = -198630844;
v3[49] = 1126891415;
v3[50] = -1416354905;
v3[51] = -57434055;
v3[52] = 1700485571;
v3[53] = -1894986606;
v3[54] = -1051523;
v3[55] = -2054922799;
v3[56] = 1873313359;
v3[57] = -30611744;
v3[58] = -1560198380;
v3[59] = 1309151649;
v3[60] = -145523070;
v3[61] = -1120210379;
v3[62] = 718787259;
v3[63] = -343485551;
dword_2030B8 = 1732584193;
dword_2030C0 = -271733879;
dword_2030B4 = -1732584194;
dword_2030BC = 271733878;
for ( i = 8 * a2 + 1; i % 512 != 448; ++i ) ;
v2 = i;
i /= 8;
dest = calloc(v2 / 8 + 64, 1uLL);
memcpy(dest, a1, a2);
*((_BYTE *)dest + a2) = 0x80;
*(_DWORD *)((char *)dest + i) = 8 * a2;
for ( j = 0; j < i; j += 64 )
{
v6 = (__int64)dest + j;
v14 = dword_2030B8;
v13 = dword_2030C0;
v12 = dword_2030B4;
v11 = dword_2030BC;
for ( k = 0; k <= 0x3F; ++k )
{
if ( k > 0xF )
{
if ( k > 0x1F )
{
if ( k > 0x2F )
{
v9 = v12 ^ (v13 | ~v11);
v8 = (7 * (_BYTE)k) & 0xF;
}
else
{
v9 = v11 ^ v12 ^ v13;
v8 = (3 * (_BYTE)k + 5) & 0xF;
}
}
else
{
v9 = v13 & v11 | v12 & ~v11;
v8 = (5 * (_BYTE)k + 1) & 0xF;
}
}
else
{
v9 = v12 & v13 | v11 & ~v13;
v8 = k;
}
v5 = v11;
v11 = v12;
v12 = v13;
v13 += __ROL4__(*(_DWORD *)(4LL * v8 + v6) + v3[k] + v9 + v14, v4[k]);
v14 = v5;
}
dword_2030B8 += v14;
dword_2030C0 += v13;
dword_2030B4 += v12;
dword_2030BC += v11;
}
free(dest);
}

这里其实是MD5算法,对它接触的不多,所以一开始没看出来,参考了攻防世界逆向高手题之The_Maya_Society_the maya society-CSDN博客

第一个64数组,和md5加密中的4大步骤16小步的移位S数字对应。

第二个64数组,符合md5的T[i]大小

image-20241213095429713

下面是md5的实现,md5的448和ABCD是发现这个算法的关键,下次要注意

md5加密的结果存在了寄存器中,这里是把4四个寄存器以16进制显示出来,就是把md5加密结果输出为32位。

格式化输出:snprintf(src, 0x21uLL, “%s%s%s%s”, v17, v16, v15, v14);不用查也可以猜是v17,v16…给了src

v3,v4是长度,dest是v3+v4+1,然后是个strcat(dest, src);

C 库函数 char *strcat(char *dest, const char *src)src 所指向的字符串追加到 dest 所指向的字符串的结尾。

sub_18A4进行处理,成了v20,后面没有用到dest,我们需要跟进看看sub_18A4

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
char *__fastcall sub_18A4(const char *a1){
char *v2; // rax
ns_rr v3; // [rsp+10h] [rbp-24A0h] BYREF
ns_msg v4; // [rsp+430h] [rbp-2080h] BYREF
char s[4096]; // [rsp+480h] [rbp-2030h] BYREF
u_char v6[4104]; // [rsp+1480h] [rbp-1030h] BYREF
char *dest; // [rsp+2488h] [rbp-28h]
size_t n; // [rsp+2490h] [rbp-20h]
char *v9; // [rsp+2498h] [rbp-18h]
char *src; // [rsp+24A0h] [rbp-10h]
int v11; // [rsp+24ACh] [rbp-4h]

v11 = __res_query(a1, 1, 16, v6, 4096);
if ( v11 < 0 ) return 0LL;
ns_initparse(v6, v11, &v4);
v11 = v4._counts[1];
ns_parserr(&v4, ns_s_an, 0, &v3);
ns_sprintrr(&v4, &v3, 0LL, 0LL, s, 0x1000uLL);
v2 = strchr(s, 34);
src = v2 + 1;
if ( v2 == (char *)-1LL ) return 0LL;
v9 = strchr(src, 34);
if ( !v9 ) return 0LL;
n = v9 - src;
dest = (char *)malloc(v9 - src + 1);
strncpy(dest, src, n);
dest[n] = 0;
return dest;
}

image-20241213100716895

image-20241213100805913

获取本地时间–>将时间MD5加密–>结果连接字符串.fluxfingers.net–>进入服务器后端函数sub_55E622E018A4(dest)

sub_15E0应该是最重要的部分

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
char *__fastcall sub_15E0(__int64 a1, unsigned __int64 a2, _QWORD *a3)
{
char *v4; // rax
char *v5; // rax
char *v6; // rax
char v8; // [rsp+28h] [rbp-138h] BYREF
unsigned __int8 v9; // [rsp+29h] [rbp-137h]
unsigned __int8 v10; // [rsp+2Ah] [rbp-136h]
char v11; // [rsp+2Bh] [rbp-135h]
char v12[4]; // [rsp+2Ch] [rbp-134h]
char s[271]; // [rsp+30h] [rbp-130h] BYREF
char v14; // [rsp+13Fh] [rbp-21h]
char *v15; // [rsp+140h] [rbp-20h]
size_t size; // [rsp+148h] [rbp-18h]
unsigned __int64 i; // [rsp+150h] [rbp-10h]
char *v18; // [rsp+158h] [rbp-8h]

memset(s, 128, 0x100uLL);
for ( i = 0LL; i <= 0x3F; ++i )
s[(unsigned __int8)aAbcdefghijklmn[i]] = i;
s[61] = 0;
size = 0LL;
for ( i = 0LL; i < a2; ++i )
{
if ( s[*(unsigned __int8 *)(a1 + i)] != (char)0x80 )
++size;
}
if ( (size & 3) != 0 )
return 0LL;
v15 = (char *)malloc(size);
v18 = v15;
if ( !v15 )
return 0LL;
size = 0LL;
for ( i = 0LL; i < a2; ++i )
{
v14 = s[*(unsigned __int8 *)(a1 + i)];
if ( v14 != (char)0x80 )
{
v12[size] = *(_BYTE *)(a1 + i);
*(&v8 + size) = v14;
if ( ++size == 4 )
{
v4 = v18++;
*v4 = (v9 >> 4) | (4 * v8);
v5 = v18++;
*v5 = (v10 >> 2) | (16 * v9);
v6 = v18++;
*v6 = v11 | (v10 << 6);
size = 0LL;
}
}
}
if ( v18 > v15 )
{
if ( v12[2] == 61 )
{
v18 -= 2;
}
else if ( v12[3] == 61 )
{
--v18;
}
}
*a3 = v18 - v15;
return v15;
}

aAbcdefghijklmn是ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/会不会是base编码?

下面是base64加解密代码,可以发现上面应该是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
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
void encodeBase64(char* str,int len,char** in){
char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//读取3个字节zxc,转换为二进制01111010 01111000 01100011
//转换为4个6位字节,011110 100111 100001 100011
//不足8位在前补0,变成00011110 00100111 00100001 00100011
//若剩余的字节数不足以构成4个字节,补等号
int encodeStrLen = 1 + (len/3)*4 ,k=0;
encodeStrLen += len%3 ? 4 : 0;
char* encodeStr = (char*)(malloc(sizeof(char)*encodeStrLen));
for(int i=0;i<len;i++){
if(len - i >= 3){
encodeStr[k++] = base64[(unsigned char)str[i]>>2];
encodeStr[k++] = base64[((unsigned char)str[i]&0x03)<<4 | (unsigned char)str[++i]>>4];
encodeStr[k++] = base64[((unsigned char)str[i]&0x0f)<<2 | (unsigned char)str[++i]>>6];
encodeStr[k++] = base64[(unsigned char)str[i]&0x3f];
}else if(len-i == 2){
encodeStr[k++] = base64[(unsigned char)str[i] >> 2];
encodeStr[k++] = base64[((unsigned char)str[i]&0x03) << 4 | ((unsigned char)str[++i] >> 4)];
encodeStr[k++] = base64[((unsigned char)str[i]&0x0f) << 2];
encodeStr[k++] = '=';
}else{
encodeStr[k++] = base64[(unsigned char)str[i] >> 2];
encodeStr[k++] = base64[((unsigned char)str[i] & 0x03) << 4]; //末尾补两个等于号
encodeStr[k++] = '=';
encodeStr[k++] = '=';
}
}
encodeStr[k] = '\0';
*in = encodeStr;
}

/**
* 解码既编码的逆过程,先找出编码后的字符在编码之前代表的数字
* 编码中将3位个字符变成4个字符,得到这4个字符的每个字符代表的原本数字
* 因为在编码中间每个字符用base64码表进行了替换,所以这里要先换回来
* 在对换回来的数字进行位运算使其还原成3个字符
*/
void decodeBase64(char* str,int len,char** in){
char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char ascill[129];
int k = 0;
for(int i=0;i<64;i++){
ascill[base64[i]] = k++;
}
int decodeStrlen = len / 4 * 3 + 1;
char* decodeStr = (char*)malloc(sizeof(char)*decodeStrlen);
k = 0;
for(int i=0;i<len;i++){
decodeStr[k++] = (ascill[str[i]] << 2) | (ascill[str[++i]] >> 4);
if(str[i+1] == '='){
break;
}
decodeStr[k++] = (ascill[str[i]] << 4) | (ascill[str[++i]] >> 2);
if(str[i+1] == '='){
break;
}
decodeStr[k++] = (ascill[str[i]] << 6) | (ascill[str[++i]]);
}
decodeStr[k] = '\0';
*in = decodeStr;
}

最后sub_1858还要^0x25

1
2
3
4
5
6
7
8
unsigned __int64 __fastcall sub_1858(__int64 a1, unsigned __int64 a2, __int64 a3){
for ( i = 0LL; ; ++i ){
result = i;
if ( i >= a2 ) break;
*(_BYTE *)(a3 + i) = *(_BYTE *)(a1 + i) ^ 0x25;
}
return result;
}

获取到正确的日期———> md5加密后拼接.fluxfingers.net————>后端服务器域名解析sub_55E622E018A4(dest)并返回正确的响应内容————>传统base64解密———–>简单的逐位异或————–>得到flag

那么这个时间应该是多少呢,题目是玛雅社会,图片下面有个2012!关于玛雅社会最著名的莫过于玛雅文明的2012年12月21日的世界末日预言了

运行得flag即可。。

这题有点像misc+逆向,其实看懂那几个dns函数才是关键。

flag:flag{e3a03c6f3fe91b40eaa8e71b41f0db12}