[CTF] 2022 CNSS Recruit Reverse 复现wp

😇 [Baby] Welcome to Reverse World

IDA打开即是flag.

image

cnss{1t_s3ems_l1ke_Y0u_c4n_us3_IDA_n0w!}

💔 [Baby] Find me

根据提示打开Strings窗口, 已经可以看到第一段和最后一段flag

image

根据提示Learn about Functions and you can see the second part of flag., 在旁边的functions窗口找到第二段flag

image

根据提示Learn about Xref and you can see the third part of flag.Find out which function refer to me!找到第三段flag(右键Xref)

image

把每一段拼接起来即可

cnss{W0w!Y0u_Comp1et3ly_Uns7and_h0w_t0_us3_ID4_N0w!}

💫 [Easy] 回レ! 雪月花

打开ida, 在main里F5, 查看加密逻辑:

image

第一次处理是异或0x11, 点进encode查看第二次处理:

image

这里稍微理解一下, 比如v5, 它的二进制位有8位, 后7位即为a2的前面七位, 第一位即为a1的最后一位, v7异或v6的值正好相反, 与v5的信息组合即可还原出a1和a2. 同样的, 将v6异或v5还原的值, 二进制位后6位为a4的前6位, 前两位为a3的最后两位, 与v8异或v7的值组合, 即可还原出a3和a4.

下面为还原脚本:

def decode(v5, v6, v7, v8):
    a1 = (((v7 ^ v6) & 0b01111111) << 1) + (v5 >> 7)
    a2 = ((v5 & 0b01111111) << 1) + ((v7 ^ v6) >> 7)
    a3 = (((v8 ^ v7) & 0b00111111) << 2) + ((v6 ^ v5) >> 6)
    a4 = (((v6 ^ v5) & 0b00111111) << 2) + ((v8 ^ v7) >> 6)
    return a1, a2, a3, a4


cipher = [63, 143, 163, 188, 141,  39, 122, 103, 226, 3,
          162, 224, 172, 234, 149, 139, 163, 237, 204, 182,
          50, 140, 148,  82, 130, 138,  20, 198, 245, 174,
          104, 115]

for i in range(28, -1, -1):
    cipher[i], cipher[i+1], cipher[i+2], cipher[i+3] = decode(cipher[i], cipher[i+1], cipher[i+2], cipher[i+3])

print(''.join(chr(c ^ 0x11) for c in cipher))

cnss{So_d1zzy...Wh3r3_am_i_N0w?}

👁 [Easy] 邪王真眼

IDA打开可以看到加密:

image

拿到加密后的字符串UR3oWS5E0G03tRibWRrR0cEx

查看encode函数:

image

根据加密特征, 猜测是base64, 查看alpha数组(字符表), 可以发现不是标准的base64表:

image

EXP即进行一个换表解密:

import base64

originString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' # 原索引表
changedString = 'abcd4EFGHij8k0lMNOPqr6stU91VWXyz7+/ABCDefg2hI5JKLmnopQRST3uvwxYZ' # 替换后的索引表
encodedString = 'UR3oWS5E0G03tRibWRrR0cEx' # 加密后的字符串

print(base64.b64decode(encodedString.translate(str.maketrans(changedString, originString))))

cnss{E4sy_bAse64!}

🔪 [Easy] 恭喜你获得了flag提现机会!

IDA打开发现需要通过某些方式调用outputflag函数

image

可以直接nop掉if, 让程序直接执行outputflag

image

nop后效果:

image

image

写入到文件, 直接打开即可

image

cnss{3njoy_H4cK1ng!}

💻 [Easy+] diannaobaozhale

反写汇编, 没啥说的, 直接对着写就好了

image

a = [0x63, 0x6E, 0x73, 0x73, 0x7B]
print(''.join(chr(c) for c in a), end='')

v5 = 0x63
v4 = 0
while v4 <= 9:
    print(chr(v5), end='')
    v5 = (v5 + 2) ^ 1
    v4 += 1

print(chr(0x7d), end='')

cnss{cdghklopst}

🤡 [Middle] Vip of Mihoyo

