收获

  • 熟悉伪代码中的 Base64 和 RC4,以及快速编写脚本

  • 识别伪代码中的 strlen() 函数


【攻防世界】ereere


思路

根据 Strings 页面定位到主函数 sub_400BC8()

攻防世界-ereere1.png

得到主函数内容:

攻防世界-ereere2.png

v3 是用户的输入,大概率就是 flag,v3 首先经过了函数 sub_41A6E0(v3) 的处理,跟进

得到 sub_41A6E0() 的内容:

攻防世界-ereere3.png

结合中间一个循环的特点:

while ( 1 )
    {
LABEL_7:
      if ( ((*(_DWORD *)a1 - 16843009) & ~*(_DWORD *)a1 & 0x80808080) != 0 )
      {
        if ( !*a1 )
          return (char *)(a1 - v1);
        if ( !a1[1] )
          return (char *)(a1 - v1 + 1);
        if ( !a1[2] )
          return (char *)(a1 - v1 + 2);
        if ( !a1[3] )
          return (char *)(a1 - v1 + 3);
      }
      a1 += 4;
    }

这个函数的作用应该是计算字符串的长度,即 strlen()

然后函数 sub_4009DC() 对 v3 进行了处理,继续跟进:

攻防世界-ereere4.png

在函数最开始,首先调用了 sub_400864(),跟进:

攻防世界-ereere5.png

可以看到两个 256 的 for 循环(十六进制的 0x100 就是十进制的 256
并且第一个 for 循环仅赋值,第二个 for 循环有 swap 操作
再结合 sub_4009DC() 后面部分的一个 for 循环、余 256、一个 swap 操作和一个异或操作

可以明显得知这是 RC4 算法的特征
sub_400864() 做 s 盒的初始化操作,即 rc4_init
sub_4009DC() 做加解密操作,即 rc4_crypt

根据 RC4 算法的特点,可知 byte_4A0860[]s_boxaFlag1233213211[]Key
同时得到 aFlag1233213211[] 的内容:flag{123321321123badbeef012}

攻防世界-ereere6.png

回到主函数 sub_400BC8() 中,在 RC4 算法之后,函数 sub_400550() 又对 v3 做了处理,跟进:

攻防世界-ereere7.png

发现多次对数组 aZyxwvutsrqponm[] 的索引操作,且 aZyxwvutsrqponm[] 的内容:

攻防世界-ereere8.png

ZYXWVUTSRQPONMLKJIHGFEDCBAabcdefghijklmnopqrstuvwxyz/+9876543210,神似 Base64 的密码表
再结合每次赋值的偏移操作,如:*(_BYTE *)(v13 + v3)
以及 if 判断语句中:

if ( i < 2 )
    {
      *(_BYTE *)(v13 + v11) = aZyxwvutsrqponm[(16 * *v8) & 0x30];
      *(_BYTE *)(v13 + v11 + 1) = 61;
      v6 = v11 + 2;
      v10 = v11 + 3;
      *(_BYTE *)(v13 + v6) = 61;
      break;
    }

i < 2 的条件下,存在两次赋值 ‘=’ 的操作 (61 是 ‘=’ 的 ASCii 码)
这些都是 Base64 加密的特点,可以推知函数 sub_400550() 是一个更换了原始码表的 Base64 算法

也就是说,本题是将 flag 进行 RC4 加密后,再进行更换码表的 Base64 加密,最终加密结果为:
ScDZC1cNDZaxnh/2eW1UdqaCiJ0ijRIExlvVEgP43rpxoxbYePBhpwHDPJ==

先进行更换码表的 Base64 解密,再进行 RC4 解密,即可得到 flag


脚本

Python(引用库)

import base64
from Crypto.Cipher import ARC4

key = "ScDZC1cNDZaxnh/2eW1UdqaCiJ0ijRIExlvVEgP43rpxoxbYePBhpwHDPJ=="
string1 = "ZYXWVUTSRQPONMLKJIHGFEDCBAabcdefghijklmnopqrstuvwxyz/+9876543210"  # string1表示更换后的码表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"  # string2表示原始码表
Str = base64.b64decode(key.translate(str.maketrans(string1, string2)))  # Base64解密,bytes型

aFlag1233213211 = "flag{123321321123badbeef012}"
flag = ARC4.new(bytes(aFlag1233213211, encoding='utf-8')).decrypt(Str)
print(flag)

Python(完整实现)

import base64

flag = ""
key = "ScDZC1cNDZaxnh/2eW1UdqaCiJ0ijRIExlvVEgP43rpxoxbYePBhpwHDPJ=="
string1 = "ZYXWVUTSRQPONMLKJIHGFEDCBAabcdefghijklmnopqrstuvwxyz/+9876543210"  # string1表示更换后的码表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"  # string2表示原始码表
print("Base64还原: ", key.translate(str.maketrans(string1, string2)))   # 将 key 还原成初始码表加密后的结果
Str = base64.b64decode(key.translate(str.maketrans(string1, string2)))  # Base64解密,bytes型
print("Base64解密: ", Str)

byte_4A0860 = []
aFlag1233213211 = "flag{123321321123badbeef012}"

# rc4_init
for i in range(256):
    byte_4A0860.append(i)
v4 = 0
v3 = 0
for j in range(256):
    v5 = byte_4A0860[j]
    v3 = (v5 + v3 + ord(aFlag1233213211[int(j % len(aFlag1233213211))])) & 0xff
    byte_4A0860[j] = byte_4A0860[v3]
    byte_4A0860[v3] = v5
    v4 = v4 + 1
    if v4 >= len(aFlag1233213211):
        v4 = 0

print("s_box:", end=" ")
for j in range(256):
    print(byte_4A0860[j], end=" ")
print()

# rc4_crypt
v4 = 0
v3 = 0
for k in range(len(Str)):
    v3 = (v3 + 1) & 0xff
    v4 = (byte_4A0860[v3] + v4) & 0xff
    v5 = byte_4A0860[v3]
    byte_4A0860[v3] = byte_4A0860[v4]
    byte_4A0860[v4] = v5
    flag += chr(Str[k] ^ byte_4A0860[(byte_4A0860[v3] + byte_4A0860[v4]) & 0xff])

print(flag)

结果

flag{RC_f0ur_And_Base_s1xty_f0ur_Encrypt_!}

Python(引用库)

攻防世界-ereere9.png

Python(完整实现)

攻防世界-ereere10.png