NSSRound22-Reverse专项赛

22这个数字我很喜欢,就是出的题目难了点😥

ezapk-1

java层有XTEA

魔改异或918,得到username,负数用jeb转成16进制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdint.h>

int main() {
uint32_t v[2] = { 1, 2 };
int num = 32;
uint32_t v0 = v[0], v1 = v[1], i; /* set up */
uint32_t delta = 0x9E3779B9, sum = 0x9E3779B9 * num;
uint32_t v2[2] = { 0x3D121D26, 0x5E6189F9 }, v3[2] = { 0xC1FB278E, 0x3B494648 }, v5[10] = { 0x3c36eb49, 0x81acb0c0, 0xfac269ae, 0xca5bf9ec };
uint32_t k[4] = { 0x12345678, 0x5678abcd, 0x89ABCDEF, 0xCDEF1234 }, l = 0, r = 0;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
for (int m = 0; m < 8; m += 2) {//flag不全的话有可能是10
sum = 0x9E3779B9 * num;
for (i = 0; i < 32; i++) { /* basic cycle start */
v5[m + 1] -= (v5[m] << 4 ^ v5[m] >> 5) + v5[m] ^ 918 ^ k[(sum >> 11) & 3] + sum;
sum += 0x61C88647;
v5[m] -= (v5[m + 1] << 4 ^ v5[m + 1] >> 5) + v5[m + 1] ^ 918 ^ k[sum & 3] + sum;
} /* end cycle */
}

for (int i = 0; i < 8; i++) {
for (int m = 0; m <= 3; m++) {
printf("%c", (v5[i] >> (8 * m)) & 0xff);
}
}

return 0;
}
//NS5_R0Un6_z2_apK

魔改rc4,256变成128

一开始以为validatePassword函数还有加密,后来想如果是这样的话java层应该有密文,再去看发现上面函数只是确认密文,这样看的话java层validatePassword(str, encryptWithRC4(str2, str))两个str含义不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def rc4(data, key):
S = list(range(128))
j = 0
out = []

for i in range(128):
j = (j + S[i] + key[i % len(key)]) % 128
S[i], S[j] = S[j], S[i]

i = j = 0
for char in data:
i = (i + 1) % 128
j = (j + S[i]) % 128
S[i], S[j] = S[j], S[i]
out.append(char ^ S[(S[i] + S[j]) % 128])

return bytes(out)


data = bytes.fromhex("572e180b1a680b3e5276344b241d5b52525a043173346b1355442028")
key = b'NS5_R0Un6_z2_apK'
decrypted = rc4(data, key)
print(decrypted)
#NSSCTF{V3ry_4z_1ib_W1th_4pk}

EzHook-1

考得是Windows IAT Hook技术,本题hook了MessageBoxA函数,当执行MessageBoxA的时候会跑到另外地方

4B0函数里面一堆异或,一个个写出来不显示,后面Right?的话应该没这么简单

往main前找,找到1240,调试起来发现运行在main函数之后

1880和1840里面调用的函数是一样的,那么大概率就是一对加解密函数

细看猜测是xxtea

最后给了个弹窗,也就是说a090函数是MessageBoxA函数

调试到这里把str2赋值给a2

1
E4 E7 FE E3 17 1C DE 32 E6 B8 68 40 40 D8 72 FA 88 14 E1 85 CD 81 AA DE 1D E8 92 41 B8 1E 5E CF CE 49 27 22 39 7D 50 DA

通过汇编的rcx进入编辑

每16个地址change byte一次,把对应的密文填进去

运行到解密函数之后

直接就是参数a1NSSCTF{C0ngr@tulat1ons!H0Ok_bY_1t_s3lf!}

ezcrypt-1

反编译pyc,得到blowfish,key并不能直接用

而要去crypto.cpython.pyc里找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {
unsigned int enc[5] = {
1396533857,
0xCC8AE275,
0x89FB8A63,
940694833
};
unsigned int key[4] = {
17,
34,
51,
68
};
int i, j;
for (i = 0; i < 4; i += 2) {
unsigned int v0 = enc[i], v1 = enc[i + 1], sum = 32 * 0x9e3779b9;
unsigned int delta = 0x9e3779b9;
unsigned int k0 = key[0], k1 = key[1], k2 = key[2], k3 = key[3];
for (j = 0; j < 32; j++) {
v1 -= ((v0 << 3) + k2 ^ v0 + sum ^ (v0 >> 4) + k3 ^ 2310) & 0xFFFFFFFF;
v0 -= ((v1 << 3) + k0 ^ v1 + sum ^ (v1 >> 4) + k1 ^ 596) & 0xFFFFFFFF;
sum -= delta & 0xFFFFFFFF;
}
enc[i] = v0;
enc[i + 1] = v1;
}
for (i = 0; i < 4; i++) {
//printf("%u ", enc[i]);
}
printf("%s", enc);//sNzEveRsjorPstce
return 0;
}