IDA打开发现是虚拟机, 导出操作码后可以发现对每一个字符的处理都是一样的:

image

7, a, 2, 8, 3, 14, 1, 10, 5, 128, 6, b可以翻译为(flag[a] * 8 - 14 + 10)^128 == b

那么flag[a]就等于((b^128)-10+14)//8, 直接解码即可

以下为解码脚本

# 注释掉的这部分是对ida导出的byte数组进行小端转换为整数, 获得实际的opcode
# opcode = [0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 
#   0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
#   0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 
#   0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 
#   0x06, 0x00, 0x00, 0x00, 0x94, 0x03, 0x00, 0x00, 0x07, 0x00, 
#   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
#   0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 
#   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 
#   0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 
#   0x00, 0x00, 0xEC, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
#   0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 
#   0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 
#   0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 
#   0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
#   0x14, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 
#   0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
#   0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 
#   0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
#   0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x03, 
#   0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
#   0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 
#   0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
#   0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 
#   0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x54, 0x03, 0x00, 0x00, 
#   0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 
#   0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
#   0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 
#   0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 
#   0x06, 0x00, 0x00, 0x00, 0xAC, 0x02, 0x00, 0x00, 0x07, 0x00, 
#   0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
#   0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 
#   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 
#   0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 
#   0x00, 0x00, 0x3C, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
#   0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 
#   0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 
#   0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 
#   0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
#   0xCC, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 
#   0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
#   0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 
#   0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
#   0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xD4, 0x03, 
#   0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 
#   0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 
#   0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
#   0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 
#   0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x02, 0x00, 0x00, 
#   0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 
#   0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
#   0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 
#   0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 
#   0x06, 0x00, 0x00, 0x00, 0x2C, 0x02, 0x00, 0x00, 0x07, 0x00, 
#   0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
#   0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 
#   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 
#   0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 
#   0x00, 0x00, 0xE4, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
#   0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 
#   0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 
#   0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 
#   0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
#   0x74, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0D, 0x00, 
#   0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
#   0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 
#   0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
#   0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x01, 
#   0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 
#   0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 
#   0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
#   0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 
#   0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 
#   0x07, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x02, 0x00, 
#   0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
#   0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 
#   0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 
#   0x06, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x07, 0x00, 
#   0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
#   0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 
#   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 
#   0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 
#   0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
#   0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 
#   0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 
#   0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 
#   0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
#   0x94, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x12, 0x00, 
#   0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
#   0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 
#   0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
#   0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1C, 0x03, 
#   0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 
#   0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 
#   0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
#   0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 
#   0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 
#   0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 
#   0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
#   0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 
#   0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 
#   0x06, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0x07, 0x00, 
#   0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
#   0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 
#   0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 
#   0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 
#   0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
#   0x16, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 
#   0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 
#   0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 
#   0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
#   0x84, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 
#   0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
#   0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 
#   0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
#   0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, 0x03, 
#   0x00, 0x00]
# opcode = [opcode[i + 3] << 24 | opcode[i + 2] << 16 | opcode[i + 1] << 8 | opcode[i] for i in range(0, len(opcode), 4)]
# print(opcode)

