好难QAQ

1.(填空)请分析检材1,该检材的蓝牙mac地址为 (参考格式:11:22:33:44:55:66) 分值:16

1
([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}
类型 MAC地址 位置
WiFi MAC a4:55:90:12:21:35 data/misc/apexdata/com.android.wifi/WifiConfigStore.xml:627
蓝牙MAC a4:55:90:15:2e:76 data/misc/bluedroid/bt_config.bak:9

image-20251011220250618

1
A4:55:90:15:2E:76

2.(填空)请分析检材1,该检材的系统Linux内核版本号为 (参考格式:1.1.1) 分值:16

1
\d{1,3}\.\d{1,3}\.\d{1,3}

image-20251011220710119

1
4.14.186

3.(填空)请分析检材1,该检材中实际使用的密码管理软件的软件包包名为 (参考格式:com.forensix.cn) 分值:19

检材1-手机\storage\emulated\0\Android\data​,在此路径中找一下

image-20251011221213296

1
design.codeux.authpass.fdroid

4.(填空)请分析检材1,该检材中密码管理软件的主密钥为 (参考格式:Your answer is right.) 分值:16

在便签里面,检材1-手机\data\user\0\com.miui.notes\databases

image

password for keepass

1
Save my P Ass.

5.(填空)请分析检材1,该检材中保存的github.com密码为 (参考格式:Abc123) 分值:19

安装Keepass

image

1
Forensix777

6.(填空)请分析检材1,该检材root工具的版本为 (参考格式:1.1) 分值:16

在package.list中查找magisk

image

1
27.0

7.(填空)请分析检材1,找到该手机上的Linux容器,并回答下列问题,该Linux发行版名称为 (参考格式:kali) 分值:19

image

1
debian

8.(单选)请分析检材1容器,该系统默认桌面环境为 (参考格式:) 分值:19
A.KDE
B.GNOME
C.XFCE
D.DDE

image

9.(填空)请分析检材1容器,该系统的android用户密码为 (参考格式:abc123) 分值:19

image

1
99c26da5

10.(填空)请分析检材1容器,浏览器下载的文件名为 (参考格式:1.txt) 分值:19

image

1
reshacker_setup.exe

11.(填空)请分析检材1容器,陈某使用过的github代理的域名为 (参考格式:fic.forensix.cn) 分值:23

image

1
gh.viru.sh

12.(填空)请分析检材1容器中助记词程序recphrase,其使用的壳类型为 (参考格式:VMP) 分值:19

image

1
upx

13.(填空)请分析上题程序,程序运行后第2列第3行助记词为 (参考格式:salute) 分值:26

recphrase​反编译后入口是reco.pyc

对这个reco.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
36
37
38
from matplotlib import pyplot as plt
from matplotlib.font_manager import FontProperties
import string

# Create a 4x3 grid of subplots
fig, axes = plt.subplots(4, 3, figsize=(12, 12))
axes = axes.flatten()
# Word list encoded as ASCII values
# These are the 12 recovery phrase words
word_codes_list = [
[115, 101, 115, 115, 105, 111, 110], # "session"
[102, 101, 118, 101, 114], # "fever"
[115, 112, 111, 110, 115, 111, 114], # "sponsor"
[99, 114, 111, 117, 99, 104], # "crouch"
[116, 105, 99, 107, 101, 116], # "ticket"
[116, 119, 105, 115, 116], # "twist"
[97, 112, 112, 114, 111, 118, 101], # "approve"
[118, 105, 108, 108, 97, 103, 101], # "village"
[102, 105, 110, 105, 115, 104], # "finish"
[115, 113, 117, 97, 114, 101], # "square"
[97, 108, 115, 111], # "also"
[99, 111, 111, 107] # "cook"
]
# Iterate through each word and display it in a subplot
for i, word_codes in enumerate(word_codes_list):
ax = axes[i]
# Set the limits and ticks
ax.set_xlim(0, len(word_codes) + 1)
ax.set_ylim(0, 3)
ax.set_xticks([])
ax.set_yticks([])
# Convert ASCII codes to string
word = ''.join([chr(code) for code in word_codes])
# Display the word in the subplot
ax.text(0.5, 1.5, word, fontsize=24, ha='left', va='center')
# Show the plot
plt.tight_layout()
plt.show()

这样创建的是一个三列四行的表格,所以第二列第三行应该是第八个,vilage

1
village

14.(填空)请分析上题程序,该组助记词对应的钱包种子前8位为 (参考格式:abc123) 分值:29

BIP39 助记词转换器

image

1
e08478b0

15.(填空)请分析检材1容器,钓鱼网站(phishing)的后台用户密码加密算法为 (参考格式:aes_sha1) 分值:23

image

1
pbkdf2_sha256

16.(填空)请分析检材1容器,钓鱼网站超管用户的弱口令为 (参考格式:123456) 分值:26

1
123456

17.(填空)请分析检材1容器,宝塔面板的入口为 (参考格式:/abc123) 分值:23

一般是在这里/www/server/panel/data/admin_path.pl

image

1
/a2d3e161

18.(填空)请分析检材1容器,宝塔面板运行在aarch64内核时报错的so文件为 (参考格式:a.so) 分值:29

image

1
PluginLoader.so

19.(填空)请分析检材2,该检材系统中设备名称为neo4chen的系统分区的sha256值为 (参考格式:) 分值:16

image

1
E2219548F5A8E61F373258EB658625ADDA7BF858A83AD8D6E4213BCD8ECEB423

20.(填空)请分析检材2,上题系统中,曾被远程控制的ip为 (参考格式:1.1.1.1) 分值:16

TerminalServices​或RemoteConnectionManager

image

image

1
192.168.3.14

21.(填空)请分析检材2加密系统,陈某通过物理方式保存助记词的东西名为 (参考格式:存钱罐) 分值:19

需要把计算机仿真起来

image

image

1
时光密钥

image这还能登上???

22.(填空)请分析检材2加密系统,陈某保存记录完整助记词的文件的md5值为 分值:19

image

image

image

1
635aa992d8513105d3c27c6b9ef373f9

23.(单选)请分析检材2加密系统,陈某交代XI位为2^1,上题文件对应中文助记词不包含一下哪一项 (参考格式:) 分值:23
A.摇
B.选
C.的
D.以

1
2
3
4
5
6
7
8
lst = ["11100111101", "11000000001", "11111010110", "01101010000", "11000110110", 
"00000000101", "10001001000", "11001111010", "00001111000", "00001100001",
"00000011001", "10001011011"]

with open("bip39_chinese_simplified.txt", 'r', encoding='utf-8') as f:
lines = f.readlines()
for binary in lst:
print(lines[(int(binary, 2)^1988)-1].strip(), end="")

BIP39 词表的索引规则

  1. BIP39 标准编号:词表中的单词编号是 1-2048(从 1 开始)
  2. Python 列表索引:列表索引是 0-2047(从 0 开始)

转换逻辑

如果 v^1988​ 的结果代表的是 BIP39 标准编号(1-2048),那么:

  • BIP39 编号为 1 的单词 → 在列表中的索引是 0
  • BIP39 编号为 2048 的单词 → 在列表中的索引是 2047

因此需要 -1​ 来转换:lines[(v^1988)-1]

image

1
C

24.(填空)请分析检材2加密系统,该检材加密系统中陈某自白的录音最后修改时间为 (参考格式:2000-00-00 00:00:00) 分值:19

image

1
2025-05-14 20:59:20

25.(填空)请分析检材2加密系统,陈某和李某共同出行的户外活动为 (参考格式:摄影) 分值:23

image

1
钓鱼

26.(填空)请分析检材2加密系统,陈某自白中的隐藏的“学习资料”所在服务器ip地址为 分值:26

剪映虽然没登录VIP但是好像可以直接用声音分离功能

imagepython也可以,就是代码些许复杂,这里就不放出来了,不如直接剪映

image

1
114.51.41.91

27.(填空)请分析检材2加密系统,存放欠条的加密容器文件名为 (参考格式:蜂蜜锅底) 分值:23

1
我的手机号

28.(填空)请分析检材2加密系统,该容器欠条中赵某欠陈某多少虚拟币 (参考格式:0.524ETH) 分值:26

密码手机号在初赛里

3170010703​,13170010703​,一个普通分区,一个隐藏分区

image

1
0.079BTC

29.(填空)请分析检材2加密系统,该检材中ubuntu光盘文件的系统内核版本号为 (参考格式:6.6.6) 分值:19

image

image

1
4.15.0

30.(单选)请分析检材2Linux系统,该系统的当前状态为 分值:23
A.Poweroff(S5)
B.Sleep(S2)
C.Hibernate(S4)
D.Poweron(G0)

找到system.journal

1
journalctl --file system.journal --lines 10

image

31.(填空)请分析检材2Linux系统,该系统使用了什么阵列 (参考格式:zfs1) 分值:19

xw直接看到

1
raid0

32.(填空)请分析检材2Linux系统,系统自带记事本软件中记录的密码的未知位数有几位 (参考格式:1) 分值:23

Kali默认的应该是mousepad

image

chrome password : chewhaoN@%d%d%d%d

1
4

33.(填空)请分析检材2Linux系统,系统自带记事本内容缓存在重组后逻辑分区中的起始偏移地址为 (参考格式:0x0123456789) 分值:26

image

1
0x0296D90000

34.(填空)请分析检材2Linux系统,chrome浏览器插件的保护密码为 (参考格式:a@1) 分值:26

直接搜/home/haobei/.config/google-chrome/Default​目录下的key字段,找到疑似是密文的部分

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const CryptoJS = require("crypto-js");
const argon2 = require("argon2");
const targetHash = "$argon2id$v=19$m=16384,t=1,p=1$k6EZEDdQYyn+/0GlJtZGpg$hicAuwJorE73Moj+Po2Txda8hyoPPGYa";
(async () => {
console.log("start");
for(var i=0;i<10000;i++){
var password = "chewhaoN@"+String(i).padStart(4, '0');
try {
var decryptedWordArray = CryptoJS.AES.decrypt("U2FsdGVkX18Tb9IA8UF4TbpMQjOs4IqZBTIkldDlgn9vw1gIF9ltOirI/lf1SCGh9hAskbnb7cIsoJL6mNii7pQ1SDSt9R7vzF3Y+/d/fPtKXHMisjbQK/U6t+3wREAuoKQ4yZ24iuw+KZ6CW9bl6ULp3nVx0B8QpueW95sw0KOtmOMpmD19nO6gkFvMohcB", password);
var decryptedHex = decryptedWordArray.toString(CryptoJS.enc.Hex); // 注意这里要用Hex
if(decryptedHex){
const isValid = await argon2.verify(targetHash, decryptedHex);
if(isValid){
console.log(`\n解密成功,密码: ${password}`);
process.exit(0);
}
}
} catch(err) {
}
}
console.log("未找到");
})();

image

1
chewhaoN@6087

35.(填空)请分析检材2Linux系统,chrome浏览器插件存放的令牌的名称为 (参考格式:abc) 分值:29

还是刚才000003.log​这个文件

1
2
3
4
5
6
7
8
9
// 令牌记录
{
"account": "chenhaoren", // 账户名
"encrypted": true, // 已加密
"hash": "58384e73-5c98-433d-87bc-165f7f0ddad6",
"index": 1,
"secret": "U2FsdGVkX1+eacsEnU0gCAZ1MQR8aoQKWZIH8oRlWkkdnsm0SrMfmXK98hBGaAqr", // 加密的TOTP密钥
"type": "totp"
}
1
chenhaoren

36.(填空)请分析检材2Linux系统,该检材Linux系统浏览器插件存放的令牌在2022-05-12 00:54:10时的令牌为 (参考格式:123456) 分值:29

先解密TOTP的秘钥

1
2
3
const masterKeyHex = CryptoJS.AES.decrypt(encryptedMasterKey, password).toString(CryptoJS.enc.Hex);
const totpSecret = CryptoJS.AES.decrypt(encryptedTotpSecret, masterKeyHex).toString(CryptoJS.enc.Utf8);
console.log("TOTP密钥:", totpSecret);

然后通过覆盖Data.now()​模拟历史时间

1
2
3
4
5
const originalDateNow = Date.now;
Date.now = () => timestamp * 1000;
const token = authenticator.generate(totpSecret);
Date.now = originalDateNow;
console.log(`token: ${token}`);

注意先npm install crypto-js otplib

34-36题脚本解题

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
const CryptoJS = require("crypto-js");
const argon2 = require("argon2");
const { authenticator } = require("otplib");

// ========== 数据 ==========
const encryptedMasterKey = "U2FsdGVkX18Tb9IA8UF4TbpMQjOs4IqZBTIkldDlgn9vw1gIF9ltOirI/lf1SCGh9hAskbnb7cIsoJL6mNii7pQ1SDSt9R7vzF3Y+/d/fPtKXHMisjbQK/U6t+3wREAuoKQ4yZ24iuw+KZ6CW9bl6ULp3nVx0B8QpueW95sw0KOtmOMpmD19nO6gkFvMohcB";
const argon2Hash = "$argon2id$v=19$m=16384,t=1,p=1$k6EZEDdQYyn+/0GlJtZGpg$hicAuwJorE73Moj+Po2Txda8hyoPPGYa";
const encryptedTotpSecret = "U2FsdGVkX1+eacsEnU0gCAZ1MQR8aoQKWZIH8oRlWkkdnsm0SrMfmXK98hBGaAqr";
const targetTime = "2022-05-12 00:54:10";

(async () => {
// ====== 1 ====== 爆破密码 ======
let password = null;

for (let i = 0; i < 10000; i++) {
const pwd = "chewhaoN@" + String(i).padStart(4, '0');
try {
const decrypted = CryptoJS.AES.decrypt(encryptedMasterKey, pwd);
const hex = decrypted.toString(CryptoJS.enc.Hex);
if (hex && await argon2.verify(argon2Hash, hex)) {
password = pwd;
console.log("密码:", password);
break;
}
} catch(e) {}
}

if (!password) {
console.log("失败");
return;
}

// ===== 2 ===== 解密TOTP秘钥 ======
const masterKeyHex = CryptoJS.AES.decrypt(encryptedMasterKey, password).toString(CryptoJS.enc.Hex);
const totpSecret = CryptoJS.AES.decrypt(encryptedTotpSecret, masterKeyHex).toString(CryptoJS.enc.Utf8);
console.log("TOTP密钥:", totpSecret);

console.log("\n步骤3: 计算历史令牌...");
const timestamp = Math.floor(new Date(targetTime).getTime() / 1000);

// 模拟历史时间
const originalDateNow = Date.now;
Date.now = () => timestamp * 1000;
const token = authenticator.generate(totpSecret);
Date.now = originalDateNow;
console.log(`token: ${token}`);
})();
1
080000

37.(填空)请分析检材3,该操作系统版本号为 (参考格式:22.01.1) 分值:16

image

1
24.04.1

38.(填空)请分析检材3,该主机名为 (参考格式:app-server-2025) 分值:16

image

1
api-server-2

39.(填空)请分析检材3,该ens33网卡IP地址为 (参考格式:192.168.1.1) 分值:19

image

1
172.16.10.254

40.(单选)请分析检材3,操作系统登录使用了第三方身份验证,该技术为 分值:19
A.pam_pwdfile
B.pam_ldap
C.Google Auth
D.pam_krb5

image

搜一下,/etc​目录里面的这个是

41.(单选)请分析检材3,该身份验证的加密算法为? 分值:23
A.Bcrypt
B.MD5
C.DES
D.AES

image

1
A

42.(填空)请分析检材3,该保存king用户密码的文件名为? (参考格式:shadow) 分值:23

image

1
my_two_factor_pwdfile

43.(填空)请分析检材3,尝试爆破king用户,其密码为(king字母加3个数字)? (参考格式:king123) 分值:23

1
2
3
4
5
6
7
import bcrypt
hash_str = "$2a$10$V/8GUI5aTNSnbFodPjP7Zu6vCFSXmvdd9oKHGtWv/vbT3Q4LLTCcW"
for num in range(1000):
password = f"king{num:03d}"
if bcrypt.checkpw(password.encode(), hash_str.encode()):
print(f"密码: {password}")
break
1
king110

44.(填空)请分析检材3,该WEB-API配置的 MySQL 数据库服务器地址为 (参考格式:192.168.1.1) 分值:23

image

1
172.16.10.200

45.(填空)请分析检材3,其中用于 WEB-API 测试的流量包文件名为 (参考格式:abc.txt) 分值:19

image

1
test.pcap

46.(填空)请分析检材3流量包,统计其中 admin 用户成功登录的次数为 (参考格式:1) 分值:23

过滤code == 200

image

点点发现前三个有登录成功​的返回

1
3

47.(填空)请分析检材3流量包,找出用户最后一次查看的商品型号为 (参考格式:kk-123) 分值:23

继续往下翻就有

image

1
hx-101

48.(填空)请分析检材3WEB-API,该容器镜像ID为(前六位) (参考格式:abc123) 分值:19

image

找到三个config.v2.json

vscode看一下,d4cb​开头的那个文件夹是web_api的docker镜像文件

image

1
996a32

49.(单选)请分析检材3WEB-API,该容器的核心服务编程语言为 分值:19
A.JAVA
B.PHP
C.NODEJS
D.C#

启动命令中有exec node index.js

1
C

50.(填空)请分析检材3WEB-API,该容器所用域名为 (参考格式:qq.com) 分值:23

根据前面test.pcap​中的访问IP进行搜索

image

1
api-server.com

51.(填空)请分析检材3WEB-API,该容器日志文件名(access_log)为 (参考格式:abc.txt) 分值:23

有提示access_log

image

1
api-server-access.log

52.(填空)请分析检材3WEB-API,该容器的FLAG2的接口URL为 (参考格式:/aaa/bbb/ccc) 分值:23

直接搜flag2

image

1
/api/auth/flag2

53.(填空)请分析检材3WEB-API,该容器的服务运行状态的接口URL为 (参考格式:/aaa/bbb) 分值:23

image

1
/api/health

54.(单选)请分析检材3WEB-API,该容器中访问FLAG2接口后,会提示需要在什么调试器下运行 分值:23
A.GDB
B.Frida
C.rr
D.Treace

image

1
A

55.(填空)请分析检材3WEB-API,该容器的admin用户的登录密码为 (参考格式:abc123) 分值:23

前面pcap已经有了

image

1
zhaohong666

56.(填空)请分析检材3WEB-API,该容器的数据库内容被SO所加密,该SO文件名为 (参考格式:abc.txt) 分值:19

直接只在这个文件夹里面搜索

image

1
libJiami.so

57.(单选)请继续分析上题SO文件,该文件的编译器类型为 分值:19
A.VC
B.DELPHI
C.GCC
D.VB

image

1
C

58.(单选)请继续分析上题SO文件,在SO文件的encrypt函数中,该加密算法为 分值:23
A.DES
B.AES-128
C.AES-192
D.AES-256

image

很明显是256

1
D 

59.(填空)请继续分析上题SO文件,尝试分析getAeskey函数,该KEY值为 (参考格式:abasdcdefghijgasdsdfsdfqwesazada) 分值:29

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
恢复 getAeskey() 函数生成的AES密钥
基于完整的C伪代码还原
"""
def recover_aes_key(xmmword_2050):
"""
根据反编译的 getAeskey() 函数逻辑恢复AES密钥

参数:
xmmword_2050: 16字节的初始值 (bytes)

返回:
(key1, key2): 两个16字节的密钥
"""
# 初始化置换表数据(从 v12-v27)
int64_constant_values = [
0xF00000002, # v12
0x1C00000000, # v13
0x900000005, # v14
0xC0000001F, # v15
0x300000014, # v16
0x1000000019, # v17
0xE00000008, # v18
0x1600000001, # v19
0x60000001B, # v20
0x120000000D, # v21
0x40000001E, # v22
0xA00000018, # v23
0xB0000001A, # v24
0x110000001D, # v25
0x1700000015, # v26
]
v27_val = 19 # v27
# v11[0..8] 是未初始化的栈变量,假设为0
mem_region_v11_parts = [0] * 9
# 将64位常量拆分为DWORD数组
constants_as_dwords = []
for val64 in int64_constant_values:
constants_as_dwords.append(val64 & 0xFFFFFFFF) # 低32位
constants_as_dwords.append((val64 >> 32) & 0xFFFFFFFF) # 高32位
constants_as_dwords.append(v27_val & 0xFFFFFFFF)
# 构建完整的DWORD视图
full_dword_view = mem_region_v11_parts + constants_as_dwords
# v9: 96字节的缓冲区
v9_data = bytearray(96)
# 初始化 v9[0] 和 v9[1]
if not isinstance(xmmword_2050, bytes) or len(xmmword_2050) != 16:
raise ValueError("xmmword_2050 必须是16字节的bytes对象")
v9_data[0:16] = xmmword_2050 # v9[0]
v9_data[16:32] = xmmword_2050 # v9[1]
# 第一个循环:填充 v9[2] 和 v9[3] (字节32-63)
v0_current_byte = 35 # 初始值
for v1_loop_idx in range(32):
v9_data[32 + v1_loop_idx] = v0_current_byte & 0xFF
v1_after_increment = v1_loop_idx + 1
if v1_after_increment == 32:
break
idx_for_v11_access = v1_after_increment + 8
v9_lookup_offset = full_dword_view[idx_for_v11_access]
if not (0 <= v9_lookup_offset < len(v9_data)):
raise IndexError(f"v9_lookup_offset {v9_lookup_offset} 越界")
v0_current_byte = v9_data[v9_lookup_offset]
# 第二个循环:构建置换数组 v28
v28_py_indices = [-1] * 32
v2_counter = 0
current_idx_for_v28_array = 7 # 初始值
while True:
if not (0 <= current_idx_for_v28_array < len(v28_py_indices)):
raise IndexError(f"current_idx_for_v28_array {current_idx_for_v28_array} 越界")
v28_py_indices[current_idx_for_v28_array] = v2_counter
v2_counter += 1
if v2_counter == 32:
break
idx_for_v11_access_v28loop = v2_counter + 8
current_idx_for_v28_array = full_dword_view[idx_for_v11_access_v28loop]
# 第三个循环:根据置换表从 v9[2] 置换到 v9[4]
for j_loop_idx in range(32):
permutation_source_offset = v28_py_indices[j_loop_idx]
if not (0 <= permutation_source_offset < 32):
raise IndexError(f"置换源偏移 {permutation_source_offset} 越界")
byte_to_permute = v9_data[32 + permutation_source_offset]
v9_data[64 + j_loop_idx] = byte_to_permute
# 第四个循环:XOR 0x44 生成 v10
v10_buffer = bytearray(32)
for k_loop_idx in range(32):
byte_from_permuted = v9_data[64 + k_loop_idx]
v10_buffer[k_loop_idx] = byte_from_permuted ^ 0x44
# 提取密钥
# key1 = v10的前16字节
v6_loaded_16_bytes = v10_buffer[0:16]
# key2 = v11的前16字节 (从full_dword_view[0:4])
v7_loaded_16_bytes_buffer = bytearray(16)
for i in range(4): # 4个DWORD = 16字节
dword_val = full_dword_view[i]
# 小端序打包
v7_loaded_16_bytes_buffer[i*4 + 0] = (dword_val >> 0) & 0xFF
v7_loaded_16_bytes_buffer[i*4 + 1] = (dword_val >> 8) & 0xFF
v7_loaded_16_bytes_buffer[i*4 + 2] = (dword_val >> 16) & 0xFF
v7_loaded_16_bytes_buffer[i*4 + 3] = (dword_val >> 24) & 0xFF
key1 = bytes(v6_loaded_16_bytes)
key2 = bytes(v7_loaded_16_bytes_buffer)
return key1, key2
def main():
xmmword_input = input("xmmword_2050: ").strip()
try:
# 尝试作为十六进制字符串解析
if len(xmmword_input) == 32 and all(c in '0123456789abcdefABCDEF' for c in xmmword_input):
# IDA显示的是大端序,需要转换为小端序
big_int = int(xmmword_input, 16)
xmmword_2050 = big_int.to_bytes(16, 'little')
else:
# 尝试作为大整数解析(little-endian)
big_int = int(xmmword_input)
xmmword_2050 = big_int.to_bytes(16, 'little')
if len(xmmword_2050) != 16:
print(f"错误: 需要16字节,但得到了 {len(xmmword_2050)} 字节")
return
print(f"\n使用的 xmmword_2050 (hex): {xmmword_2050.hex()}")
print(f"ASCII表示: {xmmword_2050}")
key1, key2 = recover_aes_key(xmmword_2050)
print("\n" + "=" * 60)
print("恢复的AES密钥:")
print("=" * 60)
print(f"密钥1 (aeskey_0): {key1.hex()}")
print(f"密钥1 ASCII: {key1.decode('ascii', errors='replace')}")
print()
print(f"密钥2 (xmmword_4190): {key2.hex()}")
print()
print(f"完整密钥 (32字节): {(key1 + key2).hex()}")
except ValueError as e:
print(f"错误: 输入格式无效 - {e}")
except Exception as e:
print(f"错误: {e}")
if __name__ == "__main__":
main()
1
2
3
4
5
6
7
8
9
============================================================
恢复的AES密钥:
============================================================
密钥1 (aeskey_0): 7a68616f686f6e677a68616f686f6e67
密钥1 ASCII: zhaohongzhaohong

密钥2 (xmmword_4190): 00000000000000000000000000000000

完整密钥 (32字节): 7a68616f686f6e677a68616f686f6e6700000000000000000000000000000000
1
zhaohongzhaohongzhaohongzhaohong

60.(填空)请继续分析上题SO文件,尝试分析get_flag1函数,该返回值为 (参考格式:abc123) 分值:26

image

1
hong112233

61.(填空)请继续分析上题SO文件,尝试分析get_flag2函数,该返回值为 (参考格式:qiang) 分值:29

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import struct

# 重新构建精确的内存布局
# 基于栈偏移:
# v8 at [rsp+0Fh]
# v9 at [rsp+17h] (相对v8 +8)
# v10 at [rsp+34h] (相对v8 +37 = 0x25)
# v11 at [rsp+3Ch] (相对v8 +45 = 0x2D)
# v12 at [rsp+44h] (相对v8 +53 = 0x35)
# v13 at [rsp+4Ch] (相对v8 +61 = 0x3D)
# v14 at [rsp+54h] (相对v8 +69 = 0x45)

mem = bytearray(100)

# v8 offset 0
v8_offset = 0
mem[v8_offset:v8_offset+8] = struct.pack('<Q', 0x484F5C1540464B41)

# v9 offset 8
v9_offset = 8
mem[v9_offset:v9_offset+3] = b'I@Z'

# v10 offset 37
mem[37:45] = struct.pack('<Q', 0x600000000)

# v11 offset 45
mem[45:53] = struct.pack('<Q', 0xA00000002)

# v12 offset 53
mem[53:61] = struct.pack('<Q', 0x700000004)

# v13 offset 61
mem[61:69] = struct.pack('<Q', 0x100000009)

# v14 offset 69
mem[69:77] = struct.pack('<Q', 0x500000008)

print("Memory layout:")
print(f"v8 (0-7): {mem[0:8].hex()} = {mem[0:8]}")
print(f"v9 (8-10): {mem[8:11].hex()} = {mem[8:11]}")
print(f"v10 (37-44): {mem[37:45].hex()}")
print(f"v11 (45-52): {mem[45:53].hex()}")
print(f"v12 (53-60): {mem[53:61].hex()}")
print(f"v13 (61-68): {mem[61:69].hex()}")
print(f"v14 (69-76): {mem[69:77].hex()}")

# 第一个循环
# for ( i = 64; ; i = *((_BYTE *)&v9[-4] + *(int *)((char *)&v9[2 * v1 + 12] + 1)) )
# {
# *((_BYTE *)&v9[1] + ++v1) = i;
# if ( v1 == 11 )
# break;
# }

sequence = [0] * 12
sequence[0] = 64 # 初始值

print("\n=== Loop 1 ===")
for v1 in range(11):
# (char *)&v9[2 * v1 + 12] + 1
# v9是__int16数组,所以v9[idx]的字节偏移是idx*2
v9_index = 2 * v1 + 12
byte_offset_in_v9 = v9_index * 2 # __int16是2字节
addr = v9_offset + byte_offset_in_v9 + 1

print(f" v1={v1}: v9[{v9_index}] at byte offset {byte_offset_in_v9}, +1 = addr {addr}")

# 从addr读取4字节int
if addr + 4 <= len(mem):
offset_val = struct.unpack('<i', mem[addr:addr+4])[0]
print(f" Read int at {addr}: {offset_val}")

# &v9[-4] = v8_offset (v9向前4个__int16 = 8字节)
# 从v8 + offset读取字节
char_addr = v8_offset + offset_val
if 0 <= char_addr < len(mem):
char_val = mem[char_addr]
sequence[v1 + 1] = char_val
print(f" v8[{offset_val}] = '{chr(char_val) if 32 <= char_val < 127 else f'\\x{char_val:02x}'}'")

print(f"\nSequence after loop 1: {[''.join([chr(b) if 32 <= b < 127 else f'\\x{b:02x}' for b in sequence])]}")
print(f"Sequence bytes: {[f'{b:02x}' for b in sequence]}")

# 第二个循环
# for ( j = 3LL; ; j = *(int *)((char *)&v9[2 * v3 + 12] + 1) )
# {
# v15[j] = v3++;
# if ( v3 == 11 )
# break;
# }

v15 = [0] * 14
print("\n=== Loop 2 ===")
for v3 in range(11):
v9_index = 2 * v3 + 12
byte_offset_in_v9 = v9_index * 2
addr = v9_offset + byte_offset_in_v9 + 1

if addr + 4 <= len(mem):
j = struct.unpack('<i', mem[addr:addr+4])[0]
print(f" v3={v3}: j={j}")
if 0 <= j < 14:
v15[j] = v3

print(f"\nv15 mapping: {v15}")

# 第三个循环
# for ( k = 0LL; k != 11; ++k )
# *((_BYTE *)&v9[7] + k) = *((_BYTE *)&v9[1] + v15[k] + 1);

reordered = [0] * 11
print("\n=== Loop 3 ===")
for k in range(11):
# *((_BYTE *)&v9[1] + v15[k] + 1) 表示 sequence[v15[k] + 1]
source_idx = v15[k] + 1
reordered[k] = sequence[source_idx]
print(f" k={k}: v15[{k}]={v15[k]}, source_idx={source_idx}, char='{chr(sequence[source_idx]) if 32 <= sequence[source_idx] < 127 else f'\\x{sequence[source_idx]:02x}'}'")

print(f"\nReordered: {''.join([chr(b) if 32 <= b < 127 else f'\\x{b:02x}' for b in reordered])}")

# 第四个循环
# for ( m = 0LL; m != 11; ++m )
# v0[m] = *((_BYTE *)&v9[7] + m) ^ 0x27;

result = bytearray()
print("\n=== Loop 4 (XOR 0x27) ===")
for m in range(11):
xored = reordered[m] ^ 0x27
result.append(xored)
print(f" m={m}: {reordered[m]:02x} ^ 27 = {xored:02x} ('{chr(xored) if 32 <= xored < 127 else f'\\x{xored:02x}'}')")

print(f"\n{'='*50}")
print(f"FINAL FLAG2: {result.decode('ascii', errors='replace')}")
print(f"{'='*50}")
1
FINAL FLAG2: flaf2{hong}
1
hong

62.(填空)请继续分析上题SO文件,尝试分析decrypt函数,该密文dnJXwBR4qc+1Y4WB6ZxR0A==的明文为 (参考格式:abc123) 分值:29

image

image

1
FICerisgood

63.(填空)请分析检材3数据库,在 products 表中,统计商品型号的种类数量(例如以 ZK、CW 等为前缀的型号) (参考格式:1) 分值:26

image

image

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
import re
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

with open('products.ibd', 'rb') as f:
data = f.read()

all_enc = re.findall(rb'([A-Za-z0-9+/]{16,}==)', data)

def decrypt(enc_b64, key, iv):
try:
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(base64.b64decode(enc_b64)), 16)
return decrypted.decode('utf-8')
except:
return None

pattern = re.compile(r'([a-z]+)-\d+', re.IGNORECASE)
prefixes = set()

for i in all_enc:
decrypted = decrypt(i.decode('utf-8'), b'zhaohongzhaohongzhaohongzhaohong', b'0123456789012345')
if decrypted:
match = pattern.search(decrypted)
if match:
prefixes.add(match.group(1))

print(f"种类: {sorted(prefixes)}")
print(f"共 {len(prefixes)} 种")
1
5

64.(填空)请分析检材3数据库,在 products 表中,统计型号为 “ZK” 且颜色为灰色的商品的数量 (参考格式:10) 分值:26

上一道题智能分析到一部分内容,全部的还是得把数据库启动起来看

在本地启动了一个mysql docker用来获取数据

1
2
3
4
5
6
7
8
9
10
docker run -d \
--name mysql-forensic \
-v /mnt/ssd/forensic/sql:/var/lib/mysql \ 这里直接把数据库目录导出来,然后启动docker的时候直接挂载成卷,这样docker能直接读取,就不用复制了
-e MYSQL_ALLOW_EMPTY_PASSWORD=yes \
-p 3307:3306 \
mysql:8.0 \
--skip-grant-tables

docker exec mysql-forensic mysqldump product_db > product_db_backup.sql

然后写个脚本吧.sql​转换成.xlsx

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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import pandas as pd
from pathlib import Path
def parse_sql_inserts(sql_file):
with open(sql_file, 'r', encoding='utf-8') as f:
content = f.read()
create_table_pattern = r'CREATE TABLE `(\w+)` \((.*?)\) ENGINE='
tables_structure = {}
for match in re.finditer(create_table_pattern, content, re.DOTALL):
table_name = match.group(1)
table_def = match.group(2)
column_pattern = r'`(\w+)`\s+(?:int|varchar|text|timestamp)'
columns = re.findall(column_pattern, table_def)
tables_structure[table_name] = columns
insert_pattern = r'INSERT INTO `(\w+)` VALUES (.*?);'
tables_data = {table: [] for table in tables_structure.keys()}
for match in re.finditer(insert_pattern, content, re.DOTALL):
table_name = match.group(1)
values_str = match.group(2)
row_pattern = r'\(([^)]+)\)'
rows = re.findall(row_pattern, values_str)
for row in rows:
values = []
current_value = ''
in_quotes = False
for char in row + ',':
if char == "'" and (not current_value or current_value[-1] != '\\'):
in_quotes = not in_quotes
current_value += char
elif char == ',' and not in_quotes:
value = current_value.strip().strip("'")
if value == 'NULL':
value = None
values.append(value)
current_value = ''
else:
current_value += char
if table_name in tables_data:
tables_data[table_name].append(values)
return tables_structure, tables_data
def save_to_excel(tables_structure, tables_data, output_file):
with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
for table_name, columns in tables_structure.items():
if table_name in tables_data and tables_data[table_name]:
df = pd.DataFrame(tables_data[table_name], columns=columns)
sheet_name = table_name[:31] # Excel工作表名称最多31个字符
df.to_excel(writer, sheet_name=sheet_name, index=False)
def main():
sql_files = list(Path('.').glob('*.sql'))
if not sql_files:
return
sql_file = sql_files[0]
print(f"正在处理SQL文件: {sql_file}")
output_file = sql_file.stem + '.xlsx'
try:
tables_structure, tables_data = parse_sql_inserts(sql_file)
save_to_excel(tables_structure, tables_data, output_file)
print(f"Excel文件已保存为: {output_file}")
except Exception as e:
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()

image

然后再写一个解密脚本

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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pandas as pd
from pathlib import Path
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

# 解密参数
KEY = b'zhaohongzhaohongzhaohongzhaohong'
IV = b'0123456789012345'
def decrypt_aes_cbc(encrypted_data):
if not encrypted_data or pd.isna(encrypted_data):
return encrypted_data
try:
encrypted_bytes = base64.b64decode(encrypted_data)
cipher = AES.new(KEY, AES.MODE_CBC, IV)
decrypted_bytes = unpad(cipher.decrypt(encrypted_bytes), AES.block_size)
return decrypted_bytes.decode('utf-8')
except Exception as e:
print(f"解密失败 '{encrypted_data}': {e}")
return f"[解密失败: {encrypted_data}]"
def main():
excel_files = list(Path('.').glob('*.xlsx'))
if not excel_files:
print("当前目录下无xlsx文件")
return

excel_file = excel_files[0]
try:
df = pd.read_excel(excel_file, sheet_name=0)
print(f"原始数据形状: {df.shape}")
print(f"列名: {df.columns.tolist()}\n")
decrypt_columns = df.columns[1:7] # B到G列
decrypt_rows = range(0, min(335, len(df))) # 2到335行
decrypted_count = 0
for row_idx in decrypt_rows:
for col in decrypt_columns:
original_value = df.at[row_idx, col]
decrypted_value = decrypt_aes_cbc(original_value)
if original_value != decrypted_value:
df.at[row_idx, col] = decrypted_value
decrypted_count += 1
output_file = excel_file.stem + '_decrypted.xlsx'
df.to_excel(output_file, index=False, engine='openpyxl')
print(f"解密后的文件已保存为: {output_file}")
except Exception as e:
print(f"错误: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()

image

image

1
29

65.(填空)请分析检材3数据库,在 products 表中,统计型号为 “ZK” 的总销售额(金额只保留整数部分,不进行四舍五入) (参考格式:10000) 分值:26

image

1
106450

66.(填空)请分析检材4,该检材的系统版本号为 (参考格式:1.1.1) 分值:16

image

1
24.10.0

67.(填空)请分析检材4,该检材的lan口ip为 分值:19

ipaddr

image

1
192.168.3.1

仿真后:

image

68.(填空)请分析检材4,该检材Overlayfs分区的大小为多少KB (参考格式:123) 分值:23

这个题应该是必须要仿真,df​命令是实时计算出来的

先安装qemu

1
sudo apt install qemu-system-x86 qemu-system-arm qemu-utils

E01​转换成RAW

1
ewfexport -t raw -u 检材4-路由器.E01
1
2
3
4
5
6
7
8
9
10
qemu-system-aarch64 \
-m 512M \
-cpu cortex-a57 \
-M virt \
-bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \
-drive file=raw.raw,format=raw,snapshot=on,if=none,id=hd0 \ 注意这里的raw.raw,改成刚才导出来的raw文件
-device virtio-blk-device,drive=hd0 \
-netdev user,id=net0,hostfwd=tcp::8080-:80,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=net0 \
-nographic

image

选第一个,进来即可

image

1
8292024

69.(填空)请分析检材4,该检材中VPN网络私钥为 (参考格式:Abc@123) 分值:23

image

1
SLkCLyRhrkWIFgJWfEd0B7s99FYWJf9PUV+scj3Vw3U=

70.(填空)请分析检材4,嫌疑人交代其开发了一款专门用于收集其售出摄像头信息的服务程序。请问该摄像头信息收集服务程序编译器版本为? (参考格式:1.1.1) 分值:23

前面搜openwrt搜出来了gcc

image

或者看仿真后把程序拿出来(仿真取出文件方法在下一题)

image

1
13.3.0

71.(填空)请分析检材4,该摄像头信息收集程序支持的运行参数(命令行参数)数量为多少 (参考格式:1) 分值:26

需要从qemu中把这个程序弄出来,这里采用共享文件夹方法

先使用halt​把qemu关机

然后使用如下参数的启动方式:start_qemu.sh

1
2
3
4
5
6
7
8
9
10
11
qemu-system-aarch64 \
-m 512M \
-cpu cortex-a57 \
-M virt \
-bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \
-drive file=raw.raw,format=raw,snapshot=on,if=none,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-netdev user,id=net0,hostfwd=tcp::8080-:80,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=net0 \
-virtfs local,path=./qemu_share,mount_tag=host0,security_model=none,id=host0 \ 注意这里的qemu_share文件夹,这个是宿主机的共享文件夹,需要先创建
-nographic

然后,在/mnt​创建一个文件夹/mnt/host

再挂载

1
mount -t 9p -o trans=virtio,version=9p2000.L,msize=262144 host0 /mnt/host

然后cp ~/password_collector /mnt/host

image

这样就有了

image

两个参数

1
2

72.(多选)请分析检材4,该摄像头信息收集程序使用了什么算法进行加密 分值:23
A.MD5
B.AES
C.BASE64
D.DES

main函数里有这两个

1
BC

73.(填空)请分析检材4,该摄像头信息收集程序所使用的数据库文件名为 (参考格式:abc.txt) 分值:23

image

image

1
collected.txt

74.(多选)请分析检材4,该摄像头信息收集程序收集了以下哪些摄像头信息? 分值:26
A.IP 地址
B.摄像头密码
C.备注信息
D.电话号码

这题没有collected.txt文件,被删除了,且被重新填充了,没找到怎么做

75.(填空)请分析检材5,该检材的包名为 (参考格式:aaa.bbb.ccc) 分值:19

image

1
com.forensix.cam

76.(填空)请分析检材5,该检材的签名证书 MD5 值为 (参考格式:202cb962ac59075b964b07152d234b70) 分值:19

image

1
7B1963B70FBAC57A50836E9A044D0029

77.(多选)请分析检材5,在尝试抓包登录 APP 时,登录请求中提交的参数包括:(请使用比武U盘中提供的智能家居账号密码进行登录抓包) 分值:23
A.devicename
B.password
C.id
D.flag

image

1
BCD

78.(填空)请分析检材5,通过抓包分析登录请求,获取到的 flag 参数的值为 (参考格式:abc123asd56) 分值:23

1
2
3
4
5
6
7
8
9
Java.perform(function() {
let c = Java.use("e1.c")
c["a"].implementation = function(str) {
console.log(`c.a is called: ${str}`)
let result = this["a"](str)
console.log(`c.a result: ${result}`)
return result
}
})

image

image

前十位

1
05d8cccb5f

79.(填空)请分析检材5,该 APK 登录请求中携带了一个远程调证 ID,分析该请求并提取该 ID,统计其长度为(请提取该 ID 并在比武平台中进行调证,准备进入下一阶段分析,可参考比武 U 盘中的手册) (参考格式:1) 分值:23

image

1
6

80.(填空)请分析检材5,在登录成功后,应用会跳转至 “欢迎使用 forensix” 界面。该界面对应的 Activity 类的完整类名为 (参考格式:com.bb.cc.ee.ff) 分值:26

1
2
3
4
5
6
7
8
9
10
11
12
Java.perform(function() {
globalThis.ga = function() {
Java.choose("android.app.Activity", {
onMatch: function(a) {
if (a.mResumed && a.mResumed.value) {
console.log(a.getClass().getName());
}
},
onComplete: function() {}
});
};
});

image

1
com.forensix.cam.activity.c75e3a8b2d

81.(填空)请分析检材5,分析上述 Activity 类后,发现其内部定义的 TAG 常量值为: (参考格式:999) 分值:26

找到com.forensix.cam.activity.c75e3a8b2d

image

82.(填空)请结合互联网分析APP调证检材,该检材系统版本号为(完成调证后,可参考比武 U 盘中的手册,在云实验室中继续完成取证任务) (参考格式:1.1) 分值:19

无检材

83.(填空)请结合互联网分析APP调证检材,该检材系统内FLAG值为(完成调证后,可参考比武 U 盘中的手册,在云实验室中继续完成取证任务) (参考格式:123456) 分值:23

无检材

84.(多选)请综合分析,陈某进行了那些操作 分值:23
A.VC加密Linux系统
B.VC加密Windows系统
C.VC加密文件
D.VC加密系统容器

VC加密了Windows 分区3​,加密文件为我的手机号

1
BC

85.(单选)请综合分析,陈某没有使用过以下那种方式安装数据库 分值:23
A.编译安装
B.包管理器安装
C.容器安装
D.单文件

UUID​镜像是Debian,通过apt管理,docker有一个mysql的容器,路由器的数据库是文件

1
A

86.(多选)请综合分析,陈某使用过以下那些系统 分值:23
A.Windows
B.MacOS
C.Debian
D.CentOS
E.Fedora

1
AC

87.(单选)请综合分析,以下说法正确的是
1.陈某将正确的助记词藏在了Linux中
2.陈某将正确的助记词藏在了windows中
3.陈某电子数据中保留了孙某的欠条
4.陈某电子数据中保留了王某的欠条
5.陈某使用JAVA搭建后台接口
6.陈某和“香格里拉大酒店”有关 分值:26
A.1245
B.2356
C.146
D.246
E.1235

正确的助记词应该是那个图片的隐写,应该是在Windows中

欠条在前面的我的手机号​加密文件中有,王某

后台是用Node​搭建的

香格里拉大酒店在初赛中有

1
D

88.(单选)请综合分析,陈某现有电子数据没有以下那个Linux内核版本 分值:29
A.4.14-arm
B.6.6-arm
C.4.15-x64
D.6.8-x64

Android 手机的 Linux 内核版本为 4.14-arm​.

Ubuntu 服务器的 Linux 内核版本为 6.8-x64​.

OpenWRT 的 Linux 内核版本为 6.6-arm​.

1
C

89.(填空)请综合分析,陈某做为壁纸的邪影芳灵原图的sm3值为 分值:19

image

1
2
3
4
5
6
7
8
9
python3 -c "
from gmssl import sm3

with open('tf11willow1.jpg', 'rb') as f:
data = f.read()

sm3_hash = sm3.sm3_hash(list(data))
print(sm3_hash)
")
1
0300a48e6acefef6ebc6ff64b957b42880febb66b5c807c7e3d7d3c3ccad2661

90.(填空)请结合分析,陈某的真实GitHub密码为 (参考格式:Abc123) 分值:19

image

image-20251017152731403

image-20251017152758751

这个大小跟最新的那个不一样

image-20251017153028389

1
Forensix666