TSCTF-J 2024 部分题目复现(未完结)

TSCTF-J 2024 部分题目复现(未完结)

iPlayBingo:

F12拿到answerCheck.wasm文件,同时观察js代码找到关键函数Check()

利用Wabt将answerCheck.wasm文件转为answerCheck.c和answerCheck.h文件,但此时可读性依然较差。用gcc链接成answerCheck.o文件,此时可以使用IDA反汇编。

image-20240926162017690

​ 关键的函数w2c_answerChecker_check_0()

__int64 __fastcall w2c_answerChecker_check_0(
        unsigned int *a1,
        int a2,
        unsigned __int64 a3,
        unsigned __int64 a4,
        unsigned __int64 a5,
        __int64 a6,
        __int64 a7,
        __int64 a8,
        __int64 a9,
        __int64 a10)
{
  _DWORD *address; // rax
  int v11; // eax
  int v12; // eax
  _DWORD *v13; // rax
  unsigned int v15; // [rsp+4Ch] [rbp-34h]
  unsigned int v16; // [rsp+4Ch] [rbp-34h]
  int v17; // [rsp+58h] [rbp-28h]
  int v18; // [rsp+58h] [rbp-28h]
  unsigned int v19; // [rsp+5Ch] [rbp-24h]
  unsigned int v20; // [rsp+60h] [rbp-20h]
  unsigned int v21; // [rsp+64h] [rbp-1Ch]
  bool v22; // [rsp+64h] [rbp-1Ch]
  bool v23; // [rsp+64h] [rbp-1Ch]
  bool v24; // [rsp+64h] [rbp-1Ch]
  bool v25; // [rsp+64h] [rbp-1Ch]
  bool v26; // [rsp+64h] [rbp-1Ch]
  bool v27; // [rsp+64h] [rbp-1Ch]
  unsigned __int8 v28; // [rsp+64h] [rbp-1Ch]
  int v29; // [rsp+68h] [rbp-18h]
  int v30; // [rsp+6Ch] [rbp-14h]
  int v31; // [rsp+70h] [rbp-10h]
  unsigned int v32; // [rsp+70h] [rbp-10h]
  unsigned int v33; // [rsp+74h] [rbp-Ch]
  int v34; // [rsp+74h] [rbp-Ch]
  int v35; // [rsp+74h] [rbp-Ch]
  int v36; // [rsp+74h] [rbp-Ch]
  int v37; // [rsp+78h] [rbp-8h]
  unsigned int v38; // [rsp+78h] [rbp-8h]
  unsigned int v39; // [rsp+78h] [rbp-8h]
  int i; // [rsp+78h] [rbp-8h]
  unsigned int v41; // [rsp+7Ch] [rbp-4h]
  unsigned int v42; // [rsp+7Ch] [rbp-4h]
  unsigned int v43; // [rsp+7Ch] [rbp-4h]
  unsigned int v46; // [rsp+98h] [rbp+18h]
  unsigned int v47; // [rsp+98h] [rbp+18h]
  int v48; // [rsp+98h] [rbp+18h]

  v29 = 0;
  address = (_DWORD *)_emutls_get_address(refptr___emutls_v_wasm_rt_call_stack_depth);
  if ( ++*address > 0x1F4u )
    wasm_rt_trap(9i64);
  v20 = *a1 - 112;
  *a1 = v20;
  i32_store8(a1 + 2, v20 + 96i64, 0i64);
  i64_store(a1 + 2, v20 + 88i64, a10);
  i64_store(a1 + 2, v20 + 80i64, a9);
  i64_store(a1 + 2, v20 + 72i64, a8);
  i64_store(a1 + 2, v20 + 64i64, a7);
  i64_store(a1 + 2, v20 + 48i64, a5);
  i64_store(a1 + 2, v20 + 40i64, a4);
  i64_store(a1 + 2, v20 + 32i64, a3);
  i64_store(a1 + 2, v20 + 56i64, a6);
  v41 = 1;
  switch ( a2 )
  {
    case 7:
      goto LABEL_27;
    case 12:
      v41 = 0;
      v46 = v20 + 32;
      if ( ((v20 + 32) & 3) == 0 )
        goto LABEL_9;
      v21 = 0;
      if ( (unsigned int)i32_load8_u(a1 + 2, v46) )
      {
        while ( (++v46 & 3) != 0 )
        {
          if ( !(unsigned int)i32_load8_u(a1 + 2, v46) )
            goto LABEL_11;
        }
        do
        {
LABEL_9:
          v33 = v46;
          v46 += 4;
          v37 = i32_load(a1 + 2, v33);
        }
        while ( ((v37 | (16843008 - v37)) & 0x80808080) == -2139062144 );
        do
          v46 = v33++;
        while ( (unsigned int)i32_load8_u(a1 + 2, v46) );
LABEL_11:
        v21 = v46 - (v20 + 32);
      }
      if ( v21 == 32 )
      {
        v17 = i32_load8_s(a1 + 2, v20 + 63i64);
        v15 = (unsigned int)i32_load8_s(a1 + 2, v20 + 61i64) << 16;
        v16 = ((unsigned int)i32_load8_u(a1 + 2, v20 + 60i64) << 24) | v15;
        v11 = i32_load8_s(a1 + 2, v20 + 62i64);
        i32_store(a1 + 2, v20 + 28i64, (v11 << 8) | v16 | v17);
        i32_store(
          a1 + 2,
          v20 + 16i64,
          ((int)a5 >> 24) | (__int16)((int)a5 >> 8) & 0xFFFFFF00 | ((_DWORD)a5 << 24) | ((__int16)a5 << 8) & 0xFFFF0000);
        i32_store(
          a1 + 2,
          v20 + 8i64,
          ((int)a4 >> 24) | (__int16)((int)a4 >> 8) & 0xFFFFFF00 | ((_DWORD)a4 << 24) | ((__int16)a4 << 8) & 0xFFFF0000);
        i32_store(
          a1 + 2,
          v20,
          ((int)a3 >> 24) | (__int16)((int)a3 >> 8) & 0xFFFFFF00 | ((_DWORD)a3 << 24) | ((__int16)a3 << 8) & 0xFFFF0000);
        v18 = i32_load8_s(a1 + 2, v20 + 59i64);
        v12 = i32_load8_s(a1 + 2, v20 + 58i64);
        i32_store(a1 + 2, v20 + 24i64, (v12 << 8) | ((_DWORD)a6 << 24) | ((__int16)a6 << 8) & 0xFFFF0000 | v18);
        i32_store(
          a1 + 2,
          v20 + 20i64,
          (SHIDWORD(a5) >> 24) | (a5 >> 8) & 0xFF000000 | ((int)(a5 >> 16) >> 8) & 0xFFFF0000 | ((int)(a5 >> 24) >> 16) & 0xFFFFFF00);
        i32_store(
          a1 + 2,
          v20 + 12i64,
          (SHIDWORD(a4) >> 24) | (a4 >> 8) & 0xFF000000 | ((int)(a4 >> 16) >> 8) & 0xFFFF0000 | ((int)(a4 >> 24) >> 16) & 0xFFFFFF00);
        i32_store(
          a1 + 2,
          v20 + 4i64,
          (SHIDWORD(a3) >> 24) | (a3 >> 8) & 0xFF000000 | ((int)(a3 >> 16) >> 8) & 0xFFFF0000 | ((int)(a3 >> 24) >> 16) & 0xFFFFFF00);
        do  //XXTEA_encode
        {
          v19 = 8 * v29 + v20;
          v47 = i32_load(a1 + 2, v19);
          v42 = i32_load(a1 + 2, v19 + 4i64);
          v34 = 31;
          v38 = 0;
          do
          {
            v38 -= 1640531527;
            v47 += (((v42 >> 3) ^ (32 * v42)) + ((v42 >> 4) ^ (4 * v42))) ^ ((v38 ^ v42)
                                                                           + (v42 ^ i32_load(
                                                                                      a1 + 2,
                                                                                      4 * ((v38 >> 2) & 3) + 1424)));
            v42 += ((v38 ^ v47) + (i32_load(a1 + 2, 4 * ((v38 >> 2) & 3 ^ 1) + 1424) ^ v47)) ^ (((v47 >> 3) ^ (32 * v47))
                                                                                              + ((v47 >> 4) ^ (4 * v47)));
            v31 = v34--;
            v30 = 0;
          }
          while ( v31 );
          v35 = 0;
          v39 = 0;
          do //XTEA_encode
          {
            v47 += (v42 + ((v42 >> 5) ^ (16 * v42))) ^ (v39 + i32_load(a1 + 2, 4 * (v39 & 3) + 1424));
            v39 -= 1640531527;
            v42 += (v39 + i32_load(a1 + 2, ((v39 >> 9) & 0xC) + 1424)) ^ (v47 + ((v47 >> 5) ^ (16 * v47)));
            ++v35;
          }
          while ( v35 != 33 );
          for ( i = 0; i != 32; ++i ) //TEA_Encode
          {
            v30 -= 1183238242;
            v47 += (16 * v42 + 19088743) ^ ((v42 >> 5) - 1985229329) ^ (v42 + v30);//密钥
            v42 += ((v47 >> 5) - 1161903906) ^ (v30 + v47) ^ (16 * v47 - 559038737);
          }
          i32_store(a1 + 2, v19 + 4i64, v42);
          i32_store(a1 + 2, v19, v47);
          ++v29;
        }
        while ( v29 != 4 );//密文
        v22 = (unsigned int)i32_load(a1 + 2, v20) == 1569711840;
        v23 = (unsigned int)i32_load(a1 + 2, v20 + 4i64) == -1153260111 && v22;
        v24 = (unsigned int)i32_load(a1 + 2, v20 + 8i64) == -92922495 && v23;
        v25 = (unsigned int)i32_load(a1 + 2, v20 + 12i64) == 852271051 && v24;
        v26 = (unsigned int)i32_load(a1 + 2, v20 + 16i64) == -40115131 && v25;
        v27 = (unsigned int)i32_load(a1 + 2, v20 + 20i64) == 37303748 && v26;
        v28 = (unsigned int)i32_load(a1 + 2, v20 + 24i64) == -352841794 && v27;
        v41 = ((unsigned int)i32_load(a1 + 2, v20 + 28i64) == -449956141) & v28;
      }
LABEL_27:
      *a1 = v20 + 112;
      v13 = (_DWORD *)_emutls_get_address(refptr___emutls_v_wasm_rt_call_stack_depth);
      --*v13;
      return v41;
    default:
      v32 = i32_load(a1 + 2, (unsigned int)(4 * a2 + 1312));
      v48 = i32_load8_u(a1 + 2, v32);
      v43 = v20 + 32;
      v36 = i32_load8_u(a1 + 2, v20 + 32);
      if ( v36 && v48 == v36 )
      {
        do
        {
          v48 = i32_load8_u(a1 + 2, v32 + 1i64);
          v36 = i32_load8_u(a1 + 2, v43 + 1i64);
          if ( !v36 )
            break;
          ++v32;
          ++v43;
        }
        while ( v48 == v36 );
      }
      v41 = v48 == v36;
      goto LABEL_27;
  }
}

