签到题



flag{Welcome_to_the_3rd_JuHeXieZhi_Cup}
一、手机取证
1. 请分析检材1:手机的序列号是什么?【答案格式:AB65CDEFG6HIJKLM,字母全部大写】

火眼的基本信息基本上啥都没有搜出来,只能去系统日志里边找了
在启动日志中检索 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">serialno</font>序列号
adb\lspd\log.old\kmsg.log
adb\ksu\log\dmesg.log

最后在kmsg.log找到了,即在内核消息日志找到了序列号(确实是没在这边翻过,更多是ai想到的
AM69VKKVU4CMGELB
2. 该手机的具体型号是什么?【答案格式:小米17至尊版】

设备信息里只为我们展示了蓝牙名称,所以我们必须要去查看系统配置属性才行
直接全局检索 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">ro.product.marketname</font>、<font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">ro.product.model</font>这些可能记录手机型号的字段

全局搜索后可以在很多的属性文件及伪装机型模块中发现以上字段
所以手机型号是一加Ace 5 至尊版
3. 手机中已删除的联系人手机号码是什么?【答案格式:12345678910】
我们可以直接在火眼看被删除的联系人是谁

发现全都列出来了,就是老六,然后手机号是13696966666
或者也可以去联系人数据库里查
user\0\com.android.providers.contacts\databases\contacts2.db
直接SQL查询
select rc._id, rc.deleted, rc.display_name, m.mimetype, d.data1
from raw_contacts rc
left join data d on d.raw_contact_id=rc._id
left join mimetypes m on m._id=d.mimetype_id
where rc.deleted=1;
结果显示删除联系人老六,手机号为:
13696966666

印证了答案正确
4. 手机中找到密码本文件,计算其MD5哈希值,取后6位,字母大写。【答案格式:EF3898】
说是密码本,我们直接搜索密码看看有没有线索

发现直接就有个文件叫做常用密码,在media\0\常用密码.txt

一看发现还真是密码表,可以拿来字典爆破的那种
直接计算MD5即可

所以后六位是AD3563
5. 嫌疑人下载的图片隐写工具名称是什么?【答案格式:outguess.zip,英文小写】
说是下载的图片隐写工具了,我们去下载记录看看有没有什么线索
/media/0/Download
发现有个文件

叫steghide,明显的图片隐写工具啊
所以本题的答案就是这个文件的文件名:steghide-0.5.1-win32.zip
6. 嫌疑人使用隐写工具进行文件隐写密码是什么?【答案格式:ABCD@202002】
隐写工具解压看看

发现一个README.txt,打开发现介绍和原版的steghide一模一样
既然是steghide,还要密码,我们不难想到拿着之前那个常用密码.txt进行爆破
只差一个图片了,我们可以直接去火眼过滤的图片格式文件里边找,也可以去media/0/DCIM/Camera找
DCIM就是Digital Camera Images,这边放了很多数码相机拍的照片
我们在这边可以看见这样子一张图片

看上去就很重要啊,我们尝试爆破看看
import subprocess
img = "/mnt/data/important.jpg"
wordlist = "/mnt/data/常用密码.txt"
out_file = "result_output"
with open(wordlist, "r", encoding="utf-8", errors="ignore") as f:
for i, pwd in enumerate(f):
pwd = pwd.strip()
if not pwd:
continue
print(f"[{i}] testing: {pwd}")
r = subprocess.run(
["steghide", "extract",
"-sf", img,
"-p", pwd,
"-xf", out_file,
"-f"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
if r.returncode == 0:
print("\n[+] FOUND PASSWORD:", pwd)
print("[+] FILE EXTRACTED:", out_file)
break
爆破成功,得到了密码是JHTJ@202605,即本题答案
7. 嫌疑人向数据贩子购买公民个人信息共计多少条?【答案格式:123】
一下子问买了多少条,一般这种交易不会上交易平台
反而该去聊天软件找才是

有很多聊天软件,我们可以一个个尝试着找一下
最后在连趣这个软件里我们找到了这个数据库user\0\com.lianqujiaoyou.chat\app_flutter\OpenIM_v3_1355997814.db

先确定一下聊天双方是谁
风有约:1355997814
观云听海:1082423674
接着看看聊天内容 ** **
说的很直接啊,软件也很直接啊,都不加密,数据库聊天内容完全明文

甚至账密都是直接明文存的,可以直接仿真登录,不过这边没必要,就不演示了
盘古石要是也这样子直接就好了
所以本题答案是100
8. 嫌疑人向数据贩子交易时使用的付款方式是什么?【答案格式:支付宝】

继续看聊天记录啊,俩人说去i聊里边继续聊,那我们也去i聊看看数据库

找到数据库
data\uni.app.UNI04963C4\files\1600123285_3137373036323233393731\msg_0.db
** ** 可以看到很明显啊,说的是银行卡,所以本题答案是银行卡
9. 数据贩子交易过程中提供的银行卡号是多少?【答案格式:6222351234482925678】

** 工商银行卡号:6222355973482923738**
10. 接上题,嫌疑人所使用聊天工具的用户 ID 是多少?【答案格式:12345】
接上题的话我们用的还是i聊这个软件
记得一开始从连趣到i聊的时候,数据贩子让嫌疑人发了一张二维码

我们来定位一下这个二维码openim_media_cache_4b8966d3-242a-4c1e-a2e3-8bd7168c9236.jpg

扫扫看

{"type":"personal","userID":"17706223971","nick":"搁浅","timestamp":1778574712018}
因此聊天工具实际用户 ID 为17706223971** **
11. 嫌疑人使用浏览器访问了该下载链接,该浏览器对应的包名是什么?【答案格式:com.heytap.market】
肯定是接着上几题在说
说什么浏览器访问了下载链接

根据题目的意思,应该就是这些数据,已经被加密传到了百度网盘,而且密码是手机号,而嫌疑人是用浏览器先访问的,访问完了用的网盘下载

在连趣的配置文件处,把手机号也直接明文存储了,所以我们可以知道密码应该就是17706223971
来找一下看看,我们最后可以用17706223971当作密码验证一下

然而浏览器还不少,我们一个个看看
最后发现在鲁班浏览器有很多百度网盘下载痕迹

剩下两个显然没有,所以我们确定了本文的答案是com.meiit.browser
12. 嫌疑人于何时下载数据商人发送的数据压缩包文件?【答案格式:2022-02-02 12:00:00】
很明确是百度网盘里下的了,所以我们先定位一下百度网盘的数据库位置
user\0\com.baidu.netdisk\databases\7045389826filelist.db

发现表 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">download_tasks</font> 中记录了这个数据.zip的下载详情

得到下载的时间戳,dcode转换为北京时间即可

所以是2026-05-12 17:00:05
13. 接上题,该压缩包的解压密码是什么?【答案格式:根据实际值填写】
接上题,我们已经确定了压缩包是数据.zip

而且我们也知道了密码就是手机号17706223971

所以这题答案就是17706223971,我们可以试着解密验证一下

直接索引找到解密试试看
发现成功解密压缩包
所以这题的答案是17706223971
14. 接上题,年龄在 40 至 60 岁(含 40、60 岁)的富豪共有多少人?【答案格式:123】
我们上一题已经找到确定了Excel表,有一栏就是年龄,直接筛选即可
=SUMPRODUCT((--F2:F100>=40)*(--F2:F100<=60))
得到一共46个人
15. 请找出嫌疑人筛选的重点客户名单,并统计名单内共有多少人?【答案格式:1】
跳的有点远,我们在第六题不是steghide爆破出了密码吗,解密出了一个文件
打开发现存在 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">重点客户.xlsx</font>

但是显示了文件损坏

发现主要是ZIP数据流尾部截断
虽然只有外层 ,但关键的 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">xl/worksheets/sheet1.xml</font> 与 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">xl/sharedStrings.xml</font> 可恢复
import struct
import zlib
import re
import xml.etree.ElementTree as ET
path = "1.zip"
data = open(path, "rb").read()
# 1. 找外层 ZIP 本地文件头
idx = data.find(b"PK\x03\x04")
if idx == -1:
raise Exception("找不到 PK\\x03\\x04")
outer = data[idx:]
nlen = struct.unpack_from("<H", outer, 26)[0]
elen = struct.unpack_from("<H", outer, 28)[0]
dstart = 30 + nlen + elen
# 2. 解外层 deflate,尾部截断没关系,能解多少算多少
d = zlib.decompressobj(-15)
xlsx_data = d.decompress(outer[dstart:], max_length=200000)
print("恢复出的内层 xlsx 数据长度:", len(xlsx_data))
print("外层是否完整:", d.eof)
files = {}
# 3. 扫内层 xlsx 的本地文件头
off = 0
while off < len(xlsx_data) - 30:
pos = xlsx_data.find(b"PK\x03\x04", off)
if pos == -1:
break
method = struct.unpack_from("<H", xlsx_data, pos + 8)[0]
csize = struct.unpack_from("<I", xlsx_data, pos + 18)[0]
nlen = struct.unpack_from("<H", xlsx_data, pos + 26)[0]
elen = struct.unpack_from("<H", xlsx_data, pos + 28)[0]
name_start = pos + 30
name = xlsx_data[name_start:name_start + nlen].decode("utf-8", errors="ignore")
dstart = name_start + nlen + elen
dend = dstart + csize
# 不完整的文件直接跳过
if dend > len(xlsx_data):
off = pos + 4
continue
raw = xlsx_data[dstart:dend]
if method == 8:
try:
raw = zlib.decompress(raw, -15)
except Exception:
off = dend
continue
files[name] = raw
off = dend
print("已恢复文件:")
for k in files:
print(" ", k)
shared_xml = files.get("xl/sharedStrings.xml")
sheet_xml = files.get("xl/worksheets/sheet1.xml")
if not shared_xml or not sheet_xml:
raise Exception("没有恢复出 sharedStrings.xml 或 sheet1.xml")
# 4. 解析 sharedStrings
strings = re.findall(r"<t[^>]*>(.*?)</t>", shared_xml.decode("utf-8", errors="ignore"), re.DOTALL)
# 5. 解析 sheet1
root = ET.fromstring(sheet_xml)
ns = {"a": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
def col_index(cell_ref):
m = re.match(r"([A-Z]+)", cell_ref)
col = m.group(1)
num = 0
for ch in col:
num = num * 26 + ord(ch) - ord("A") + 1
return num - 1
rows = []
for row in root.findall(".//a:row", ns):
arr = []
for c in row.findall("a:c", ns):
ref = c.attrib.get("r", "")
idx = col_index(ref) if ref else len(arr)
while len(arr) <= idx:
arr.append("")
t = c.attrib.get("t")
v = c.find("a:v", ns)
if v is None:
arr[idx] = ""
continue
val = v.text or ""
if t == "s":
arr[idx] = strings[int(val)]
else:
arr[idx] = val
rows.append(arr)
# 6. 打印表格
for row in rows:
print("\t".join(row))

最后恢复出名单里5个人
所以答案是5
看https://mp.weixin.qq.com/s/3lok6N3tVoqHR59AqXgw1g又学到一些吼吼吼
这边其实是分卷解压,我们搜索重点客户

可以在计算机检材的回收站搜到这样子一个zip,这是主卷,只需将刚刚的1.zip改成同名,放在同一个目录下双击这个zip文件就会自动拼起来解压


**即可成功打开,确认是5人 **
二、计算机取证
1.请分析检材2:密码连续错误输入多少次数后,系统会自动锁定用户账户?【答案格式:1】
算是基础题吧,多少次自动锁定
我们可以在cmd输入net accounts查看

可以看到锁定阈值是3
其次我们也可以去账户策略看看,在Win+R输入gpedit.msc

所以答案是3
2.请分析检材2:检材中对应的微信 wxid 是多少?【答案格式:wxid_1a2b3c4d5e6f】
这边分析检材并没有分析出微信,甚至都分析结果里安装软件都没有微信,怀疑是下完删掉了
我们只能在这边直接搜索wxid
找到了这样子一个文件夹

所以本题的wxid应该是wxid_q1w2e3r4t5y6u7i8o9
3.请分析检材2:E盘 BitLocker 恢复密钥末尾六位是多少?【答案格式:616912】
上一题我们说到微信文件夹

双击进入后发现了MsgAttach下有两张AI图片



扫码发现这俩二维码全能解析出恢复密钥

但是咖啡那个不全,少了6位,所以正确答案应该是清单(8)里边这个
所以最后几位是126269
尝试用这个去解开E盘的BitLocker

填入恢复密钥即可

发现成功恢复,所以验证答案正确为126269
4.请分析检材2:VC加密容器的外层加密卷密码是什么?【答案格式:根据实际值填写】
翻一下电脑很容易发现D盘有一个1.png

一个png文件只有66字节,明显不是图片,是文本,我们直接notepad打开

成功找到外层加密卷的密码
JHTJ!@#¥A313

同目录还有个1,无后缀且大小1.00GB,很像加密容器

将密码填入后显示类型常规,确认是VC外层密码,本题答案是JHTJ!@#¥A313
这边打开空空倒是少见,一般都会有点啥吧,还尝试恢复,结果发现就是没东西
5.请分析检材2:带有“豆包AI生成”水印的图片一共有多少张?【答案格式:1】

在图片一栏下看见了4张有这个水印的
但不止
刚刚第三题的那两张也是有豆包水印的

所以本题答案应该是6
6.请分析检材2:VC加密容器的隐藏加密卷密码是什么?【答案格式:根据实际值填写】
上一题让我们找了豆包水印的,想了想应该是不会白找

发现3.png在blue plane 0下是一个二维码


得到这样子一串字符,怀疑是隐藏层密码,但是打不开,比赛的时候猜的,结果真是这个,至于为什么打不开隐藏卷呢,是因为这边需要组合使用

应该想到是这个钥匙不会0作用,我们需要将其作为密钥文件,再填入密码ClearSky@SecretSignal#SevenMileJasmine,才能解开隐藏卷


发现成功解开了隐藏卷,确认密码的确是ClearSky@SecretSignal#SevenMileJasmine
7.请分析检材2:接上题,嫌疑人的接头暗号是什么?【答案格式:根据实际值填写】

解开发现有很多文件,尤其是密钥和一个叫做隐藏信号的音频

密钥写了 ⊕ 是拿来异或的,暂时应该是用不上
继续看这个隐藏信号的音频,怀疑是音频隐写

用Audacity打开

拖入文件后右键选择频谱图看看

发现了接头暗号:步行9千米
8.请分析检材2:接上题,嫌疑人的接头地点在哪里?【答案格式:天津117大厦201室】
接下来来继续深究一下这个异或 ⊕ 的密钥图片是干什么用的
跟这一串二进制有联系的线索有什么呢?

明显是图片中的这四个画着二进制的图片了
我们只需要把这四张图里的二进制按5 -> 6 -> 7 -> 8 顺序拼起来,然后每个字节和密钥 11011010 做异或就好啦
key = int("11011010", 2)
binary_data = [
"10001110", "10111011", "10110011", "10101010", "10111111", "10110011", "11111010",
"11101011", "11101010", "11101011", "11111010", "10111000", "10101111", "10110011",
"10110110", "10111110", "10110011", "10110100", "10111101", "11111010", "11101111",
"11101010", "11101000", "11111010", "10101000", "10110101", "10110101", "10110111",
]
result = bytes(int(x, 2) ^ key for x in binary_data)
print(result.decode("utf-8"))
得到Taipei 101 building 502 room
所以街头地点是台北101大厦502室
9.请分析检材2:木马残留样本中,核心信息窃取配置数量为多少?【答案格式:1】
这个得回到我们之前第三题解开的E盘里
在这边我们看见了有一个c文件

打开来发现是一个木马残留文件
写了很多的危险函数,虽然这些函数都没有被main函数调用,比如
CheckForDebugger()
WriteRegistryPersistence()
CreateLogFile()
WriteLogEntry()
CleanupFiles()
InitNetwork()
ConnectToC2()
SimulateProcessInjection()
确认是这个文件之后看看核心信息窃取配置数量为多少
发现主要是这样子五个


1,g_KEYLOG_PATH ** **键盘记录器,路径是 keylog.dat
2,g_BROWSER_DB ** **浏览器凭据,值是 "Login Data"
3,g_COOKIE_DB ** **Cookie 窃取,值是 "Cookies"
4,g_SCREENSHOT_DIR ** **屏幕截图目录
5,SimulateProcessInjection() ** **进程注入窃取
所以本题答案是5
10.请分析检材2:木马残留样本中,申请的内存保护标志是什么?【答案格式:PAGE_READWRITE (0x04)】
继续审计代码

在SimulateProcessInjection里找到了这一段
可以看到这边VirtualAllocEx的参数就写了内存保护属性
PAGE_EXECUTE_READWRITE (0x40) ,即可读可写可执行
**这个宏在Windows的内存保护常量里就对应0x40,所以答案是PAGE_EXECUTE_READWRITE (0x40) **
11.请分析检材2:嫌疑人涉案交易使用的银行卡号是什么?【答案格式:纯数字】

在文档下我们可以看到有一个交易银行卡.xlsx的文件,还有个密码

不过密码很狡猾啊,没有直说,给了一些爆破规则,卡了很多人的应该是这边的4个字母前缀其实是大写前缀(

为了减少爆破次数,可以尝试这个时间是20260512

然后这样子设置掩码就会爆破的快一些(也快不到哪去,慢的很,借一下yc哥的图

得到密码是JUHE@20260512
当然用hashcat也可以啦
还有我们ai也可以()


打开来就一个内容,银行卡就是6221882234367490125
12.请分析检材2:AI 换脸图片大概率使用的 AI 模型是哪一个?【答案格式:根据实际值填写】

AI换脸图片很容易找到,主要是找模型
没什么好的思路,我是觉得应该是在检材内部然后有一个AI换脸软件再找模型
但是这边明显没有什么模型或AI换脸软件
而且题目说什么“大概率”,也有点怪
或许真的是这样子做的吧,跟着钟师傅做一下
这边拿出来就是reve最高,在里边就是steadydancer最高,我觉得有点牵强(


有点奇怪的题目
13.请分析检材2:萤小石的身份证号码是什么?【答案格式:纯数字】

在D盘很容易找到萤小石的身份证,但是显然这图片有点问题
还有一个身份证的压缩包

但是要密码

发现这是伪加密啊,我们定位504B0102,把这个9改掉就好了
向大家推荐Mitunlny的深入理解zip伪加密
https://czxh.top/posts/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3zip%E4%BC%AA%E5%8A%A0%E5%AF%86/

解开发现就有完整的身份证了,所以走前边那个坏的那条路有点麻烦
但是这身份证没露照片,发现竟然藏在文件尾了

所以是330122199801209527
14.请分析检材2:小众通联工具绑定的手机号码为多少?【答案格式:纯数字】
回到一开始解密完E盘

这边有一个ldbk文件,这是雷电模拟器镜像文件

我们在雷电多开器选择还原,主要这边要64位的

可以发现还原出的有一个i聊,这应该就是题目所说的小众通联工具了,但是不知道账密,还要叫我更新,似乎仿真不太方便
这个时候我们可以直接把ldbk文件的后缀改成7z,本质7z


直接提出来扔到火眼当镜像就可以了

就可以分析出我们的数据库了

在i聊数据库中找到了萤小石对应的手机号

根据这个可以确认这个小众通联工具绑定的手机号就是18136091921
15.请分析检材2:小众通联工具添加好友的具体时间是什么?【答案格式:2025-01-01 01:01:01】

回到上一题的这个im.db
这边我们可以看到userinfo

对于搁浅有一个add_time:1778659957

解密得到是2026-05-13 16:12:37
16.请分析检材2:挖矿程序(请勿在本地运行)的版本是什么?【答案格式:1.00.1】

在用户痕迹里边可以发现有一个可疑程序timo
追踪到这个程序C:/Windows/windows/timo


发现同目录的config.json写了XMR矿池地址,符合下一题说的门罗币
再分析一下timo.exe坐实一下看看

查看字符串非常符合XMR挖矿特性

所以看这个的版本号就是了
所以答案是6.26.0
17.请分析检材2:门罗币钱包地址后6位是什么?【答案格式:根据实际值填写】

刚刚已经找到了钱包地址了,所以后六位是6soTWp
三、服务器取证
1.请分析检材3:服务器的内核版本号是多少?【答案格式:4.25.0】

火眼能直接看见内核版本号是3.10.0-514.el7.x86_64
或者也可以先火眼仿真,毕竟迟早要仿真的
ifconfig
systemctl status sshd

ip有,ssh开着,很正常啊
直接ssh连接

成功连接,查看内核版本
uname -a

所以本题答案为3.10.0
2. 请分析检材3:嫌疑人将某普通用户加入特殊用户组,赋予其读取 /etc/shadow 的权限,请问该普通用户的用户名是什么?【答案格式:admin】
简而言之,我们只需要看看/etc/shadow的访问控制列表就好了
这边可疑使用getfacl这个命令
getfacl /etc/shadow

发现把普通用户ahao给了读的权限
所以本题答案是ahao
3. 请分析检材3:分析嫌疑人所使用的 Web 服务器,其具体名称及主版本号是什么?【答案格式:apache/2.40】
查服务先
netstat -antp
看到了nginx

所以Web服务器应该是nginx搭建的
查一下版本号即可
nginx -v

所以答案是nginx/1.20
4. 请分析检材3:嫌疑人借助 AI 部署 “守卫” 脚本,非管理员 IP 登录时将触发定时强制登出,该服务每隔几分钟触发一次?【答案格式:10】
ps aux
先去进程里找这个守卫

找到一个很像的,我们cat一下
[root@localhost ~]# cat /usr/local/bin/network-check.py
# -*- coding: utf-8 -*-
import os
import subprocess
import time
# --- 题目核心配置 ---
ALLOWED_IP = "192.168.203.100" # 嫌疑人预设的安全IP
CHECK_INTERVAL = 30 # 检查间隔(秒)
KICK_DELAY = "5 minutes" # 触发后延迟时间:5分钟
def get_current_logins():
"""获取当前所有登录用户的 IP 和 TTY 终端"""
logins = []
try:
# 执行 who 命令获取当前登录信息
process = subprocess.Popen(['who'], stdout=subprocess.PIPE)
output, err = process.communicate()
lines = output.decode('utf-8').splitlines()
for line in lines:
parts = line.split()
if len(parts) >= 2:
user = parts[0]
tty = parts[1]
ip = "unknown"
# 提取括号中的 IP 地址
for p in parts:
if '(' in p and ')' in p:
ip = p.strip('()')
logins.append({'user': user, 'tty': tty, 'ip': ip})
except:
pass
return logins
def is_job_exists(tty):
"""逻辑去重:检查 at 任务池中是否已存在针对该终端的任务"""
try:
# 扫描 at 任务池目录 /var/spool/at/
at_dir = "/var/spool/at/"
if os.path.exists(at_dir):
for f in os.listdir(at_dir):
file_path = os.path.join(at_dir, f)
if os.path.isfile(file_path):
with open(file_path, 'r') as content:
# 如果任务脚本中已包含该 tty 编号,说明已排队
if tty in content.read():
return True
except:
pass
return False
def trigger_kickout(tty):
"""触发踢人逻辑"""
if is_job_exists(tty):
return # 已存在任务则跳过,避免重复添加
# 使用 pkill 强制杀死指定终端的所有进程
kick_cmd = "pkill -9 -t {}".format(tty)
# 调用 at 命令,并将所有输出重定向到黑洞,防止产生系统邮件
os.system('echo "{}" | at now + {} > /dev/null 2>&1'.format(kick_cmd, KICK_DELAY))
if __name__ == "__main__":
while True:
current_users = get_current_logins()
for u in current_users:
# 逻辑判定:非安全IP 且 是远程终端(pts)
if u['ip'] != ALLOWED_IP and 'pts' in u['tty']:
trigger_kickout(u['tty'])
time.sleep(CHECK_INTERVAL)
发现确实是这个

每隔5分钟一次,答案是5
5. 请分析检材3:计算服务器内数据库备份文件,计算其SHA256哈希值,取后6位,字母大写。【答案格式:6DEF38】
在/tmp/db_backup这个备份路径下发现了备份文件

但都几乎是空的,没什么内容
还有/opt/faka.sql,发现也不全
只有解开了计算机的Bitlocker才会发现真正的sql备份文件在E盘


接着计算SHA256即可,得到最后六位大写为FF8180
6. 请分析检材3:MySQL 数据库 root 用户的登录密码是什么?【答案格式:根据实际值填写】
先找到核心网页业务

在/usr/share/nginx/html/fk
发现配置文件config.php
<?php
/*数据库配置*/
$dbconfig=array(
"host" => "192.168.203.155", //数据库服务器
"port" => 3306, //数据库端口
"user" => "root", //数据库用户名
"pwd" => "Root@123456", //数据库密码
"dbname" => "fk", //数据库名
"dbqz" => "shua" //数据表前缀
);
得到密码明文存储:Root@123456
7. 请分析检材3:外挂网站所对外开放的端口号是多少?【答案格式:1234】

查服务的时候就看见对外端口号是8081了
8. 请分析检材3:嫌疑人为上传大型恶意插件修改文件上传限制,其最大上传限制是多少?【答案格式:100M】
上传限制,还是php网站,所以我们想到去看看php.ini或者看看nginx的配置文件nginx.conf

在/etc/php.ini里面找到了答案,最大上传限制是60M
9. 请分析检材3:嫌疑人设置数据库定时自动备份并上传至境外,请问该境外服务器的IP地址是多少?【答案格式:8.8.8.8]】
定时任务,我们自然是先看定时任务了,直接
crontab -l

找到了定时自动备份脚本,看看有没有写怎么上传到国外的
[root@localhost conf.d]# cat /etc/cron.daily/autobackup.sh
ER="root"
DB_PASSWORD="Root@123456"
DB_NAME="fk"
REMOTE_USER="root"
REMOTE_SERVER="8.208.44.202"
REMOTE_DIR="/root/"
BACKUP_DIR="/tmp/db_backup"
# ====================================================================
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.sql.gz"
mkdir -p ${BACKUP_DIR}
if mysqldump -h 127.0.0.1 -u${DB_USER} -p${DB_PASSWORD} \
--single-transaction --set-gtid-purged=OFF \
--routines --triggers --events \
${DB_NAME} | gzip > ${BACKUP_FILE}; then
echo "$(date) - 数据库备份成功:${BACKUP_FILE}"
else
echo "$(date) - 数据库备份失败!" >&2
exit 1
fi
# 需要配置 ssh-copy-id 以实现免密登录
if scp -o StrictHostKeyChecking=no ${BACKUP_FILE} ${REMOTE_USER}@${REMOTE_SERVER}:${REMOTE_DIR}; then
echo "$(date) - 文件上传至 ${REMOTE_SERVER} 成功"
rm -f ${BACKUP_FILE}
ssh ${REMOTE_USER}@${REMOTE_SERVER} "find ${REMOTE_DIR} -name '${DB_NAME}_*.sql.gz' -type f -mtime +30 -delete"
else
echo "$(date) - 文件上传至 ${REMOTE_SERVER} 失败!" >&2
exit 1
fi
exit 0
写的很明确了
REMOTE_SERVER="8.208.44.202"
所以答案就是8.208.44.202
10. 请分析检材3:嫌疑人登录后台的目录路径是什么?【答案格式:/abc/abc】
跟网站结构有关,我们看看网站结构
还是到/usr/share/nginx/html/fk这边
find /usr/share/nginx/html/fk/ -name "login.php"

发现admin/login.php 和 static/login.php都存在


php里边还都说自己是后台
不确定是哪一个,但是/fk/static这个还写了独立的密码盐,更有可能一些,最后确定可以看访问日志
zcat -f /var/log/nginx/access.log* | awk '$7 ~ /\/fk\/(static|admin)\/login/ {print $7}' | sort | uniq -c | sort -rn

发现了/fk/static访问的多,更可能是真正的后台登录页面
11. 请分析检材3:访问后台登录页面次数最多的 IP 地址是什么?【答案格式:192.168.1.1】
这题明显就是要看访问后台登录的日志了
我们去nginx access.log看看
上题确定了后台是/fk/static/login.php,所以看看访问/fk/static/login.php的情况
zcat -f /var/log/nginx/access.log* | awk '$7 ~ /\/fk\/static\/login\.php/ {cnt[$1]++} END {for (ip in cnt) print cnt[ip], ip}' | sort -rn | head -5

所以答案是192.168.203.135
(虽然如果我们同时计算后台是static和admin的情况答案是一样的,但是上题都确定了是这一个,然后这题又把俩都纳入统计范围,感觉很怪,所以我这边只统计了static的)
12. 请分析检材3:网站后台管理员的明文密码为多少?【答案格式:根据实际值填写】
后台管理员的明文密码,我们之前在计算机E盘已经拿到了数据库的备份文件了
尝试打开这个备份文件看看
这边很奇怪,我连接着服务器的数据库导入不进去,但是可以导入到我本地的mysql里,可能是mysql的版本问题,所以我们就直接导入本地的mysql看看吧,主要也只是看看内容

先新建一个faka的数据库


然后直接创建就可以了
然后我们运行一下这个sql文件


成功导入,打开看看

在config里边看见了密码,但是是哈希
我们在后台登录php看见了是加盐的

即sha256(密码+"2025baofu!")
所以开始爆破
hashcat -m 1410 -a 0 '94bd34e3010a6468f312eafe359e9d926fc16bba62c0b6cf646d041a5c281bf2:2025baofu!' rockyou.txt --potfile-disable --outfile-format 2,3 --status --status-timer 5

得到密码是abc123456
13. 请分析检材3:该网站支付接口所对接的第三方接入商名称是什么?【答案格式:根据实际值填写】

在备份数据库可以看到payapi对应的是13
我们去set.php找一下这个对应哪一家

发现有混淆,需要解一下
import re
import sys
from pathlib import Path
def php_int(s):
s = s.strip()
if s.lower().startswith("0x"):
return int(s, 16)
# PHP 里 01042 这种是八进制
if len(s) > 1 and s.startswith("0") and re.fullmatch(r"[0-7]+", s):
return int(s, 8)
return int(s, 10)
def decode_hex(hx):
try:
return bytes.fromhex(hx).decode("utf-8", errors="ignore")
except Exception:
return ""
def find_big_explode_array(src):
# 匹配 call_user_func_array("explode",array("分隔符","内容"))
pattern = re.compile(
r'explode",array\("(?P<sep>.*?)","(?P<data>.*?)"\)\)',
re.S
)
candidates = []
for m in pattern.finditer(src):
sep = m.group("sep")
data = m.group("data")
parts = data.split(sep)
if len(parts) > 20:
candidates.append((len(parts), m, sep, data))
if not candidates:
raise RuntimeError("没找到主要的 explode 十六进制数组")
# 选最大的一组,一般就是主混淆数组
_, m, sep, data = max(candidates, key=lambda x: x[0])
return m, sep, data
def main():
if len(sys.argv) < 2:
print("用法: python3 deob_setphp.py set.php")
sys.exit(1)
in_file = Path(sys.argv[1])
src = in_file.read_text(encoding="utf-8", errors="ignore")
m, sep, data = find_big_explode_array(src)
# 1. 解出所有字符串块
arr = []
for hx in data.split(sep):
arr.append(decode_hex(hx))
strings_file = in_file.with_suffix(".strings.txt")
with strings_file.open("w", encoding="utf-8", errors="ignore") as f:
for i, text in enumerate(arr):
if text.strip():
f.write(f"\n===== INDEX {i} =====\n")
f.write(text)
f.write("\n")
# 2. 尝试还原 echo pack(...) 拼出来的代码
pack_pat = re.compile(
r'call_user_func_array\("pack",array\([^)]*?\)\);echo\s+\$U4jeF0;',
re.S
)
idx_pat = re.compile(
r'U4jcV2\s*(?:=&|=)\s*\$GLOBALS\[B0000BB00\]\[([^\]]+)\]'
)
out = []
last = m.end()
for pm in pack_pat.finditer(src, m.end()):
block = src[last:pm.start()]
idxs = idx_pat.findall(block)
if idxs:
idx = php_int(idxs[-1])
if 0 <= idx < len(arr):
out.append(arr[idx])
last = pm.end()
deob_file = in_file.with_suffix(".deobf.php")
deob_text = "".join(out)
deob_file.write_text(deob_text, encoding="utf-8", errors="ignore")
print(f"[+] 已输出还原代码: {deob_file}")
print(f"[+] 已输出全部字符串: {strings_file}")
# 3. 自动找 value=13 对应项
corpus = deob_text + "\n".join(arr)
found = False
for mm in re.finditer(r'<option\s+value=["\']13["\']>(.*?)</option>', corpus):
print(f"[+] 找到 value=13 对应: {mm.group(1)}")
found = True
if not found:
print("[!] 没自动找到 value=13,可以手动 grep:")
print(f" grep -n 'value=\"13\"' {strings_file}")
if __name__ == "__main__":
main()
[+] 已输出还原代码: set.deobf.php
[+] 已输出全部字符串: set.strings.txt
[+] 找到 value=13 对应: 无忧支付
解混淆一下就好了,找到value=13对应的是无忧支付
注意这边要看的是实际接入商配置,所以是这个,不是彩虹易支付
14. 请分析检材3:网站的创建时间是什么时候?【答案格式:2026/5/20】

在数据库可以直接看见是2018/12/14
15. 请分析检材3:网站Git配置信息中,找出作者姓名是什么?【答案格式:根据实际值填写】
一开始是想直接在网站的备份配置文件找

解base64得到了GhostOperator,但这是错误干扰答案

在历史命令bash_history里边我们可以看见git相关命令
发现给藏到这边去了"/usr/share/icons/hicolor/48x48/apps/... "
我们去看看

发现了git.txt文件,这才是真的
name=576d6868626d6454595735665532566a

解码得到用户名其实是ZhangSan_Sec
16. 请分析检材3:分析该网站 2025 年 6 月 1 日至 12 月 31 日的全部订单,其中状态为 "已完成" 的订单总成交金额为多少?【答案格式:1234】
数据分析题,没什么好说的,备份数据库都找到了,直接SQL查询即可
SELECT
SUM(money) AS total_amount
FROM
shua_orders
WHERE
status = 1
AND addtime >= '2025-06-01'
AND addtime <= '2025-12-31 23:59:59';

所以答案为24073
17. 请分析检材3:分析 2025 年全年的订单数据,计算下单金额总计最高的那一天的总金额是多少?【答案格式:1234】
还是数据分析
SELECT
DATE(addtime) AS order_date,
SUM(money) AS daily_total
FROM
shua_orders
WHERE
YEAR(addtime) = 2025
GROUP BY
DATE(addtime)
ORDER BY
daily_total DESC
LIMIT 1;

所以答案是5442
18. 请分析检材3:统计全部订单数据,购买数量累计最高的应用名称是什么?【答案格式:根据实际值填写】
依旧数据分析,Jerry狂喜
SELECT
t.name AS app_name,
SUM(o.value) AS total_quantity
FROM
shua_orders o
LEFT JOIN
shua_tools t ON o.tid = t.tid
WHERE
t.name IS NOT NULL
GROUP BY
t.name
ORDER BY
total_quantity DESC
LIMIT 1;

最高的是无畏契约自动扳机+透视+准星辅助
19. 请分析检材3:统计全部订单数据,用户累计购买总额最高的用户账号是哪个?【答案格式:admin】
SELECT
s.user AS username,
t.total_spent
FROM
shua_site s
INNER JOIN (
SELECT
userid,
SUM(money) AS total_spent
FROM
shua_orders
GROUP BY
userid
ORDER BY
SUM(money) DESC
LIMIT 1
) t ON s.zid = t.userid;

最高的guoqi这个账号
20. 请分析检材3:嫌疑人创建的拥有 FILE 与 SUPER 权限的隐蔽 MySQL 账户,其用户名是什么?【答案格式:admin】
这下要回到獬豸杯自己的数据库了
我们在Navicat连接一下
首先是打通ssh隧道

这边用的是服务器密码123456
之后再去连接数据库,就像我们之前在配置文件看到的那样

密码是Root@123456

这边的密码就是Root@123456了
连接之后就好做了,又是数据分析其实()
SELECT
User,
Host,
Super_priv,
File_priv
FROM
mysql.user
WHERE
User LIKE '_tmp%'
AND Super_priv = 'Y'
AND File_priv = 'Y';
同时筛选这两个都有的,都是Y的就好了

所以是_tmp_z5m1w8
当然也可以直接在服务器做啦
mysql -uroot -p'Root@123456' -e "SELECT User,Host,File_priv,Super_priv FROM
mysql.user WHERE File_priv='Y' AND Super_priv='Y';"

也能得到是_tmp_z5m1w8
四、逆向分析
1. 样本中的 C2 地址与端口分别是多少?【答案格式:127.0.0.1:8080】
拿到样本,是一个exe文件


放入IDA看看,可以很快发现样本中存在着大量的PyInstaller特征文件和字符串
或者直接跳到main函数,继续步入

也写的很明确,因此不难判断本样本是由PyInstaller打包
因此我们可以先使用Pyinstxtractor解包
python3 pyinstxtractor.py EduRATSample.exe

解包的时候还推测出了可能是程序入口点,可以看到这个edu_ratsample.pyc明显有很大嫌疑
接着尝试反编译
import marshal
import types
import dis
import struct
def show(code, depth=0):
pad = " " * depth
print(f"{pad}[代码块] {code.co_name}")
print(f"{pad}[起始行] {code.co_firstlineno}")
print(f"{pad}[调用名称] {code.co_names}")
print(f"{pad}[常量] {[c for c in code.co_consts if not isinstance(c, types.CodeType)]}\n")
for const in code.co_consts:
if isinstance(const, types.CodeType):
show(const, depth + 1)
with open("edu_ratsample.pyc", "rb") as f:
data = f.read()
# Python 3.7+: pyc header = 16 bytes
# Python 3.3–3.6: 12 bytes
# 保险起见:自动跳过 header
offset = 0
magic = data[:4]
offset += 4
if magic >= b'\x33\x0d\x0d\x0a': # Python 3.7+
offset += 12
else:
offset += 8
root = marshal.loads(data[offset:])
show(root)
得到如下结果
[代码块] <module>
[起始行] 1
[调用名称] ('base64', 'socket', 'sys', 'time', 'C2_HOST', 'C2_PORT', 'BEACON_B64', 'MUTEX_NAME', 'USER_AGENT', 'bytes', '_xor', 'build_payload', 'try_connect', 'int', 'main', '__name__', 'exit')
[常量] [0, None, '192.0.2.1', 64123, 'eyJ0IjoiYmVhY29uIiwidiI6IjEuMCJ9', 'Global\\EduLab_RAT_Mutex_2026', 'Mozilla/5.0 (EduLab; Win32) RAT-Stub/1.0', 'data', 'key', 'return', '__main__', ('return', None)]
[代码块] _xor
[起始行] 15
[调用名称] ('bytes', 'enumerate')
[常量] [None]
[代码块] <genexpr>
[起始行] 16
[调用名称] ('len',)
[常量] [None]
[代码块] build_payload
[起始行] 19
[调用名称] ('base64', 'b64decode', 'BEACON_B64', '_xor')
[常量] [None, b'EDU']
[代码块] try_connect
[起始行] 25
[调用名称] ('build_payload', 'socket', 'AF_INET', 'SOCK_STREAM', 'settimeout', 'connect', 'C2_HOST', 'C2_PORT', 'sendall', 'USER_AGENT', 'encode', 'time', 'sleep', 'OSError', 'close')
[常量] [None, 3.0, b'UA:', 'utf-8', b'\r\n', b'PAYLOAD:', 0.2]
[代码块] main
[起始行] 40
[调用名称] ('MUTEX_NAME', 'try_connect')
[常量] [None, 0]
或者用反编译工具也可以

尝试反编译
不难发现直接反编译出了C2的地址和端口,所以本题答案是 192.0.2.1:64123
2. 样本使用的传输层协议是什么?【答案格式:HTTP】(全大写)
继续来看反编译的结果

主要看try_connect的连接过程
我们可以看到AF_INET,即Address Family Internet Protocol v4,表示使用了IPv4地址
而SOCK_STREAM则表示创建了面向连接的流式套接字,对应着TCP协议
基本原始逻辑就相当于
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
所以样本使用的传输层协议为TCP
3. 样本外发的 User-Agent 完整字符串是什么?【按实际值填写】

在线反编译pyc直接就出了,脚本里也能看见,只是没这样直观
4. Beacon 的 Base64 常量是什么?【按实际值填写】

在线反编译pyc直接就出了,脚本里也能看见,只是没这样直观
5. 样本中出现的 Mutex 名称是什么?【按实际值填写】

在线反编译pyc直接就出了,脚本里也能看见,只是没这样直观
6. 是否具备注册表 Run、计划任务、服务安装或 UAC 绕过等行为?

**根据反编译内容,我们可以确认大概逻辑,main只用了MUTEX_NAME和try_connect,说明程序入口最终只会进入网络连接函数,没有调用其他持久化或提权函数 **
**同时也没有发现 **eval、exec、__import__ 等动态加载方式。因此样本无法在隐藏字符串的情况下,动态导入其他模块执行相关操作
因此样本的全部有效逻辑只有:
- 对Beacon进行Base64解码;
- **使用密钥 **
EDU进行XOR处理; - 创建TCP套接字;
- 连接固定C2;
- 发送User-Agent和Payload;
- 关闭套接字并退出。
所以本题答案为否
7. 该 exe 由何种方式打包?【答案格式:全大写】
第一题就已经确定了是PYINSTALLER,就不重复了

五、流量分析
1. 内网用户向 intranet.corp.lab 提交登录表单。请给出 POST 正文里 password 字段的解码后的提交值【按实际值填写】

就给了个流量包,而且很小,就没几条
题目说的很明确啊,是POST正文,那我们肯定先过滤POST流量
http.request.method==POST

发现就两条啊,题目说了是登录表单,肯定是第一条的/login

追踪HTTP流即可以看到表单内容:
**其中 **password 字段为LabPass%23Q7
**这里 **%23 是 URL 编码,表示字符 #,因此解码后的密码为LabPass#Q7
2. 客户端 10.10.10.50 向 DNS 10.10.10.53 发起一次查询。Queries 中的域名看似随机十六进制。请将该段十六进制视为 ASCII 的十六进制表示,还原出可读字符串(即解码后的域名语义)【答案格式:abc-abc.abc.abc】
题目说的很明确了是DNS流量,我们过滤DNS流量
dns

发现就两条啊,题目说是10.10.10.50向10.10.10.53发起了一次查询,那就直接明确了是第一条,No.6的那条

发现了Queries的域名是一串十六进制字符串
6578616c7468726561642d64726f702e696e7472616e65742e6c61622e
将该字符串按 ASCII 十六进制解码得到exalthread-drop.intranet.lab.
所以答案是exalthread-drop.intranet.lab
3. 哪台客户端对哪台 FTP 服务器完成了认证?【答案格式:127.0.0.1-192.168.0.1】
这边流量题的特点就是说的蛮明确的,使用过滤条件查看 FTP 控制连接:
ftp

可以看到五条
第11条客户端(10.10.10.50)向服务器(10.10.10.101)发送了Request说我是bob
第12条服务器回复ready
第13条客户端发送了密码Ftp_S3cret_9z
第14条服务器回复收到,在验证
第15条服务器最终回复验证成功
所以对应连接为10.10.10.50-10.10.10.101
4. USER 与成功登录前的 PASS 明文分别是什么?【答案格式:USER-PASS 例:admin-123456】
上一题完整分析过了,就是 FTP 登录过程中直接写了PASS是bob-Ftp_S3cret_9z
USER bob
PASS Ftp_S3cret_9z

5. 存在来自外网段地址对 10.10.10.50 的 ICMP Echo 请求。请提取 ICMP 数据部分中隐藏的完整FLAG。【答案格式:ICMP_COVERT_FLAG {123_abc_def}】
根据题意,使用过滤条件查看 ICMP 流量:
icmp
**发现存在来自外网段地址 **198.51.100.66 发往内网主机 10.10.10.50 的 ICMP Echo 请求。
展开 ICMP 数据部分,可以看到 Payload 中直接写了完整的flag

ICMP_COVERT_FLAG{ping_payload_stego}
6. 对 api.corp.lab 的 GET /api/me 请求返回 200。除 JSON 体外,响应中哪条 非标准 HTTP 头 泄露了高权限备份密钥?【答案格式:A-Admin-Admin】
**使用过滤条件查看访问 **api.corp.lab 的 HTTP 流量:
http.host == "api.corp.lab"

直接就能定位到这一条,追踪TCP流

发现服务端返回状态码:
HTTP/1.1 200 OK
除 JSON 响应体外,响应头中存在一个非标准 HTTP 头:
X-Admin-Token: TOKEN_LEAK{http_header_backup_key}
题目要求填写泄露高权限备份密钥的非标准 HTTP 头名称,因此答案为X-Admin-Token
7. 同一源 IP 对主机 10.10.10.200 在短时间内向多个不同目的端口发送了仅含 SYN 的 TCP 报文,请写出源 IP。【答案格式:192.168.0.1】
根据题目含义使用过滤条件查找仅包含 SYN 的 TCP 报文:

**可以看到同一源 IP 在短时间内向主机 **10.10.10.200 的多个端口发送 SYN 包,目标端口包括:
22
23
80
445
3389
这些端口分别对应 SSH、Telnet、HTTP、SMB 和 RDP,符合端口扫描特征,都是198.51.100.66发过来的
所以源 IP 为198.51.100.66
8. 客户端通过 Telnet(端口 23) 连接 10.10.10.1。流中出现登录名与口令行。请给出登录名与完整口令FLAG(含题目中的FLAG格式)。【答案格式:用户名-FLAG】
使用过滤条件查看 Telnet 流量:
telnet
或者过滤 23 端口 TCP 流:
tcp.port == 23
其实都一样

**发现客户端连接目标 **10.10.10.1:23,追踪TCP流即可看到登录名与密码:

因此登录名为:
charlie
完整口令 FLAG 为:
Telnet_PASS_FLAG{legacy_cleartext}
所以flag就是charlie-Telnet_PASS_FLAG{legacy_cleartext}
六、内存取证
还有背景
公司某员工的电脑感染了勒索病毒,所有办公文档都被加密。安全团队在病毒仍在运行时制作了内存镜像。要求从内存镜像中提取加密密钥,解密被加密的最重要文档,获取其中的 flag。

1. 该勒索进程的进程标识号(PID)是多少?【按实际值填写】

我们用Lovelymem看一下,直接就能看见有HACK用户

桌面发现了四个文件,其中有两个exe,研究看看,先提取
New-Item -ItemType Directory -Force -Path .\extracted
$env:PYTHONIOENCODING='utf-8'
vol.exe -q --cache-path .\volcache -s .\symbols -o .\extracted `
-f .\HACKER-20260606-174920.dmp windows.dumpfiles.DumpFiles `
--filter ransom --ignore-case
在进程里找这个程序

分析一下

打开IDA,shift+f12定位字符串后交叉引用查看主要函数地址

说的很明确了,你的文件被加密了,要恢复的话就给钱,妥妥勒索啊
所以确认题目所说的勒索程序就是这个ransom.exe

定位得到PID是8804
2. 受害计算机的主机名(COMPUTERNAME)是什么? 【答案格式:ABC】
HACKER,这在lovelymem直接就能看见

3. 勒索软件将用户桌面下哪个子目录中的文件进行了批量加密?【仅写目录名,答案格式:abc1234_abc1234】

回到第一题我们发现的那个函数,发现前面有这样子一个函数,参数中包含了路径,把桌面下的2026xzb_enc这个文件夹里的文件进行了某种处理,具体函数在sub_1400014C0
继续步进,发现这个函数进行了三步

看着有点复杂,其实就是
for (int i = 0; i < 256; i++)
v51[i] = i;
即v51在生成一个256字节的S盒

然后这边进行了KSA密钥调度

最后PRGA生成密钥流并异或
所以这边是一个明显的标准RC4加密
确定了是对2026xzb_enc进行了RC4加密,所以本题答案为2026xzb_enc
4. 附件 secret_project4.docx.enc 采用勒索家族自定义封装格式。请对该文件进行十六进制分析,该加密文件开头的 5 字节魔数(Magic)是什么?【答案格式:ABCDe 大小写需完全一致】
题目说了是开头5字节魔数,其实可以直接看十六进制,前5字节是什么就是什么
所以答案是RNSMa


看加密完的,其实文件布局是这样子的
偏移 0x00:4 字节 Magic,"RNSM"
偏移 0x04:4 字节原始文件大小,小端序
偏移 0x08:RC4 密文
所以其实魔数是四位RNSM才对(,但是题目说5位,那就5位
5. 真正的密文数据从文件起始偏移多少字节处开始?(从 0 计)【答案格式:数字】

**上一题分析过了,真正的密文数据是从偏移0x08的位置开始的 **
所以本题答案是8
6. 请从内存镜像中提取本次加密所使用的对称密钥,该密钥的长度是多少字节?【答案格式:数字】
回到 sub_140009000 函数

按照原型长这样子
BOOL CryptGenRandom(
HCRYPTPROV hProv, // phProv
DWORD dwLen, // 0x10u
BYTE *pbBuffer // qword_14000F030 + 4
);
所以可以看到密钥的长度是0x10,即16
7. 请写出密钥的完整十六进制表示【答案格式:无空格、无 0x】

可以看到函数这几行
先分配了24字节,然后说的很明确了把密钥写在偏移+4的地方,大概就是这样子
偏移 0x00:0xDEADC0DE 4字节前哨
偏移 0x04:RC4 key 16字节
偏移 0x14:0xCAFEBABE 4字节后哨
总长度:0x18 24字节
所以可去内存搜索字节:
DE C0 AD DE ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? BE BA FE CA
注意 x86 小端序下,<font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">0xDEADC0DE</font> 在内存中是 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">DE C0 AD DE</font>,<font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">0xCAFEBABE</font> 在内存中是 <font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">BE BA FE CA</font>。两者中间的 16 字节即第 7 题答案

所以答案是cb<font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">8978dde5b08227aac1c40ba91849c5</font>
8. 请结合内存样本、导入表或静态逆向分析,对 .enc 文件中密文部分所采用的加密算法名称是什么?【答案格式:大写】

第三题分析过了,在sub_1400014C0函数,是RC4加密
9. 程序在启动加密前,通过哪个 Windows CryptoAPI 函数生成了随机密钥?(写出函数名)【答案格式:全小写】

<font style="color:rgb(51, 51, 51);background-color:rgb(243, 244, 244);">cryptgenrandom</font>
分析过了真正生成随机密钥的函数就是 CryptGenRandom

10. 勒索程序在加密完成后会向用户展示勒索提示。请从内存镜像或提取的样本字符串中分析,攻击者要求的赎金金额是多少?【答案格式:99.9 BTC】

第一题就分析过了,这边写的很清楚要0.5 BTC
11. 攻击者留下的联系邮箱是什么?【按实际值填写】

同一个地方,也是第一题,联系n0t_r3al@pr0ton.me
12. 内存镜像中还残留了受害者小张写在桌面上的一份文本文件内容。请根据镜像中的相关信息回答,该日记文件的完整文件名是什么?【按实际值填写】

打开看看桌面是什么就好了,所以是摸鱼日记.txt
小张的摸鱼日记.txt
================================================================
小张的摸鱼日记.txt
================================================================
下午 2:15
老板让我看财务发的"年度财报模板"。
邮件标题【急!速看】,行吧,速看就速看。
点开之后……好像没反应?算了,先去接杯水。
下午 2:31
回来桌面弹了个红框框,说我文件被加密了,
让我转 0.5 个比特币。
0.5 个比特币多少钱来着?我月薪都不够。
下午 2:33
冷静。先发个朋友圈。
配文:在吗?教我一下怎么把今天从日历上删掉。
零赞。连我妈都没赞。
下午 2:40
打给隔壁老李,占线。
打给我对象,她说"活该谁让你上班摸鱼"。
我没摸鱼啊,这是工作需要点的附件!
……好吧我确实也开着淘宝。
下午 2:52
老李终于回了,就一句:"别关机,等我。"
然后又没声了。
你们搞安全的能不能把话说完整啊喂!
下午 3:10
等老李的时候我重读了一遍勒索信。
错别字三个,标点不对俩,结尾还写"祝您生活愉快"。
被你勒索还愉快个屁。
下午 3:30
老李来了,捣鼓了十分钟,文件回来了。
我问他怎么弄的,他说"说了你也不懂"。
行吧大佬,奶茶我请,三杯,加料的那种。
下午 3:47
今日总结:
1. 标题带"急"和"!"的邮件,九成九有鬼。
2. 中招了先别慌,更别发朋友圈,没人赞。
3. 公司一定要养一个老李。
——— 完 ———
P.S. 早知道今天就请假了。
================================================================
13. 日记中,小张在下午 2:52 联系上的那位安全同事,在电话里对他说了什么?【答案格式:引号内原文】

所以是”别关机,等我。“,就在日记里
14. 解密后文件的大小是多少字节?【答案格式:99999】
我们在第四题分析过具体的文件头结构
偏移 0x00:4 字节 Magic,"RNSM"
偏移 0x04:4 字节原始文件大小,小端序
偏移 0x08:RC4 密文
所以原始文件大小其实是这四个字节

所以是0x2761

即10081
15. 解密后的内部文档记载了一份供备份系统使用的认证令牌。请完整写出该 flag。【按实际值填写】
对enc进行完整解密即可,算法我们知道了,密钥我们知道了,其实都知道了
from pathlib import Path
from Crypto.Cipher import ARC4
BASE_DIR = Path(__file__).resolve().parent
ENC_PATH = BASE_DIR / "secret_project4.docx.enc"
OUT_PATH = BASE_DIR / "secret_project4.docx"
KEY = bytes.fromhex("cb8978dde5b08227aac1c40ba91849c5")
def main() -> None:
data = ENC_PATH.read_bytes()
plaintext = ARC4.new(KEY).decrypt(data[8:])
OUT_PATH.write_bytes(plaintext)
print(f"enc={ENC_PATH}")
print(f"out={OUT_PATH}")
print(f"magic={plaintext[:8]!r}")
print(f"size={len(plaintext)}")
if __name__ == "__main__":
main()
所以flag是flag{m3m0ry_f0r3ns1cs_rc4_k3y_hunt_2026}