# 转换后的opcode
opcode = [7, 0, 2, 8, 3, 14, 1, 10, 5, 128, 6, 916, 
          7, 1, 2, 8, 3, 14, 1, 10, 5, 128, 6, 1004, 
          7, 2, 2, 8, 3, 14, 1, 10, 5, 128, 6, 788, 
          7, 3, 2, 8, 3, 14, 1, 10, 5, 128, 6, 788, 
          7, 4, 2, 8, 3, 14, 1, 10, 5, 128, 6, 852, 
          7, 5, 2, 8, 3, 14, 1, 10, 5, 128, 6, 684, 
          7, 6, 2, 8, 3, 14, 1, 10, 5, 128, 6, 828, 
          7, 7, 2, 8, 3, 14, 1, 10, 5, 128, 6, 460, 
          7, 8, 2, 8, 3, 14, 1, 10, 5, 128, 6, 980, 
          7, 9, 2, 8, 3, 14, 1, 10, 5, 128, 6, 628, 
          7, 10, 2, 8, 3, 14, 1, 10, 5, 128, 6, 556, 
          7, 11, 2, 8, 3, 14, 1, 10, 5, 128, 6, 996, 
          7, 12, 2, 8, 3, 14, 1, 10, 5, 128, 6, 628, 
          7, 13, 2, 8, 3, 14, 1, 10, 5, 128, 6, 292, 
          7, 14, 2, 8, 3, 14, 1, 10, 5, 128, 6, 796, 
          7, 15, 2, 8, 3, 14, 1, 10, 5, 128, 6, 780, 
          7, 16, 2, 8, 3, 14, 1, 10, 5, 128, 6, 548, 
          7, 17, 2, 8, 3, 14, 1, 10, 5, 128, 6, 916, 
          7, 18, 2, 8, 3, 14, 1, 10, 5, 128, 6, 796, 
          7, 19, 2, 8, 3, 14, 1, 10, 5, 128, 6, 524, 
          7, 20, 2, 8, 3, 14, 1, 10, 5, 128, 6, 804, 
          7, 21, 2, 8, 3, 14, 1, 10, 5, 128, 6, 276, 
          7, 22, 2, 8, 3, 14, 1, 10, 5, 128, 6, 388, 
          7, 23, 2, 8, 3, 14, 1, 10, 5, 128, 6, 868]


# 这里是把虚拟机转写成python版本了(好理解一点)
def vm():
    flag = "asdasdasdasdasdasd"
    i = 0
    v5 = 0
    operator = {
        1: lambda a,b: a+b,
        2: lambda a,b: a*b,
        3: lambda a,b: a-b,
        4: lambda a,b: a//b,
        5: lambda a,b: a^b,
    }
    while i <= 287:
        v3 = opcode[i+1]
        
        if opcode[i] in operator:
            v5 = operator[opcode[i]](v5,v3)
        elif opcode[i] == 6:
            if v5 != v3:
                return False
        elif opcode[i] == 7:
            v5 = ord(flag[v3])
        elif opcode[i] == 8:
            flag[v3] = chr(v5)
        
        v5 &= 0xff
        i+=2
    return True

