测试文件:https://adworld.xctf.org.cn/media/task/attachments/17574fc423474b93a0e6e6a6e583e003.zip
我们直接将Linux当前日期设置为2012-12-21,运行文件就能得到flag,不过还是要分析一下。
1.准备
获取信息
- 64位文件
2.IDA打开
主函数main
signed __int64 __fastcall main(__int64 a1, char **a2, char **a3) { size_t v3; // rbx size_t v4; // rax unsigned __int64 v6; // rax unsigned __int64 v7; // rax unsigned __int64 v8; // rsi char *v9; // rdi time_t timer; // [rsp+18h] [rbp-128h] char v11[8]; // [rsp+20h] [rbp-120h] char src; // [rsp+40h] [rbp-100h] char s; // [rsp+60h] [rbp-E0h] unsigned __int64 v14; // [rsp+C8h] [rbp-78h] char v15; // [rsp+D4h] [rbp-6Ch] char v16; // [rsp+DDh] [rbp-63h] char v17; // [rsp+E6h] [rbp-5Ah] char v18; // [rsp+EFh] [rbp-51h] char *v19; // [rsp+F8h] [rbp-48h] char *v20; // [rsp+100h] [rbp-40h] char *v21; // [rsp+108h] [rbp-38h] char *dest; // [rsp+110h] [rbp-30h] int *v23; // [rsp+118h] [rbp-28h] size_t v24; // [rsp+120h] [rbp-20h] struct tm *tp; // [rsp+128h] [rbp-18h] strcpy(v11, ".fluxfingers.net"); timer = time(0LL); tp = localtime(&timer); strftime(&s, 99uLL, "%Y-%m-%d", tp); // 将现在的日期放入s v24 = strlen(&s); // v24=99 sub_B5A(&s, v24); // 将日期s进行MD5加密 v23 = &dword_2030B8; // v23为加密后的日期的一部分 snprintf( &v18, 9uLL, "%02x%02x%02x%02x", (unsigned __int8)dword_2030B8, BYTE1(dword_2030B8), BYTE2(dword_2030B8), HIBYTE(dword_2030B8)); v23 = &dword_2030C0; snprintf( &v17, 9uLL, "%02x%02x%02x%02x", (unsigned __int8)dword_2030C0, BYTE1(dword_2030C0), BYTE2(dword_2030C0), HIBYTE(dword_2030C0)); v23 = &dword_2030B4; snprintf( &v16, 9uLL, "%02x%02x%02x%02x", (unsigned __int8)dword_2030B4, BYTE1(dword_2030B4), BYTE2(dword_2030B4), HIBYTE(dword_2030B4)); v23 = &dword_2030BC; snprintf( &v15, 9uLL, "%02x%02x%02x%02x", (unsigned __int8)dword_2030BC, BYTE1(dword_2030BC), BYTE2(dword_2030BC), HIBYTE(dword_2030BC)); snprintf(&src, 33uLL, "%s%s%s%s", &v18, &v17, &v16, &v15);// src为加密后的日期 v3 = strlen(&src); // v3=33 v4 = strlen(v11); // v4=16 dest = (char *)malloc(v3 + v4 + 1); if ( !dest ) return 1LL; *dest = 0; strcat(dest, &src); strcat(dest, v11); // dest为MD5(s)+".fluxfingers.net" v21 = sub_18A4(dest); if ( !v21 ) return 1LL; v6 = strlen(v21); v20 = sub_15E0((__int64)v21, v6, &v14); // base64解密 v7 = strlen(v21); v19 = sub_15E0((__int64)v21, v7, &v14); if ( !v20 ) return 1LL; v8 = v14; v9 = v20; sub_1858((__int64)v20, v14, (__int64)v19); // 异或0x25 ((void (__fastcall *)(char *, unsigned __int64))v19)(v9, v8); return 0LL; }
3.代码分析
3.1 MD5加密
首先,程序将获取到的时间进行了MD5码加密
for ( i = 8 * a2 + 1; i % 512 != 448; ++i ) ; v2 = i; i /= 8; dest = calloc(v2 / 8 + 64, 1uLL); memcpy(dest, a1, a2); // 将a1中的值存入dest中 *((_BYTE *)dest + a2) = -128; *(_DWORD *)((char *)dest + i) = 8 * a2; for ( j = 0; j < i; j += 64 ) { v132 = (char *)dest + j; v140 = dword_2030B8; v139 = dword_2030C0; v138 = dword_2030B4; v137 = dword_2030BC; for ( k = 0; k <= 0x3F; ++k ) // MD5码加密 { if ( k > 0xF ) { if ( k > 0x1F ) { if ( k > 0x2F ) { v135 = v138 ^ (v139 | ~v137); v134 = 7 * (_BYTE)k & 0xF; } else { v135 = v137 ^ v138 ^ v139; v134 = (3 * (_BYTE)k + 5) & 0xF; } } else { v135 = v139 & v137 | v138 & ~v137; v134 = (5 * (_BYTE)k + 1) & 0xF; } } else { v135 = v138 & v139 | v137 & ~v139; v134 = k; } v131 = v137; v137 = v138; v138 = v139; v139 += __ROL4__(*(_DWORD *)&v132[4 * v134] + *(&v3 + k) + v135 + v140, *(&v67 + k)); v140 = v131; } dword_2030B8 += v140; dword_2030C0 += v139; dword_2030B4 += v138; dword_2030BC += v137; } free(dest); }
3.2 连接字符串
将加密后的时间与“.fluxfingers.net”结合
snprintf(&src, 33uLL, "%s%s%s%s", &v18, &v17, &v16, &v15);// src为加密后的日期 v3 = strlen(&src); // v3=33 v4 = strlen(v11); // v4=16 dest = (char *)malloc(v3 + v4 + 1); if ( !dest ) return 1LL; *dest = 0; strcat(dest, &src); strcat(dest, v11); // dest为MD5(s)+".fluxfingers.net"
3.3 传递处理
将得到的字符串传入 v21 = sub_18A4(dest);处理
char *__fastcall sub_18A4(const char *a1) { char *v2; // rax ns_rr v3; // [rsp+10h] [rbp-24A0h] ns_msg v4; // [rsp+430h] [rbp-2080h] char s; // [rsp+480h] [rbp-2030h] u_char v6; // [rsp+1480h] [rbp-1030h] 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; }
3.4 base64解密
再对得到的字符串进行base64解密
v6 = strlen(v21); v20 = sub_15E0((__int64)v21, v6, &v14); // base64解密 v7 = strlen(v21); v19 = sub_15E0((__int64)v21, v7, &v14);
char *__fastcall sub_15E0(__int64 a1, unsigned __int64 a2, _QWORD *a3) { char *v4; // rax char *v5; // rax char *v6; // rax _QWORD *v7; // [rsp+8h] [rbp-158h] char v8; // [rsp+28h] [rbp-138h] unsigned __int8 v9; // [rsp+29h] [rbp-137h] unsigned __int8 v10; // [rsp+2Ah] [rbp-136h] char v11; // [rsp+2Bh] [rbp-135h] char v12[2]; // [rsp+2Ch] [rbp-134h] char v13; // [rsp+2Eh] [rbp-132h] char v14; // [rsp+2Fh] [rbp-131h] char s[61]; // [rsp+30h] [rbp-130h] char v16; // [rsp+6Dh] [rbp-F3h] char v17; // [rsp+13Fh] [rbp-21h] char *v18; // [rsp+140h] [rbp-20h] size_t size; // [rsp+148h] [rbp-18h] unsigned __int64 i; // [rsp+150h] [rbp-10h] char *v21; // [rsp+158h] [rbp-8h] v7 = a3; memset(s, 128, 0x100uLL); for ( i = 0LL; i <= 0x3F; ++i ) s[(unsigned __int8)aAbcdefghijklmn[i]] = i; // base64解密 v16 = 0; size = 0LL; for ( i = 0LL; i < a2; ++i ) { if ( s[*(unsigned __int8 *)(a1 + i)] != -128 ) ++size; } if ( size & 3 ) return 0LL; v18 = (char *)malloc(size); v21 = v18; if ( !v18 ) return 0LL; size = 0LL; for ( i = 0LL; i < a2; ++i ) { v17 = s[*(unsigned __int8 *)(a1 + i)]; if ( v17 != -128 ) { v12[size] = *(_BYTE *)(a1 + i); *(&v8 + size++) = v17; if ( size == 4 ) { v4 = v21++; *v4 = (v9 >> 4) | 4 * v8; v5 = v21++; *v5 = (v10 >> 2) | 16 * v9; v6 = v21++; *v6 = v11 | (v10 << 6); size = 0LL; } } } if ( v21 > v18 ) { if ( v13 == 61 ) { v21 -= 2; } else if ( v14 == 61 ) { --v21; } } *v7 = v21 - v18; return v18; }
.rodata:0000000000001E80 aAbcdefghijklmn db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/%'
3.5 异或操作
最后对解密后的字符串进行异或0x25
unsigned __int64 __fastcall sub_1858(__int64 a1, unsigned __int64 a2, __int64 a3) { unsigned __int64 result; // rax unsigned __int64 i; // [rsp+20h] [rbp-8h] for ( i = 0LL; ; ++i ) { result = i; if ( i >= a2 ) break; *(_BYTE *)(a3 + i) = *(_BYTE *)(a1 + i) ^ 0x25; } return result; }
3.6 总结
实际上就是将获得的日期date进行
base64(sub_18A4(MD5(date)+".fluxfingers.net")).decode() ^ 0x25
因此我们获取到正确时间即可。联系到玛雅社会,最出名的就是玛雅预言,因此我们可以判断这个时间就是2012-12-21
4.get flag!
flag{e3a03c6f3fe91b40eaa8e71b41f0db12}