TypechoJoeTheme

霍雅的博客

登录
用户名
密码
/
注册
用户名
邮箱

2024网鼎杯青龙组RE2 reverse wp(Write-up)

2024-12-11
/
0 评论
/
162 阅读
/
正在检测是否收录...
12/11

打开是four无后缀文件,13KB
用查壳工具打开,发现是64位ELF文件GCC编译无壳

打开IDA64位shift+F12打开字符串窗口,发现几个特殊字符和一个wdflag{以及一个correct FLAG!

可以看到main函数,里面包含一个wdflag{和correct Flag!,可以看出来这是程序入口,同时还有个base64_table的字符串,后面会用到。

双击进主函数F2看伪代码,可以看到四种加密方式第一种是数组乘积算法,第二种是亦或,第三种是base64,第四种是AES,对应提示的四大护法。

第一种加密,实际上就是一个乘2算法,所以将下列数组除2可得前八位为0170b39c,加上我们一开始就看到的wdflag{可得flag的前几位为wdflag{0170b39c

memcpy(dest, v51, 0x20uLL);
    v49 = 0;
    s2 = 96;
    v38 = 98;
    v39 = 110;
    v40 = 96;
    v41 = -60;
    v42 = 102;
    v43 = 114;
    v44 = -58;
    for ( i = 0; i <= 7; ++i )
      s1[i] = 2 * dest[i];
96  =>  0x60  | 0x60 / 2 = 0x30 = 48 (ASCII '0')
98  =>  0x62  | 0x62 / 2 = 0x31 = 49 (ASCII '1')
110 =>  0x6E  | 0x6E / 2 = 0x37 = 55 (ASCII '7')
96  =>  0x60  | 0x60 / 2 = 0x30 = 48 (ASCII '0')
-60 =>  0xC4  | 0xC4 / 2 = 0x62 = 98  (ASCII 'b')
102 =>  0x66  | 0x66 / 2 = 0x33 = 51 (ASCII '3')
114 =>  0x72  | 0x72 / 2 = 0x39 = 57 (ASCII '9')
-58 =>  0xC6  | 0xC6 / 2 = 0x63 = 99  (ASCII 'c')

第二部分如下代码,是一个异或算法
XorrLord的ascii值为:
X = 88, o = 111, r = 114, r = 114, L = 76, o = 111, r = 114, d = 100
和变量v28-v35亦或可得5ed24c63,结合上面的结果可得flag前几位为wdflag{0170b39c5ed24c63

  if ( !memcmp(s1, &s2, 8uLL) )
    {
      v54 = (__int64)"XorrLord";
      v28 = 109;
      v29 = 10;
      v30 = 22;
      v31 = 64;
      v32 = 120;
      v33 = 12;
      v34 = 68;
      v35 = 87;
109 ^ 88 = 53  =>  '5'
10  ^ 111 = 101 => 'e'
22  ^ 114 = 100 => 'd'
64  ^ 114 = 50  => '2'
120 ^ 76  = 52  => '4'
12  ^ 111 = 99  => 'c'
68  ^ 114 = 54  => '6'
87  ^ 100 = 51  => '3'

第三个算法是一个base64的魔改表,魔改表也就是我们一开始寻找到的特殊字符,符合base64表的特征,同时名字也有base64,进去查看base64_encode这个函数,内容也和推断一样

但是这个魔改表有个坑,他是63位,所以我们要补一个C,完整表如下DEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/
(其实他就在base64_table后面有个43H,这个就是C,我没注意到)

base64_encode((__int64)&v17, 8uLL, (__int64)v10);
  v21 = "BYOzAjWyAVA";
  if ( strcmp(v10, "BYOzAjWyAVA") )
    return 1;

查看这个函数在main函数里的调用,加密的密文可以看出来就是BYOzAjWyAVA通过编写脚本可得
结果为ec3b52a6,加上我们前面解出来的flag可得flag前几位为:wdflag{0170b39c5ed24c63ec3b52a6

import base64

# 修正版的魔改 Base64 表(补全了缺失的 C)
mod_base64_table = 'CDEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/'
# 标准的 Base64 表
std_base64_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

# 1. 确保长度一致
if len(mod_base64_table) != 64 or len(std_base64_table) != 64:
    raise ValueError(f"Base64 表的长度不一致:魔改表({len(mod_base64_table)}),标准表({len(std_base64_table)})")

# 2. 生成转换映射
decode_map = str.maketrans(mod_base64_table, std_base64_table)


def decode_mod_base64(mod_encoded):
    """将魔改 Base64 转为标准 Base64 并解码"""
    # 1. 将魔改的 Base64 字符串转成标准 Base64
    std_encoded = mod_encoded.translate(decode_map)
    print(f"魔改的 Base64: {mod_encoded} => 标准 Base64: {std_encoded}")

    # 2. 补充填充符 '=',确保字符串长度为 4 的倍数
    padding_needed = len(std_encoded) % 4
    if padding_needed:
        std_encoded += '=' * (4 - padding_needed)

    # 3. 解码标准 Base64
    decoded_bytes = base64.b64decode(std_encoded)
    return decoded_bytes.decode('utf-8', errors='ignore')  # 忽略解码错误


mod_base64_string = 'BYOzAjWyAVA'
decoded_text = decode_mod_base64(mod_base64_string)
print(f"解码结果: {decoded_text}")

最后一种加密是AES加密,密文为V4数组,秘钥为AesMasterAesMast,详细代码分析让ai来,这里就不继续分析了,有经验的师父应该一眼能看出来

qmemcpy(v9, "AesMasterAesMast", sizeof(v9));
  v8[0] = 0LL;
  v8[1] = 0LL;
  memcpy(v8, v18, 8uLL);
  for ( k = 8; k <= 15; ++k )
    *((_BYTE *)v8 + k) = 8;
  AES_set_encrypt_key(v9, 128LL, v6);
  AES_encrypt(v8, v7, v6);
  hex_to_string(v7, 16LL, v5);
  v4[0] = -10;
  v4[1] = -85;
  v4[2] = 71;
  v4[3] = -66;
  v4[4] = 113;
  v4[5] = -28;
  v4[6] = 1;
  v4[7] = -36;
  v4[8] = 3;
  v4[9] = 48;
  v4[10] = -97;
  v4[11] = -15;
  v4[12] = 67;
  v4[13] = -15;
  v4[14] = -45;
  v4[15] = 102;
  if ( memcmp(v7, v4, 0x10uLL) )
    return 1;
  puts("Correct Flag!");
  return 0;
}

先将数组的内容转换成16进制,然后exp如下,结果为724ba7d5

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad


# 提供的数据 v4
v4 = bytes([0xF6, 0xAB, 0x47, 0xBE, 0x71, 0xE4, 0x01, 0xDC, 0x03, 0x30, 0x9F, 0xF1, 0x43, 0xF1, 0xD3, 0x66])

# 使用"AesMasterAesMast"作为密钥,编码为字节
key = "AesMasterAesMast".encode()

# 初始化AES解密器,选择ECB模式
cipher = AES.new(key, AES.MODE_ECB)

# 解密数据
decrypted_data = cipher.decrypt(v4)

# 去除填充
try:
    unpadded_data = unpad(decrypted_data, AES.block_size)
    # 输出解密后的数据,假设是ASCII字符串
    print("Decrypted data:", unpadded_data.decode('utf-8', errors='ignore'))
except ValueError as e:
    print(f"Padding error or decryption issue: {e}")

最后结果wdflag{0170b39c5ed24c63ec3b52a6724ba7d5}
完整伪代码如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax@6
  char v4; // [sp+0h] [bp-240h]@22
  char v5; // [sp+1h] [bp-23Fh]@22
  char v6; // [sp+2h] [bp-23Eh]@22
  char v7; // [sp+3h] [bp-23Dh]@22
  char v8; // [sp+4h] [bp-23Ch]@22
  char v9; // [sp+5h] [bp-23Bh]@22
  char v10; // [sp+6h] [bp-23Ah]@22
  char v11; // [sp+7h] [bp-239h]@22
  char v12; // [sp+8h] [bp-238h]@22
  char v13; // [sp+9h] [bp-237h]@22
  char v14; // [sp+Ah] [bp-236h]@22
  char v15; // [sp+Bh] [bp-235h]@22
  char v16; // [sp+Ch] [bp-234h]@22
  char v17; // [sp+Dh] [bp-233h]@22
  char v18; // [sp+Eh] [bp-232h]@22
  char v19; // [sp+Fh] [bp-231h]@22
  char v20; // [sp+10h] [bp-230h]@22
  char v21; // [sp+40h] [bp-200h]@22
  char v22; // [sp+140h] [bp-100h]@22
  __int64 v23; // [sp+150h] [bp-F0h]@19
  __int64 v24; // [sp+158h] [bp-E8h]@19
  __int64 v25; // [sp+160h] [bp-E0h]@19
  __int64 v26; // [sp+168h] [bp-D8h]@19
  char v27; // [sp+170h] [bp-D0h]@17
  char v28; // [sp+180h] [bp-C0h]@12
  char v29; // [sp+181h] [bp-BFh]@12
  char v30; // [sp+182h] [bp-BEh]@12
  char v31; // [sp+183h] [bp-BDh]@12
  char v32; // [sp+184h] [bp-BCh]@12
  char v33; // [sp+185h] [bp-BBh]@12
  char v34; // [sp+186h] [bp-BAh]@12
  char v35; // [sp+187h] [bp-B9h]@12
  char v36[16]; // [sp+190h] [bp-B0h]@13
  char s2; // [sp+1A0h] [bp-A0h]@7
  char v38; // [sp+1A1h] [bp-9Fh]@7
  char v39; // [sp+1A2h] [bp-9Eh]@7
  char v40; // [sp+1A3h] [bp-9Dh]@7
  char v41; // [sp+1A4h] [bp-9Ch]@7
  char v42; // [sp+1A5h] [bp-9Bh]@7
  char v43; // [sp+1A6h] [bp-9Ah]@7
  char v44; // [sp+1A7h] [bp-99h]@7
  char s1[16]; // [sp+1B0h] [bp-90h]@8
  char dest[32]; // [sp+1C0h] [bp-80h]@7
  char v47[32]; // [sp+1D0h] [bp-70h]@17
  char v48[32]; // [sp+1D8h] [bp-68h]@19
  char v49; // [sp+1E0h] [bp-60h]@7
  char s[39]; // [sp+1F0h] [bp-50h]@1
  char v51[39]; // [sp+1F7h] [bp-49h]@7
  char v52; // [sp+217h] [bp-29h]@5
  char *v53; // [sp+220h] [bp-20h]@17
  __int64 v54; // [sp+228h] [bp-18h]@12
  int k; // [sp+234h] [bp-Ch]@19
  int j; // [sp+238h] [bp-8h]@12
  int i; // [sp+23Ch] [bp-4h]@7

  printf("Enter the flag:", argv, envp);
  if ( fgets(s, 41, stdin) )
    s[strcspn(s, "\n")] = 0;
  if ( strlen(s) == 40 && !strncmp(s, "wdflag{", 7uLL) && v52 == 125 )
  {
    memcpy(dest, v51, 0x20uLL);
    v49 = 0;
    s2 = 96;
    v38 = 98;
    v39 = 110;
    v40 = 96;
    v41 = -60;
    v42 = 102;
    v43 = 114;
    v44 = -58;
    for ( i = 0; i <= 7; ++i )
      s1[i] = 2 * dest[i];
    if ( !memcmp(s1, &s2, 8uLL) )
    {
      v54 = (__int64)"XorrLord";
      v28 = 109;
      v29 = 10;
      v30 = 22;
      v31 = 64;
      v32 = 120;
      v33 = 12;
      v34 = 68;
      v35 = 87;
      for ( j = 8; j <= 15; ++j )
        v36[j - 8] = dest[j] ^ *(_BYTE *)(j - 8LL + v54);
      if ( !memcmp(v36, &v28, 8uLL) )
      {
        base64_encode(v47, 8LL, &v27);
        v53 = "BYOzAjWyAVA";
        if ( !strcmp(&v27, "BYOzAjWyAVA") )
        {
          v25 = 7310594956877587777LL;
          v26 = 8391157515997757810LL;
          v23 = 0LL;
          v24 = 0LL;
          memcpy(&v23, v48, 8uLL);
          for ( k = 8; k <= 15; ++k )
            *((_BYTE *)&v23 + k) = 8;
          AES_set_encrypt_key(&v25, 128LL, &v21);
          AES_encrypt(&v23, &v22, &v21);
          hex_to_string(&v22, 16LL, &v20);
          v4 = -10;
          v5 = -85;
          v6 = 71;
          v7 = -66;
          v8 = 113;
          v9 = -28;
          v10 = 1;
          v11 = -36;
          v12 = 3;
          v13 = 48;
          v14 = -97;
          v15 = -15;
          v16 = 67;
          v17 = -15;
          v18 = -45;
          v19 = 102;
          if ( !memcmp(&v22, &v4, 0x10uLL) )
          {
            puts("Correct Flag!");
            result = 0;
          }
          else
          {
            result = 1;
          }
        }
        else
        {
          result = 1;
        }
      }
      else
      {
        result = 1;
      }
    }
    else
    {
      result = 1;
    }
  }
  else
  {
    result = 1;
  }
  return result;
}

base64伪代码如下

_BYTE *__fastcall base64_encode(__int64 a1, unsigned __int64 a2, __int64 a3)
{
  int v3; // eax
  int v4; // eax
  int v5; // eax
  int v6; // eax
  int v7; // eax
  int v8; // eax
  _BYTE *result; // rax
  unsigned __int64 v10; // [rsp+8h] [rbp-30h]
  unsigned int v11; // [rsp+20h] [rbp-18h]
  int v12; // [rsp+28h] [rbp-10h]
  int v13; // [rsp+2Ch] [rbp-Ch]
  int v14; // [rsp+30h] [rbp-8h]
  int v15; // [rsp+34h] [rbp-4h]

  v10 = a2;
  v15 = 0;
  v14 = 0;
  while ( v15 < a2 )
  {
    v3 = v15++;
    v13 = *(unsigned __int8 *)(v3 + a1);
    if ( v15 >= a2 )
    {
      v5 = 0;
    }
    else
    {
      v4 = v15++;
      v5 = *(unsigned __int8 *)(v4 + a1);
    }
    v12 = v5;
    if ( v15 >= a2 )
    {
      v7 = 0;
    }
    else
    {
      v6 = v15++;
      v7 = *(unsigned __int8 *)(v6 + a1);
    }
    v11 = (v12 << 8) + (v13 << 16) + v7;
    *(_BYTE *)(a3 + v14) = base64_table[(v11 >> 18) & 0x3F];
    *(_BYTE *)(a3 + v14 + 1) = base64_table[(v11 >> 12) & 0x3F];
    *(_BYTE *)(a3 + v14 + 2) = base64_table[(v11 >> 6) & 0x3F];
    v8 = v14 + 3;
    v14 += 4;
    *(_BYTE *)(a3 + v8) = base64_table[v11 & 0x3F];
  }
  while ( v10 % 3 )
  {
    *(_BYTE *)(--v14 + a3) = 61;
    ++v10;
  }
  result = (_BYTE *)(v14 + a3);
  *result = 0;
  return result;
}
朗读
赞(1)
版权属于:

霍雅的博客

本文链接:

https://huoya.work/bk/index.php/archives/93/(转载时请注明本文出处及文章链接)

评论 (0)

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月