key四位里面反转,得到EzNssRevProjects,用脚本分割iv和密文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# ezcrypt wp
from Crypto.Cipher import Blowfish
from Crypto.Util.Padding import unpad
from Crypto.Random import get_random_bytes


def decrypt_file(input_path, output_path, key):
with open(input_path, 'rb') as f:
# 读取整个文件内容,包括IV和密文
data = f.read()

# 分割IV和密文
iv = data[:Blowfish.block_size]
print(iv)
ciphertext = data[Blowfish.block_size:]
#print(ciphertext)
# 验证密钥长度
# if len(key) != Blowfish.key_size:
# raise ValueError("Invalid key size for Blowfish. It must be exactly 8 bytes long.")

# 创建一个新的Blowfish cipher对象,并设置密钥和IV
cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv=iv)

# 解密数据
plaintext = (cipher.decrypt(ciphertext), Blowfish.block_size)
#print(plaintext[0])
# 将解密后的数据写入输出文件
with open(output_path, 'wb') as f:
f.write(plaintext[0])


key = b'EzNssRevProjects'
input_path = 'output'
output_path = 'flag'

decrypt_file(input_path, output_path, key)

得到elf,发现是vm,v5是opcode,v4是key

VM函数抄下来符号改一下,有个地方给的代码还不对,看汇编也是sub,其实是add

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<stdio.h>
__int64 __fastcall vm(unsigned char* a1, int* a2, int a3)
{
__int64 result; // rax
int i; // [rsp+1Ch] [rbp-8h]
int v5; // [rsp+20h] [rbp-4h]

for (i = 0; ; ++i)
{
result = i;
if (i >= a3)
break;
v5 = i % 4;
if (i % 4 == 3)
{
a1[i] -= a2[8] + a2[0];
}
else if (v5 <= 3)
{
if (v5 == 2)
{
a1[i] += a2[4] ^ a2[12];
}
else if (v5 <= 2)
{
if (v5)
{
if (v5 == 1)
{
a1[i] ^= a2[0] - a2[8];
}

}
else
{
a1[i] ^= a2[16] + a2[4];
}
}
}
}
return result;
}
int main()
{
unsigned char opcode[] =
{
0x37, 0x8D, 0x0F, 0xAB, 0x2D, 0x98, 0x37, 0xB5, 0x48, 0xA6,
0x30, 0xDA, 0x0C, 0xED, 0x1B, 0xB8, 0x00, 0xE9, 0x24, 0x98,
0x17, 0x81, 0xED, 0xB6, 0x26, 0x8C, 0x21, 0xDE, 0x04, 0xDE
};
int key[] =
{
0x23, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x67
};

vm(opcode, key, 30);
printf("%s", opcode);//NSSCTF{M1xtru3_Py7h0n_1N_Rev}
return 0;
}

稍微分析可以写出python,这里还是把上面的-改成+了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
data = bytearray.fromhex(
"378D0FAB2D9837B548A630DA0CED1BB800E924981781EDB6268C21DE04DE")
key = [0x23, 0x12, 0x45, 0x56, 0x67]
for i in range(30):
n = i % 4
if (n == 0):
data[i] = (data[i] ^ (key[4] + key[1])) & 0xff
if (n == 1):
data[i] = (data[i] ^ (key[0] - key[2])) & 0xff
if (n == 2):
data[i] = (data[i] + (key[3] ^ key[1])) & 0xff
if (n == 3):
data[i] = (data[i] - (key[2] + key[0])) & 0xff

for i in data:
print(chr(i), end='')

Go!Go!Go!-1

大量的WinAPI调用,进入1490

交叉引用5080

动调发现qword_140005080内资源开头为MZ,是PE文件

ResourceHacker正好可以提取

导出elf,后面发现是exe文件

hashcat -m 0 -a 3 b098cacb2d43b882ef9a83168d13c3a7 ?a?a?a?a?a?a(-a后面跟16500表示jwt HMAC-SHA256 哈希类型 )

第二个key同理

1
G0@K3y` `n3SC1f

main1的两个key拼接在一起传到main2

main2函数后面,第三次输入的就是flag

发现RC4特征,发现魔改了

p->string就是输入的明文

用正确的密文一行行patch

输入密文长度匹配


NSSRound22-Reverse专项赛
https://j1ya-22.github.io/2024/04/28/NSSRound22Reverse专项赛/
作者
j1ya
发布于
2024年4月28日
许可协议