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

64位无壳,zip下的其它文件浏览一遍,没发现什么线索,先看IDA

__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

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

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应该是最重要的部分

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解密

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

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}