NSSCTF2nd部分Reverse

j1ya Lv5

Reverse

MyBase

不是简单base64,研究后发现3转4的时候,前后字符颠倒了位置

exception_handler函数每次运行会修改base64表

所以需要每次都重新生成base64表,根据新的表和对应的加密块解密得到一部分flag

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
61
62
63
64
65
BASE64_TABLE = "+86420ywusqomkigecaYWUSQOMKIGECABDFHJLNPRTVXZbdfhjlnprtvxz13579/"

class MSVCRTRand:
"""
模拟 Windows/MSVCRT 的 srand/rand
"""
def __init__(self, seed):
self.state = seed & 0xffffffff

def rand(self):
self.state = (
self.state * 214013 + 2531011
) & 0xffffffff
return (self.state >> 16) & 0x7fff

def generate_base64_table(old_table):
STD_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
rand = MSVCRTRand(ord(old_table[0]))
tmp = list(STD_TABLE + old_table)
for i in range(63, 0, -1):
j = rand.rand() % (i + 1)
tmp[j], tmp[i] = tmp[i], tmp[j]
return "".join(tmp[:64]) + "="

def decode_block(block, table):
decode_table = {
char: index
for index, char in enumerate(table[:64])
}

v1 = decode_table[block[0]] if block[0] != "=" else 0
v2 = decode_table[block[1]] if block[1] != "=" else 0
v3 = decode_table[block[2]] if block[2] != "=" else 0
v4 = decode_table[block[3]] if block[3] != "=" else 0
value = (
v1 |
(v2 << 6) |
(v3 << 12) |
(v4 << 18)
)
b1 = (value >> 16) & 0xff
b2 = (value >> 8) & 0xff
b3 = value & 0xff

result = bytearray()
result.append(b1)
if block[2] != "=":
result.append(b2)
if block[3] != "=":
result.append(b3)
return bytes(result)

def base64_decode(encoded):
table = BASE64_TABLE
result = bytearray()
for i in range(0, len(encoded), 4):
block = encoded[i:i + 4]
decoded = decode_block(block, table)
result.extend(decoded)
table = generate_base64_table(table)
return bytes(result)

encrypted = "YkLYv1Xj23X7N0E5eoFgUveKeos1XS8K9r4g"
flag = base64_decode(encrypted)
print(flag)

Bytecode

给的是字节码,让gpt生成python脚本

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import base64
import string

def check(key):
x = [78, 82, 81, 64, 80, 67, 125, 83, 96, 56, 121, 84, 61, 126, 81, 79, 79, 119, 38, 120, 39, 74, 112, 38, 44, 126, 103]
if len(key) != len(x):
print('Wrong length!')
exit()
for i in range(len(key)):
if ord(key[i]) ^ i != x[i]:
return 0
return 1