阅读完这个函数,很清晰的看出来依次使用了XXTEA,XTEA,TEA加密,同时看到一个while循环的检查函数,知道这就是密文。从hint中也可以得知,三个算法共享密钥,而最后的TEA加密清晰的给出了密钥。整理得到:

int enc[] = [ 1569711840, -1153260111, -92922495, 852271051, -40115131, 
37303748, -352841794, -449956141]
 int k[] ={ 19088743, -1985229329, -559038737, -1161903906 }

另外,观察三个加密算法,可以看出部分轮函数、Delta、轮数都被魔改了,所以用网上的解题脚本得稍微修改一下。

解题脚本详见Official_wp

iPlayCal

使用DIE查看

image-20240926164047570

DIE告诉我们这是一个魔改UPX壳,所以upx -d不奏效。

打开x32dbg开始调试

F9运行到pushad部分,单步步过,找到右上角的ESP寄存器,下硬件访问断点

image-20240926164349076

找到OEP,插件dump出来脱壳完毕

IDA点开,易见如下字符串:

image-20240926171040116

Shellcode的本质就是16进制机器码

我们把他全部提取出来,用Base64解码,再把解码出来的16进制转成2进制文件(这样才可以使用IDA分析)

关于怎么转存为二进制文件:Ubuntu指令: echo <十六进制数据> | xxd -r -ps <二进制文件>

注意,使用IDA分析时,选择Binary File 以及metapc模式

image-20240927132445566

看到这里得恶补一下密码学。从flag密文的形式来猜应该是用了某种变换将字符映射过去了。

Official_WP说这叫仿射密码,但没有细讲。所以我详细写一写

image-20240927134645397

仿射密码是一种单表代换的对称密码。明文中所有字母对应成数值,经过加密函数加密成新的数值,再对应到相应的字母,组成密文, 密文和明文一样经过解密函数恢复成明文。

其中乘法逆元比较简单的是用扩展欧几里得算法求解。当然现在网上已经可以找到成熟的在线解密工具

输入密文以及key(a,b)就可以得到flag

(这里建议还是自己逆向算法写脚本,因为涉及大小写的问题)

posted @   凉猹  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示