def decode():
    flag = ''.join(chr(((opcode[i + 11] ^ 128) - 10 + 14) // 8) for i in range(0, len(opcode), 12))
    print(flag)
    return flag

decode()

cnss{Fx*k_Vm_5trUctRu3!}

⭐ [Middle] Super Mario Code

打开IDA, 发现main是乱码, 根据题目可以知道是SMC.

image

动调找到解码后的SMC(可能需要到断点的时候按u将main取消定义了再按p重新生成函数)

image

image

可以看见就是个异或加密, 脚本解密就行

from Crypto.Util.number import *

a = 0x200E103830302D20
b = 0x3A3072261C30721C
c = b"b s-$1\"76/\"7r,-0b>"

a = long_to_bytes(a)[::-1]
b = long_to_bytes(b)[::-1]

cipher = a + b + c

flag = "".join([chr(i^0x43) for i in cipher])
print(flag)

cnss{SMc_1s_e1sy!c0ngratulat1ons!}

🌸 [Middle] 花花

打开IDA无法反汇编, 结合题目发现是花指令

类似这样的都是花指令,一般nop掉再重新按p生成函数即可

image

image

可以得到两部分加密函数

main函数:

image

第一部分:

image

第二部分:

image

脚本解密即可

cipher = list('Jew{PwcnwJJsCMMM1qyPZE5iHshiOF')
l = len(cipher)
for i in range(len(cipher)-1,-1,-1):
    tmp = cipher[i]
    cipher[i] = cipher[(i+9)%l]
    cipher[(i+9)%l] = tmp
for i in range(len(cipher)-1,-1,-1):
    tmp = cipher[i]
    cipher[i] = cipher[(i+3)%l]
    cipher[(i+3)%l] = tmp

a = [0, 0, 4, 6, 16, 20, 36, 42, 64, 72, 100, 110, 144, 156, 196, 210, 256, 272, 324, 342, 400, 420, 484, 506, 576, 600, 676, 702, 784, 812, 900, 930, 1024, 1056, 1156, 1190, 1296, 1332, 1444, 1482, 1600, 1640, 1764, 1806, 1936, 1980, 2116, 2162, 2304, 2352, 2500, 2550, 2704, 2756, 2916, 2970, 3136, 3192, 3364, 
3422, 3600, 3660, 3844, 3906, 4096, 4160, 4356, 4422, 4624, 4692, 4900, 4970, 5184, 5256, 5476, 5550, 5776, 5852, 6084, 6162, 6400, 6480, 6724, 6806, 7056, 7140, 7396, 7482, 7744, 7832, 8100, 8190, 8464, 8556, 8836, 8930, 9216, 9312, 9604, 9702]

alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789}{'
l = len(alphabet)
for i,c in enumerate(cipher):
    indexC = alphabet.index(c)
    indexF = ((indexC - a[i]) + 10*l)%l
    cipher[i] = alphabet[indexF]

print(''.join(cipher))

cnss{Fl0w3rC0de1sRe41llyC0oOl}

❤ [Middle] Shino 的心跳大冒险

一直走流程到最后发现flag被挡住了

image

这里用Cheat Engine的骚操作直接扫描cnss这个字符串即可(想到CE是因为它是常用游戏作弊器)

image

image

image

cnss{W0w!Y0u_4re_K1ng_0f_R3vers1g_n0W!!!}

这道题还有很多其他做法,比如修改资源删掉这张图片(应该是官解)、修改资源文件修改字体大小让flag漏出来(SSG爷的做法)等等,可以自己试试,方法很多

🦠 [Easy?] Baby XOR?

打开IDA发现加密逻辑,尝试之后发现不对。看汇编可以发现try...catch

image

按u将整个main函数(包括catch部分)全部undefinded掉,然后在catch处按p将catch部分生成为函数。

image

image

进入_Encrypt函数,根据S、ST、K可以大致猜测到为RC4加密

image

根据提示利用Meet In the Middle攻击,明文部分即为png的文件头,我们取四个字节当明文,再从密文中选四个字节作为对应的密文

等式对应如下

\[RC4(key1, plainText) == RC4(key2, cipherText) \]

下面为爆破程序,实测使用Cython和pypy均可将运行时间控制在十多分钟,使用原版python大概需要四十分钟以上

import binascii
import itertools

def rc4_crypt(PlainBytes:bytes, KeyBytes:bytes) -> bytes:
    cipherList = []
 
    keyLen = len(KeyBytes)
    plainLen = len(PlainBytes)
    S = list(range(256))
 
    j = 0
    for i in range(256):
        j = (j + S[i] + KeyBytes[i % keyLen]) % 256
        S[i], S[j] = S[j], S[i]
 
    i = 0
    j = 0
    for m in range(plainLen):
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        k = S[(S[i] + S[j]) % 256]
        cipherList.append(k ^ PlainBytes[m])
 
    return bytes(cipherList)

def main():
    keys = [bytes([i, j, k, l]) for i, j, k, l in itertools.product(range(81), repeat=4)]
    with open("./setu_encoded.png","rb") as f:
        cipherText = b"".join((i-17) for i in f.read()[:4])
    plainText = b"\x89\x50\x4E\x47"
    
    dic = {}
    
    for key in keys:
        encoded = rc4_crypt(plainText, key)
        dic[encoded] = key
        # print(f'\r{binascii.b2a_hex(key)} : {binascii.b2a_hex(encoded)}', end='', flush=True)
    
    for key in keys:
        # print(f'\r{binascii.b2a_hex(key)}', end='', flush=True)
        if rc4_crypt(cipherText, key) in dic:
            print(f"\nFound: {binascii.b2a_hex(key)} , {binascii.b2a_hex(dic[rc4_crypt(cipherText, key)])}")

main()

可以跑出来两个key分别为35, 31, 34, 69和25, 6, 19, 6解密setu即可

flag怎么把关键部位挡住了啊喂

cnss{Re4a1_Fu1_St4ck_CtfER_1s_cl3r}

🧠 [Hard] Brainfuck++

反反调试

IDA打开调试时发现有反调试,在exe的逆向里并没有发现反调试相关的代码,于是进入dll中寻找,利用Strings定位到反调试所在之处

image

image

反调试逻辑还是较为简单的,将这一大部分nop掉即可

image

nop的效果为

image

动态调试

开始动态调试,这里将Application改成Brainfuck++.exe

image

我选择在此处打断点(因为上面那部分字符串异或的结果是brainfuck++.exe)

image

成功捕获断点

image

这里查看v3的值,就可以找到被dll更改过的brainfuck++码。

image

这里可以发现会对数据预处理,从最后一位开始异或后一位,(最后一位的后一位被赋值成了4,动调可以看出来,这里不再赘述),解密时也要做反向的操作。

按住F8单步步过,一直到程序等待输入的时候

image

尝试搜索flag字符串,可以找到stack里有flag相关的字符串

image

这里给这个内存空间打上断点

image

输入数据继续调试, 进入到了一部分无法反汇编的代码,可以先在这里打个断点,然后取消刚刚在内存空间打的断点。

image

这里我们直接将这一部分代码按u取消定义,到上面去按p创建函数。

image

image

可以发现这里就是虚拟机的函数。在调用dll里的函数的这一步打上断点

image

继续运行,成功捕获

image

按下F7步进,可以进入加密的函数

image

这里照样遇到了不能反编译,按之前的方法先取消再创建即可。

image

image

这里的v2数组可以猜测就是加密后的字符串了,直接导出即可

v2 = [203, 189, 254, 233, 107,  96,  96,  40,  30, 206, 230,  99, 176, 194,  46,  15, 111, 237,   3,  85, 235, 139,  61, 138,  60, 229, 116, 153, 130,  37, 245,  63]

点击进入sub_401550, 可以看出明显的TEA加密

image

在里面打上断点,运行进入。

可以发现v4就是delta,值为0x9E3779B9

image

a2是key,值为[0x69207A6C, 0x7475706E, 0x65687420, 0x616C6620]

image

解密

写脚本解密即可

from ctypes import *
from Crypto.Util.number import *

delta = 0x9E3779B9

def decrypt(v, k):
    v0, v1 = c_uint32(v[0]), c_uint32(v[1])
    k0, k1, k2, k3 = k[0], k[1], k[2], k[3]

    total = c_uint32(delta * 32)
    for i in range(32):                       
        v1.value -= ((v0.value<<4) + k2) ^ (v0.value + total.value) ^ ((v0.value>>5) + k3) 
        v0.value -= ((v1.value<<4) + k0) ^ (v1.value + total.value) ^ ((v1.value>>5) + k1)  
        total.value -= delta

    return v0.value, v1.value   

def toLittleEndian(x):
    return x[0] + (x[1] << 8) + (x[2] << 16) + (x[3] << 24)

if __name__ == "__main__":
    cipher = [203, 189, 254, 233, 107,  96,  96,  40,  30, 206, 230,  99, 176, 194,  46,  15, 111, 237,   3,  85, 235, 139,  61, 138,  60, 229, 116, 153, 130,  37, 245,  63]
    
    key = [0x69207A6C, 0x7475706E, 0x65687420, 0x616C6620]

    bytes = b''
    for i in range(0, len(cipher), 8):
        v = [toLittleEndian(cipher[i:i+4]), toLittleEndian(cipher[i+4:i+8])]
        res = decrypt(v, key)
        bytes += long_to_bytes(res[0])[::-1] + long_to_bytes(res[1])[::-1]

    flag = list(bytes)

    flag.append(4)
    for i in range(len(flag)-1):
        flag[i] ^= flag[i+1]

    flag = ''.join([chr(i) for i in flag])
    
    print(flag) 

cnss{k1nG_0f_tHE_BRa1nFuCk++!!!}

😴 [BOSS] Crazy Hacker

⚓ [Real World] 互联网海盗

抓包找到sign生成

image

进index搜索sign:(带冒号是因为只匹配json中的

image

给四个sign:都打上断点

image

点击翻译按钮进入断点, 跟随断点来到这个位置, 就找到了sign的生成函数.

image

复制到python中, 给这里取个函数名:

image

image

利用execjs执行一遍试试:

import execjs

js = r"""
function e(t, e) {
    (null == e || e > t.length) && (e = t.length);
    for (var n = 0, r = new Array(e); n < e; n++)
        r[n] = t[n];
    return r
}
function n(t, e) {
    for (var n = 0; n < e.length - 2; n += 3) {
        var r = e.charAt(n + 2);
        r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
        r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
        t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
    }
    return t
}
var r = null;
function signGen(t) {
    var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
    if (null === i) {
        var a = t.length;
        a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
    } else {
        for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
            "" !== s[c] && l.push.apply(l, function(t) {
                if (Array.isArray(t))
                    return e(t)
            }(o = s[c].split("")) || function(t) {
                if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
                    return Array.from(t)
            }(o) || function(t, n) {
                if (t) {
                    if ("string" == typeof t)
                        return e(t, n);
                    var r = Object.prototype.toString.call(t).slice(8, -1);
                    return "Object" === r && t.constructor && (r = t.constructor.name),
                    "Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
                }
            }(o) || function() {
                throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
            }()),
            c !== u - 1 && l.push(i[c]);
        var p = l.length;
        p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
    }
    for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
        var _ = t.charCodeAt(v);
        _ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
        g[y++] = _ >> 18 | 240,
        g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
        g[y++] = _ >> 6 & 63 | 128),
        g[y++] = 63 & _ | 128)
    }
    for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
        b = n(b += g[x], w);
    return b = n(b, k),
    (b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
    "".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}
"""


def signGen(text):
    return execjs.compile(js).call('signGen', text)

print(signGen("CNSS"))

发现报错execjs._exceptions.ProgramError: ReferenceError: window is not defined,这里我们可以直接搜索window发现是对r进行定义, 在断点中查看r的值, 可以发现r是一个定值

image

image

r = "320305.131321201"

所以我们把js中r的定义语句删掉, 换成let r = "320305.131321201";

image

image

即可正常运行

image

稍微修改代码逻辑, 打包一下, 最终程序:

import execjs

js = r"""
function e(t, e) {
    (null == e || e > t.length) && (e = t.length);
    for (var n = 0, r = new Array(e); n < e; n++)
        r[n] = t[n];
    return r
}
function n(t, e) {
    for (var n = 0; n < e.length - 2; n += 3) {
        var r = e.charAt(n + 2);
        r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
        r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
        t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
    }
    return t
}
let r = "320305.131321201";
function signGen(t) {
    var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
    if (null === i) {
        var a = t.length;
        a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
    } else {
        for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
            "" !== s[c] && l.push.apply(l, function(t) {
                if (Array.isArray(t))
                    return e(t)
            }(o = s[c].split("")) || function(t) {
                if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
                    return Array.from(t)
            }(o) || function(t, n) {
                if (t) {
                    if ("string" == typeof t)
                        return e(t, n);
                    var r = Object.prototype.toString.call(t).slice(8, -1);
                    return "Object" === r && t.constructor && (r = t.constructor.name),
                    "Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
                }
            }(o) || function() {
                throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
            }()),
            c !== u - 1 && l.push(i[c]);
        var p = l.length;
        p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
    }
    for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
        var _ = t.charCodeAt(v);
        _ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
        g[y++] = _ >> 18 | 240,
        g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
        g[y++] = _ >> 6 & 63 | 128),
        g[y++] = 63 & _ | 128)
    }
    for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
        b = n(b += g[x], w);
    return b = n(b, k),
    (b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
    "".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}
"""

def signGen(text):
    return execjs.compile(js).call('signGen', text)

while True:
    text = str(input('输入文本: '))
    print(signGen(text))

pyinstaller打包

pyinstaller.exe sign.py -F

最终效果:

image

posted @ 2022-10-21 22:30  Tim厉  阅读(274)  评论(0编辑  收藏  举报