def init(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box

def fun(msg, key="Just kidding, don't take it personally!"):
x = []
for i in range(len(msg)):
x.append(ord(msg[i]) ^ ord(key[i % len(key)]))
for i in range(len(x)):
x[i] ^= i
return x

def encrypt1(msg, s_box):
x = []
i = 0
j = 0
for k in range(len(msg)):
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
t = (s_box[i] + s_box[j]) % 256
x.append(ord(msg[k]) ^ s_box[t])
return x

def encrypt2(msg, s_box, key):
x = []
i = 0
j = 0
for k in range(len(msg)):
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
t = (s_box[i] + s_box[j]) % 256
x.append(ord(msg[k]) ^ s_box[t] ^ ord(key[i]))
return x

def encrypt(msg, s_box):
x = []
i = 0
j = 0
for k in range(len(msg)):
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
t = (s_box[i] + s_box[j]) % 256
x.append(ord(msg[k]) ^ s_box[t] ^ i)
return x

if __name__ == '__main__':
key = input('Please input your key:')
if check(key) == 1:
print('Right!')
else:
print('Wrong!')
exit()

msg = input('Please input your message:')

box = init(key)
encode = encrypt(msg, box)

string1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
string2 = 'YRiAOe4PlGvxaCoNj2ZgX+q8t/5Em6IUpM9FrVb7BKwsT1n3fSydhDWuQHJ0ckzL'

encode = base64.b64encode(bytes(encode)).decode().translate(str.maketrans(string1, string2))

if encode == 'mWGFL24R/RSZY3pzK9H4FOmFOnXJKyCjXWbZ7Ijy11GbCBukDrjsiPPFiYB=':
print('Congraduation!You get the right flag!')
else:
print('Wrong!')

加密为魔改RC4+base64变表

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
import base64

def recover_key():
x = [78, 82, 81, 64, 80, 67, 125, 83, 96,56, 121, 84, 61, 126, 81, 79, 79, 119,38, 120, 39, 74, 112, 38, 44, 126, 103]
return ''.join(chr(value ^ i) for i, value in enumerate(x))

def init_sbox(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box

def decrypt(ciphertext, key):
string1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
string2 = 'YRiAOe4PlGvxaCoNj2ZgX+q8t/5Em6IUpM9FrVb7BKwsT1n3fSydhDWuQHJ0ckzL'
standard_base64 = ciphertext.translate(str.maketrans(string2, string1))
encrypted_bytes = base64.b64decode(standard_base64)

s_box = init_sbox(key)
plaintext = bytearray()

i = 0
j = 0
for value in encrypted_bytes:
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]

t = (s_box[i] + s_box[j]) % 256
plaintext.append(value ^ s_box[t] ^ i)
return plaintext.decode('utf-8')

if __name__ == '__main__':
ciphertext = 'mWGFL24R/RSZY3pzK9H4FOmFOnXJKyCjXWbZ7Ijy11GbCBukDrjsiPPFiYB='
key = recover_key()
flag = decrypt(ciphertext, key)
print(flag)
#NSSCTF{eda20db6-3cff-6125-f6ca-1a155bd3292c}

Tea or XTtea

D810插件去控制流平坦化混淆之后main如下,fork后父子进程执行顺序在操作系统调度层面不固定

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
61
62
63
64
65
66
67
68
69
70
71
int __fastcall main(int argc, const char **argv, const char **envp)
{
int v3; // edx
int v4; // esi
int v5; // edx
int v6; // esi
int j; // [rsp+F0h] [rbp-20h]
int i; // [rsp+F4h] [rbp-1Ch]
int v10; // [rsp+F8h] [rbp-18h]
int k; // [rsp+FCh] [rbp-14h]
int v12; // [rsp+100h] [rbp-10h]

before_main();
printf(aNoOneTraceMe, argv);
puts("Please input your flag:");
scanf("%s", input);
if ( strlen((const char *)(unsigned int)input) != 40 )
::k = 0;
if ( pipe(fd) != -1 )
{
pid = fork();
if ( pid != -1 )
{
if ( pid )
{
puts("this is father");
v10 = 0;
close(fd[0]);
while ( v10 < strlen((const char *)(unsigned int)input) )
{
p = (__int64)&input[v10];
v5 = *(_DWORD *)&input[v10];
v6 = cd++;
flag[v6] = v5;
v10 += 4;
}
for ( i = 0; i < 5; ++i )
encode_2((unsigned int *)&flag[2 * i], &key1);
for ( j = 0; j < 10; ++j )
{
if ( flag[j] != enc1[j] )
::k = 0;
}
if ( ::k )
puts("You are right!!!");
else
puts("You are wrong!!!");
close(dword_404138);
wait(0LL);
exit(0);
}
v12 = 0;
close(dword_404138);
while ( v12 < strlen((const char *)(unsigned int)input) )
{
p = (__int64)&input[v12];
v3 = *(_DWORD *)&input[v12];
v4 = cd++;
flag[v4] = v3;
v12 += 4;
}
for ( k = 0; k < 10; k += 2 )
encode_1((unsigned int *)&flag[k], &key2);
close(fd[0]);
_exit(0);
}
exit(1);
}
perror("pipe");
exit(1);
}

需要注意没有导入/调用 read 或 write,所以子进程的结果不会传给父进程,只有encode_2与flag有关

tea算法中会访问key[4]

而.bss 段在程序装载时会被系统初始化为全 0

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

void decrypt2(uint32_t v[2], const uint32_t key[4]) {
uint32_t v0 = v[0], v1 = v[1], delta = 0x61C88647;
uint32_t sum=0xC6EF3720-32*delta;
for (int i = 0; i < 32; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 3)) + v0) ^ (sum + key[sum & 4]);
v0 -= (((v1 << 4) ^ (v1 >> 3)) + v1) ^ (sum + key[(sum>>2) & 4]);
sum += delta;
}
v[0] = v0;
v[1] = v1;
}
int main() {
uint32_t key1[5] = {0x21, 0x37, 0x4D, 0x63, 0x0};
uint32_t key2[4] = {0x63, 0x4D, 0x37, 0x21};
uint32_t v5[10] = {0x78156470,0xa03f8fea,0x9a5483ca,0xd609a639,0xf90345b,0x12300b20,0x38d00d6a,0xc3f8c215,0x842d02c9,0x56cf1afb};
for (int i = 0; i < 10; i += 2) {
decrypt2(&v5[i], key1);
}
for (int i = 0; i < 10; i++) {
for (int m = 0; m <= 3; m++) {
printf("%c", (v5[i] >> (8 * m)) & 0xff);
}
}
return 0;
}
#flag{tea_or_xtea_you_should_choose_one!}
  • 标题: NSSCTF2nd部分Reverse
  • 作者: j1ya
  • 创建于 : 2023-09-08 16:43:02
  • 更新于 : 2026-10-03 16:46:34
  • 链接: https://j1ya-22.github.io/2023/09/08/NSSCTF2nd部分Reverse/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
NSSCTF2nd部分Reverse