第25届数证杯决赛 - 团体服务器取证 完整解题报告
比赛时间: 2026年5月 检材数量: 2 台服务器镜像 题目范围: Q36-Q52(共 17 题) 最终得分: 全部解答完毕 ✅
目录
- 环境信息
- 解题过程详解
- Q36 - systemd 开机自启服务数量
- Q37 - 系统内核编译时间
- Q38 - GitLab 服务端口
- Q39 - GitLab 登录失败次数
- Q40 - GitLab root 用户密码
- Q41 - 仓库第一次提交时间
- Q42 - root 用户电子邮件
- Q43 - Git仓库被谁下载传播
- Q44 - git remote 远程服务器地址
- Q45 - OIM 后台管理服务端口
- Q46 - Spring Boot 框架版本
- Q47 - 登录时查询的数据库表
- Q48 - 删除的用户数量
- Q49 - xinchao 最早管理的群名
- Q50 - ES 群消息数量
- Q51 - "小雨末" 手机号
- Q52 - 贷款利息
- 关键中间过程
- 数据库表结构参考
- 常用命令模板
- 经验总结
一、环境信息
| 项目 | 检材一 (GitLab) | 检材二 (OIM后端) |
|---|---|---|
| IP 地址 | 192.168.100.234 | 192.168.100.233 |
| 主机名 | localhost.localdomain | iZj6chw5inj1ussq3xplaoZ |
| 操作系统 | CentOS 7 | CentOS 7 |
| 内核版本 | 3.10.0-1160.119.1.el7.x86_64 | 3.10.0-1127.19.1.el7.x86_64 |
| SSH 端口 | 22 | 22 |
| 初始账号 | root / 123456 | root / 123456 |
| 主要服务 | GitLab (端口 9999) | OIM 后台管理 (Spring Boot) |
| Docker 容器 | - | redis, mysql_master, nginx-web, elasticsearch |
SSH 连接方式:
ssh -i ~/.ssh/id_ed25519 root@192.168.100.234 # 检材一 (GitLab)
ssh -i ~/.ssh/id_ed25519 root@192.168.100.233 # 检材二 (OIM后端)
二、解题过程详解
Q36 - systemd 开机自启服务数量
题目: 通过对服务器中的检材一镜像进行分析,该服务器上systemd管理的开机自启的服务数量是多少?(答案格式:仅数字)
答案:34
解题思路
- 连接检材一服务器
- 使用
systemctl list-unit-files命令列出所有已启用(enabled)的服务 - 统计输出结果中的服务数量
关键命令
# 列出所有已启用的 systemd 服务
systemctl list-unit-files --type=service --state=enabled
# 输出末尾显示:
# "34 unit files listed."
知识点
--type=service:只列出服务类型(排除 target、mount 等)--state=enabled:只列出开机自启的服务- 输出最后一行会显示总数
Q37 - 系统内核编译时间(中国时区)
题目: 通过对服务器中的检材一镜像进行分析,该服务器当前运行的系统内核的编译时间是多少?(答案格式:2024-12-24 15:29:38)
答案:2024-06-04 22:43:51
解题思路
- 使用
uname -v查看内核编译时间戳 - 原始输出为 UTC 时间,需转换为 中国时区(UTC+8)
关键命令
# 查看内核版本和编译时间
uname -v
# 输出:#1 SMP Tue Jun 4 14:43:51 UTC 2024
# 查看完整内核信息
uname -a
时间转换计算
- 原始时间:
Tue Jun 4 14:43:51 UTC 2024 - 中国时区:UTC + 8h =
22:43:51 - 最终答案:
2024-06-04 22:43:51
知识点
uname -v显示内核版本号和编译时间(UTC)- CTF 中涉及时间的题目通常需要时区转换
- UTC + 8h = 北京时间(中国标准时间)
Q38 - GitLab 服务端口
题目: 通过对服务器中的检材一镜像进行分析,该服务器上GitLab服务的端口是多少?(答案格式:仅数字)
答案:9999
解题思路
- GitLab Omnibus 配置文件位于
/etc/gitlab/gitlab.rb - Nginx 监听端口在配置文件中定义为
nginx['listen_port']
关键命令
# 查看 GitLab 配置文件中关于端口的设置
cat /etc/gitlab/gitlab.rb | grep listen_port
# 输出:nginx['listen_port'] = 9999
# 或使用 grep 精确查找
grep "listen_port" /etc/gitlab/gitlab.rb
知识点
- GitLab Omnibus 使用 Ruby DSL 配置文件
- Nginx 端口配置键为
nginx['listen_port'] - 默认端口为 80,此处被修改为 9999
Q39 - GitLab 登录失败次数
题目: 通过对服务器中的检材一镜像进行分析,该服务器上GitLab服务被登录失败的次数是多少?(答案格式:仅数字)
答案:6
解题思路
- GitLab Rails 应用日志位于
/var/log/gitlab/gitlab-rails/ - 登录操作对应
SessionsController#create - 登录失败的状态码为
status=0(在 GitLab JSON 日志中表示失败) - 筛选所有符合条件的日志条目并计数
关键命令
# 方法1:使用 Python 解析 JSON 日志
zcat /var/log/gitlab/gitlab-rails/production_json.log* | python3 -c "
import sys, json
count = 0
for line in sys.stdin:
obj = json.loads(line.strip())
if 'SessionsController' in obj.get('controller', '') and obj.get('status') == 0:
count += 1
print(f\"{obj.get('time')} - {obj.get('controller')}#{obj.get('action')} status={obj.get('status')}\")
print(f'Total: {count}')
"
# 方法2:使用 grep 快速筛选(粗略统计)
zcat /var/log/gitlab/gitlab-rails/production_json.log* | grep -c 'SessionsController.*status.*0'
6次失败时间线(UTC)
| 序号 | 时间 (UTC) | 说明 |
|---|---|---|
| 1 | 2025-11-06T02:51:38Z | 首次登录尝试 |
| 2 | 2025-11-06T02:52:10Z | 第二次尝试 |
| 3 | 2025-11-06T02:52:26Z | 第三次尝试 |
| 4 | 2025-11-06T02:52:43Z | 第四次尝试 |
| 5 | 2025-11-06T02:52:48Z | 第五次尝试 |
| 6 | 2025-11-06T05:08:40Z | 第六次尝试(root 尝试以 Mia 登录) |
知识点
- GitLab Rails 日志为 JSON 格式(production_json.log)
SessionsController#create= 用户登录动作status=0= 登录失败(密码错误或账号不存在)status=302= 登录成功(重定向到首页)- 日志可能已被 gzip 压缩,需用
zcat读取
Q40 - GitLab root 用户密码哈希与明文
题目: 通过对服务器中的检材一镜像进行分析,该服务器上GitLab服务的root用户的密码是多少?
答案:abc123654
哈希值: $2a$10$joK1mu.0whkjO8IvGSG/X.wVlUofNpX6hplpT85SQjdp.Dg0l7AKO
解题思路
- GitLab 使用 PostgreSQL 作为数据库,但需要以系统用户
git身份通过 peer 认证连接 - 从
users表中查询 root 用户的encrypted_password字段(bcrypt 哈希) - 使用 hashcat 进行掩码攻击破解
关键命令
# 1. 以 git 用户身份连接 PostgreSQL(peer 认证)
su git -s /bin/bash -c "/opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -U gitlab -d gitlabhq_production"
# 2. 查询 root 用户的密码哈希
su git -s /bin/bash -c "/opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -U gitlab -d gitlabhq_production -t -A -c \"SELECT encrypted_password FROM users WHERE username='root';\""
# 3. 将哈希保存到文件
echo '$2a$10$joK1mu.0whkjO8IvGSG/X.wVlUofNpX6hplpT85SQjdp.Dg0l7AKO' > hash.txt
# 4. hashcat 掩码攻击破解(-m 3200 = bcrypt)
hashcat -m 3200 -a 3 hash.txt 'abc?d?d?d?d?d?d'
# -m 3200: bcrypt 哈希模式
# -a 3: mask attack(掩码攻击)
# abc?d?d?d?d?d?d: 以 abc 开头 + 7位数字
# 5. 验证结果
echo 'abc123654' | openssl passwd -1 -salt $(echo '$2a$10$joK1mu.0whkjO8IvGSG/X.wVlUofNpX6hplpT85SQjdp.Dg0l7AKO' | cut -c5-25)
破解过程详解
- 哈希类型: bcrypt($2a$ 标识)
- hashcat 模式: 3200(bcrypt)
- 掩码规则:
abc?d?d?d?d?d?d= abc + 7位数字 - 破解结果:
abc123654
知识点
- GitLab 使用 PostgreSQL peer 认证,必须以系统用户
git身份连接 - GitLab 内置的 PostgreSQL 在
/var/opt/gitlab/postgresql/目录 - bcrypt 哈希格式:
$2a$<cost>$<salt><hash> - hashcat 掩码字符:
?d= 数字 0-9,?l= 小写字母,?u= 大写字母,?s= 特殊字符
Q41 - 仓库第一次提交时间(中国时区)
题目: 通过对服务器中的检材一镜像进行分析,该服务器上GitLab服务的仓库中第一次提交的时间是多少?(答案格式:2024-12-24 15:29:38)
答案:2025-11-06 11:07:02
解题思路
- GitLab 仓库可能存储在自定义路径(非默认 /var/opt/gitlab)
- 通过
git_data_dirs配置找到实际仓库路径 - 使用
git log查看最早的 commit 时间 - 转换为 中国时区
关键命令
# 1. 查找 GitLab 自定义仓库路径
cat /etc/gitlab/gitlab.rb | grep git_data_dirs
# 输出显示仓库在 /opt/gitlab-ce/git-data/
# 2. 找到具体仓库
find /opt/gitlab-ce/git-data/repositories -name '*.git' -type d
# 输出:/opt/gitlab-ce/git-data/repositories/@hashed/4e/07/4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce.git
# 3. 查看最早的 commit
cd /opt/gitlab-ce/git-data/repositories/@hashed/4e/07/4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce.git
git log --reverse --format="%ai %s" | head -1
# 4. 查看完整 commit 信息
git log --reverse -1 --pretty=fuller
知识点
- GitLab Omnibus 可通过
git_data_dirs配置自定义仓库路径 - 默认路径为
/var/opt/gitlab/git-data/repositories/ git log --reverse按时间正序排列(最早的在前)%ai显示作者日期(ISO 8601 格式,本地时区)
Q42 - root 用户电子邮件
题目: 通过对服务器中的检材一镜像进行分析,该服务器上GitLab服务的root用户的电子邮件是什么?(答案格式:a@b.com)
解题思路
- 以 git 用户身份连接 PostgreSQL
- 从 users 表查询 root 用户的 email 字段
关键命令
# 查询 root 用户邮箱
su git -s /bin/bash -c "/opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -U gitlab -d gitlabhq_production -t -A -c \"SELECT email FROM users WHERE username='root';\""
# 输出:wangdefa888@gmail.com
# 查看所有用户信息(用于其他题目分析)
su git -s /bin/bash -c "/opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -U gitlab -d gitlabhq_production -c \"SELECT id, username, name, email, last_sign_in_at FROM users ORDER BY id;\""
知识点
-t参数:只显示数据(无表头)-A参数:非对齐输出(纯文本格式)- GitLab users 表包含完整的用户信息
Q43 - Git仓库被谁下载传播(用户名)
题目: 通过对服务器中的检材一镜像进行分析,该服务器上GitLab服务的仓库是被哪个用户下载传播的?(答案格式:用户名)
答案:Mia
解题思路
这是一个典型的日志关联分析题,需要通过多条线索还原完整的事件时间线:
-
第一步:查看所有用户最后登录时间
- 发现 Mia 是唯一一个在 2025-11-06 新登录的非管理员用户
- 其他普通用户最后登录时间都是 2025-10-06
-
第二步:分析 GitLab Rails 日志
- 搜索
Projects::RepositoriesController#archive(下载 ZIP 操作) - 找到 05:09:47 UTC 的下载记录
- 搜索
-
第三步:还原完整时间线
- root 管理员尝试以 Mia 账号登录 → 密码失败
- root 在管理员后台重置了 Mia 的密码
- root 以 Mia 身份登录成功
- Mia 修改了自己的密码并重新登录
- Mia 下载了仓库 ZIP 包
-
第四步:Nginx 访问日志确认
- URL:
/ccy/oimmanage/-/archive/main/oimmanage-main.zip - 文件大小: 56MB,状态码 200
- URL:
完整事件时间线(UTC)
| 时间 | 操作 | 控制器 | 状态码 |
|---|---|---|---|
| 05:08:36-05:08:40 | root 尝试以 Mia 账号登录,密码失败 | SessionsController#create | 0 |
| 05:08:44-05:08:48 | root 查看 Mia 的用户页面 | UsersController#show/activity/calendar | 200 |
| 05:08:48-05:09:22 | root 在管理员后台重置 Mia 密码 | Admin::UsersController | 302 |
| 05:09:28 | root 以 Mia 身份登录成功 | SessionsController#create | 302 |
| 05:09:28-05:09:38 | Mia 修改自己的密码 | UserSettings::PasswordsController | 302 |
| 05:09:40 | Mia 用新密码重新登录 | SessionsController#create | 302 |
| 05:09:47 | 下载仓库 ZIP 包(关键动作) | Projects::RepositoriesController#archive | 200 |
Nginx 日志确认
172.23.194.1 - - [06/Nov/2025:13:09:48 +0800] "GET /ccy/oimmanage/-/archive/main/oimmanage-main.zip HTTP/1.1" 200 56207514
关键命令
# 1. 查看所有用户最后登录时间,定位异常登录
su git -s /bin/bash -c "/opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -U gitlab -d gitlabhq_production -t -A -c \"SELECT id, username, name, email, last_sign_in_at FROM users ORDER BY id;\""
# 2. 查看 GitLab Rails 日志,筛选 archive(下载仓库ZIP)操作
zcat /var/log/gitlab/gitlab-rails/production_json.log* | python3 -c "
import sys, json
for line in sys.stdin:
obj = json.loads(line.strip())
controller_action = obj.get('controller', '') + '#' + obj.get('action', '')
if 'archive' in controller_action.lower():
print(json.dumps(obj, indent=2))
"
# 3. Nginx 访问日志确认下载记录
zcat /var/log/gitlab/nginx/gitlab_access.log* | grep "archive"
# 4. 审计日志确认操作者身份
zcat /var/log/gitlab/gitlab-rails/audit_json.log* | python3 -c "
import sys, json
for line in sys.stdin:
obj = json.loads(line.strip())
author = obj.get('author_name', '')
user = obj.get('meta', {}).get('user', '') if isinstance(obj.get('meta'), dict) else ''
time = obj.get('time', '')
print(f'{time} | {author} | {user}')
"
# 5. 查看 SessionsController 相关日志(登录事件)
zcat /var/log/gitlab/gitlab-rails/production_json.log* | python3 -c "
import sys, json
for line in sys.stdin:
obj = json.loads(line.strip())
if 'SessionsController' in obj.get('controller', ''):
print(f\"{obj.get('time')} | {obj.get('controller')}#{obj.get('action')} | status={obj.get('status')}\")
"
# 6. 查看 Admin::UsersController 相关日志(管理员操作)
zcat /var/log/gitlab/gitlab-rails/production_json.log* | python3 -c "
import sys, json
for line in sys.stdin:
obj = json.loads(line.strip())
if 'Admin::UsersController' in obj.get('controller', ''):
print(f\"{obj.get('time')} | {obj.get('controller')}#{obj.get('action')} | status={obj.get('status')}\")
"
知识点
Projects::RepositoriesController#archive= GitLab 下载仓库 ZIP- Nginx URL 模式:
/group/project/-/archive/branch/project-branch.zip - 管理员可通过 Admin::UsersController 重置其他用户密码
- 审计日志(audit_json.log)记录操作者身份
- 通过 last_sign_in_at 可快速定位异常登录的用户
Q44 - 检材二 git remote 远程服务器地址
题目: 通过对服务器中的检材二镜像进行分析,嫌疑人项目中git配置的远程服务器地址是多少?(答案格式:192.168.1.1)
答案:172.23.194.159
解题思路
- 连接检材二服务器(192.168.100.233)
- 找到项目仓库
/home/CCY/oim-server-manage/.git/config - 提取
[remote "origin"]下的 url 字段 - 从 URL 中提取 IP 地址部分
关键命令
# 1. 查找所有 Git 仓库
find /home /root -name '.git' -type d 2>/dev/null
# 输出:/home/CCY/oim-server-manage/.git
# 2. 查看 Git 远程配置
cat /home/CCY/oim-server-manage/.git/config
# 输出内容:
# [remote "origin"]
# url = http://172.23.194.159:9999/ccy/oimmanage
# fetch = +refs/heads/:refs/remotes/origin/
# 3. 或使用 git 命令直接查看
cd /home/CCY/oim-server-manage && git remote -v
# 输出:
# origin http://172.23.194.159:9999/ccy/oimmanage (fetch)
# origin http://172.23.194.159:9999/ccy/oimmanage (push)
# 4. 查看全局 Git 配置(辅助确认)
cat /root/.gitconfig
Git 配置文件内容
[remote "origin"]
url = http://172.23.194.159:9999/ccy/oimmanage
fetch = +refs/heads/:refs/remotes/origin/
分析
- 远程服务器 IP: 172.23.194.159
- 端口: 9999(与检材一上的 GitLab 实例一致)
- 仓库路径: /ccy/oimmanage
- 题目要求答案格式为 IP 地址,只需提取 IP 部分
知识点
- Git 远程仓库配置在
.git/config的[remote "origin"]段落中 - url 格式:
http(s)://IP:PORT/path或git@IP:path git remote -v可查看远程仓库地址(fetch 和 push)
Q45 - OIM 后台管理服务端口
题目: 通过对服务器中的检材二镜像进行分析,嫌疑人后台管理服务的端口是多少?(答案格式:仅数字)
答案:13000
解题思路
- 在检材二服务器上找到项目路径
/home/CCY/oim-server-manage/ - 该项目是一个 Java Spring Boot 应用(oim-server-manage-server.jar)
- Spring Boot 的服务端口配置在 application.yml 文件中
- 读取配置文件,找到
server.port的值
关键命令
# 1. 查看 Spring Boot 主配置文件
cat /home/CCY/oim-server-manage/config/application.yml
# 2. 提取端口配置
cat /home/CCY/oim-server-manage/config/application.yml | grep -A 1 'server:'
# 输出:
# server:
# port: 13000
# 3. 查看启动脚本确认运行方式
cat /home/CCY/oim-server-manage/startup.sh
# 4. 查看当前监听端口(辅助验证)
ss -tlnp
# 输出中应包含 13000 端口的监听信息
关键配置内容
server:
port: 13000
spring:
datasource:
url: jdbc:mysql://172.23.194.157:3307/CCY?useUnicode=true&characterEncoding=utf8
username: root
password: 123789
redis:
host: 172.23.194.157
port: 6379
系统架构分析
- 应用类型: OIM(Online IM)后台管理服务
- 技术栈: Spring Boot + MyBatis-Plus + Redis + MySQL
- 数据库: MySQL(172.23.194.157:3307)
- 缓存: Redis(172.23.194.157:6379)
知识点
- Spring Boot 项目的服务端口配置在
application.yml或application.properties中的server.port字段 - 配置文件可能位于项目目录的
config/子目录下 - 也可通过
unzip -p app.jar BOOT-INF/classes/application.yml从 JAR 包中提取
Q46 - Spring Boot 框架版本
题目: 通过对服务器中的检材二镜像进行分析,嫌疑人后台管理服务使用的spring boot框架版本是多少?(答案格式:1.0.0)
答案:1.5.8
解题思路
- 检材二上的项目是一个 Spring Boot 应用
- 项目中没有 pom.xml 或 build.gradle(只有打包后的 JAR 文件)
- 通过
unzip -l查看 JAR 包内部结构 - 在
BOOT-INF/lib/目录下找到 Spring Boot 相关依赖 - 从依赖文件名中提取版本号
关键命令
# 1. 查找项目构建文件(确认无 pom.xml / build.gradle)
find /home/CCY/oim-server-manage -name 'pom.xml' -o -name 'build.gradle'
# 输出为空,说明只有打包后的 JAR
# 2. 解压查看 JAR 包内部结构,获取 Spring Boot 版本
unzip -l /home/CCY/oim-server-manage/oim-server-manage-server.jar | grep 'spring-boot'
# 输出:
# BOOT-INF/lib/spring-boot-1.5.8.RELEASE.jar
# BOOT-INF/lib/spring-boot-autoconfigure-1.5.8.RELEASE.jar
# BOOT-INF/lib/spring-boot-starter-web-1.5.8.RELEASE.jar
# BOOT-INF/lib/spring-boot-starter-1.5.8.RELEASE.jar
# ...
# 3. 如果系统有 jar 命令也可以用
jar tf /home/CCY/oim-server-manage/oim-server-manage-server.jar | grep 'spring-boot'
# 4. 从 JAR 包中提取嵌入的 application.yml(辅助确认)
unzip -p /home/CCY/oim-server-manage/oim-server-manage-server.jar BOOT-INF/classes/application.yml
关键输出
BOOT-INF/lib/spring-boot-1.5.8.RELEASE.jar
BOOT-INF/lib/spring-boot-autoconfigure-1.5.8.RELEASE.jar
BOOT-INF/lib/spring-boot-starter-web-1.5.8.RELEASE.jar
所有 Spring Boot 相关依赖版本一致:1.5.8.RELEASE
知识点
- Spring Boot 打包后的 JAR 是可执行 JAR(fat JAR),内部结构包含
BOOT-INF/lib/目录存放所有依赖 - 通过
unzip -l或jar tf可以列出 JAR 包内容,无需实际解压 - 依赖 JAR 文件名中直接包含版本号,如
spring-boot-1.5.8.RELEASE.jar - 1.5.8.RELEASE 是 Spring Boot 1.x 系列的稳定版本,发布于 2017 年
- 答案格式要求为
1.0.0,所以提取为1.5.8
Q47 - OIM 后台管理系统登录时查询的数据库表
题目: 通过对服务器中的检材二镜像进行分析,嫌疑人后台管理系统在登录时,查询的数据库表名是什么?(答案格式:表名)
答案:im_user
解题思路
- 修改 Docker MySQL root 密码为
123789,导入CCY.sql数据 - 开启 MySQL general_log 记录所有 SQL 查询
- 从前端 JS 代码中提取登录 API 路径和参数格式
- 启动 jar 包(端口 13000)和 nginx-admin(端口 8000)
- 使用 curl 模拟登录请求
- 查看 general_log,捕获登录时执行的 SQL
前端 JS 分析
// 从 main.a49ed8c4e67805ee7bba.js 提取的登录函数
i.login = function(e, t, n) {
var r = {account: e, password: t}, i = {body: r};
o.default.post("/manage/index/login", i, n)
}
// 密码加密(MD5)
// pages-login-Login.ac749ee0.js
MD5(password) // 发送前进行 MD5 加密
关键命令
# 1. 开启 MySQL general_log
docker exec mysql_master mysql -u root -p123789 -e "
SET GLOBAL general_log = 'ON';
SET GLOBAL general_log_file = '/var/lib/mysql/general.log';
SET GLOBAL log_output = 'FILE';
"
# 2. 清空日志(可选)
docker exec mysql_master truncate /var/lib/mysql/general.log
# 3. 模拟登录请求
curl -s -X POST http://localhost:13000/manage/index/login \
-H "Content-Type: application/json" \
-d '{"body":{"account":"admin","password":"123456"}}'
# 4. 查看 general_log 捕获的 SQL
docker exec mysql_master cat /var/lib/mysql/general.log | grep "Query"
# 输出:
# Query select * from im_user where account='admin'
捕获的 SQL
select * from im_user where account='admin'
补充发现
im_user表中无admin账号- 实际存在的后台管理账号包括:CG07, sw23914, BY24, DYY34 等
- 登录逻辑要求
type字段必须为"1"或"2",数据库中所有用户 type 均为"0" - 前端 MD5 加密密码后发送,后端直接比较 MD5 哈希值
知识点
- MySQL general_log 可记录所有执行的 SQL 查询
- 通过模拟 API 请求 + general_log 是发现后端数据库操作的有效方法
- 前端 JS 逆向可提取 API 路径和参数格式
- Spring Boot + MyBatis-Plus 项目的登录通常查询用户表
Q48 - 后台管理系统中删除的用户数量
题目: 通过对服务器中的检材二镜像进行分析,嫌疑人后台管理系统中删除的用户数量是多少?(答案格式:仅数字)
答案:510
解题思路
- 查询
im_user表,发现flag字段有两种值:0和1 flag='0'的用户有 510 个flag='1'的用户有 6879 个- 所有
flag='0'用户的cancelTime字段均为 NULL,说明是通过逻辑删除标记的 - 结论:
flag='0'= 已删除用户
关键命令
# 1. 查询 flag 字段分布
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT flag, COUNT(*) as count FROM im_user GROUP BY flag;
"
# 输出:
# +------+-------+
# | flag | count |
# +------+-------+
# | 0 | 510 |
# | 1 | 6879 |
# +------+-------+
# 2. 查询已删除用户数量(flag='0')
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT COUNT(*) FROM im_user WHERE flag='0';
"
# 输出:510
# 3. 验证 cancelTime 字段
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT flag, cancelTime, COUNT(*) FROM im_user WHERE flag='0' GROUP BY cancelTime;
"
# 所有 flag='0' 用户的 cancelTime 均为 NULL
知识点
flag字段为逻辑删除标记:'0'=已删除,'1'=正常- 逻辑删除不物理删除记录,便于数据恢复和审计
- MySQL 查询含中文字段需加
--default-character-set=utf8mb4
Q49 - xinchao 参与管理的最早的群名
题目: 通过对服务器中的检材二镜像进行分析,用户xinchao参与管理的最早的群名称是什么?(答案格式:群名称)
答案:测试
解题思路
- 在
im_user表中找到用户 xinchao,获取其 userId - 在
im_group_member表中查询该用户的管理记录(position IN ('1','2')) - 关联
im_group表获取群名 - 按 createTime 升序排序,取最早的群
关键命令
# 1. 查找 xinchao 用户
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT id, account, name FROM im_user WHERE name='xinchao';
"
# 输出:
# +--------------------------------------+---------+---------+
# | id | account | name |
# +--------------------------------------+---------+---------+
# | cb7e10f9-6e29-464a-aa96-748ef4fb9e7b | wwwww5 | xinchao |
# +--------------------------------------+---------+---------+
# 2. 查找参与管理的最早的群
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT g.name as group_name, g.createTime, gm.position
FROM im_group_member gm
JOIN im_group g ON gm.groupId = g.id
WHERE gm.userId = 'cb7e10f9-6e29-464a-aa96-748ef4fb9e7b'
AND gm.position IN ('1','2')
ORDER BY g.createTime ASC;
"
# 输出:
# +------------+---------------------+----------+
# | group_name | createTime | position |
# +------------+---------------------+----------+
# | 测试 | 2021-10-18 10:06:34 | 2 |
# | ... | ... | ... |
# +------------+---------------------+----------+
# 最早的群为"测试",xinchao 在其中为管理员(position=2)
知识点
im_group_member.position字段含义:1=群主,2=管理员,3=普通成员- "参与管理" = position IN ('1','2')
- JOIN 查询关联两个表获取完整信息
- ORDER BY createTime ASC 按时间升序排列
Q50 - Elasticsearch 索引中群消息数量
题目: 通过对服务器中的检材二镜像进行分析,该服务器上elasticsearch存储的群消息数量是多少?(答案格式:仅数字)
答案:3
解题思路
- 找到 ES 容器
adoring_fermat(elasticsearch:7.9.3),已退出状态 - xpack.security.enabled=true,环境变量凭据为
ccyQo:ccy#@132 - 但 basic license 下 native realm security index 不可用,认证失败
- 数据目录位于
/root/elasticsearch-data - 启动无认证 ES 容器挂载同一数据目录到端口 9201
- 查询
_cat/indices发现 3 个索引,其中ccy_group_message_index有 3 条群消息
关键命令
# 1. 查看 ES 容器信息
docker ps -a | grep elastic
docker inspect adoring_fermat
# 2. 查看环境变量(凭据)
docker inspect adoring_fermat | grep -A 50 Env
# ELASTICSEARCH_USERNAME=ccyQo
# ELASTICSEARCH_PASSWORD=ccy#@132
# 3. 启动无认证 ES 挂载原数据目录
docker run -d --name es_noauth -p 9201:9200 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
-v /root/elasticsearch-data:/usr/share/elasticsearch/data \
docker.elastic.co/elasticsearch/elasticsearch:7.9.3
# 4. 等待 ES 启动完成
sleep 10
# 5. 查看所有索引
curl -s http://localhost:9201/_cat/indices?v
# 输出:
# health status index docs.count
# yellow open ccy_user_message_index 10
# yellow open ccy_group_message_index 3
# yellow open ccy_offline_message_index 12
# 6. 查询群消息数量
curl -s http://localhost:9201/ccy_group_message_index/_count
# 输出:{"count":3}
# 7. 查看群消息详情(验证)
curl -s http://localhost:9201/ccy_group_message_index/_search?pretty
ES 索引结构
| 索引名称 | 文档数量 | 说明 |
|---|---|---|
| ccy_user_message_index | 10 | 用户私聊消息 |
| ccy_group_message_index | 3 | 群消息(本题答案) |
| ccy_offline_message_index | 12 | 离线消息 |
知识点
- ES basic license 下 native realm security 不可用,需 bypass
- 通过挂载数据目录到无认证容器可绕过 xpack security
_cat/indices查看所有索引及其文档数量/_countAPI 快速获取索引中文档总数
Q51 - 用户"小雨末"的手机号
题目: 通过对服务器中的检材二镜像进行分析,用户"小雨末"的手机号码是多少?(答案格式:手机号)
答案:14499466022
解题思路
- 直接在
im_user表的 name/nickname/account 字段搜索"小雨末" → 结果为空 - 该用户的名字字段存储为 "YM",而非"小雨末"
- 在
im_user_add_request(好友申请表)中搜索requestUserName LIKE '%小雨末%' - 找到
requestUserId = 76d866ae418946cba6eec6bc423613ed - 用该 user id 回到
im_user表查询手机号 - 得到
mobile = +861****6022,去掉国家码前缀+86
关键命令
# 1. 在 im_user 表中直接搜索(结果为空)
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT id, account, name, nickname FROM im_user
WHERE name LIKE '%小雨末%' OR nickname LIKE '%小雨末%' OR account LIKE '%小雨末%';
"
# 2. 在好友申请表中搜索"小雨末"
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT requestUserId, requestUserName FROM im_user_add_request
WHERE requestUserName LIKE '%小雨末%';
"
# 输出:
# +--------------------------------------+---------------+
# | requestUserId | requestUserName |
# +--------------------------------------+---------------+
# | 76d866ae418946cba6eec6bc423613ed | 小雨末 |
# +--------------------------------------+---------------+
# 3. 根据 user id 回到 im_user 查手机号
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT id, account, name, nickname, mobile FROM im_user
WHERE id = '76d866ae418946cba6eec6bc423613ed';
"
# 输出:
# +--------------------------------------+---------+------+------+--------------+
# | id | account | name | nickname | mobile |
# +--------------------------------------+---------+------+------+--------------+
# | 76d866ae418946cba6eec6bc423613ed | ... | YM | ... | +861****6022|
# +--------------------------------------+---------+------+------+--------------+
# 4. 去掉 +86 前缀,得到最终答案:14499466022
知识点
im_user_add_request表中存储了好友申请时的用户昵称- 昵称可能与
im_user.name字段不一致 mobile字段包含国家码前缀+86,答案需去掉前缀- 跨表关联查询是常见的数据取证技巧
Q52 - 贷款利息
题目: 通过对服务器中的检材二镜像进行分析,该系统存储的贷款利息是多少?(答案格式:仅数字)
答案:0.8
解题思路
- 在
im_system_group_notice(系统群公告)表中搜索与"贷款"、"利息"相关的公告 - 找到公告内容:"!!!【!!!重要通知!!!】所有群交单统一贷款利息为0.8%,所有人切记!!!"
- 提取利息数值:0.8
关键命令
# 在系统群公告表中搜索贷款利息相关信息
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT * FROM im_system_group_notice
WHERE notice LIKE '%贷款%' OR notice LIKE '%利息%';
"
# 输出:
# +----+--------------------------------------------------------------------------+
# | id | notice |
# +----+--------------------------------------------------------------------------+
# | 1 | !!!【!!!重要通知!!!】所有群交单统一贷款利息为0.8%,所有人切记!!! |
# +----+--------------------------------------------------------------------------+
# 答案:0.8
知识点
im_system_group_notice表存储系统级公告- LIKE 模糊查询可用于搜索关键词
- 中文内容查询需加
--default-character-set=utf8mb4
三、关键中间过程
Git Stash 中恢复 JAR 包
背景: 检材二上的 JAR 包是旧版本,需要从 git stash 中恢复正确的 JAR 包。
发现过程
- 检材二
/home/CCY/oim-server-manage有.git仓库 git stash list为空(stash ref 已被删除)- 遍历未打包的 loose objects,发现两个额外 commit:
8f5fcabc— stash index commit: "index on dev: c21d6ee 'dev'"617655b9— stash merge commit: "On dev: oim-server-manage-server.jar"(双 parent)
- stash merge commit 的 tree 中包含正确的 JAR 包,blob hash 为
17b2de3380d238709558af466d701cdc724b8a0c
关键命令
cd /home/CCY/oim-server-manage
# 1. 查找所有 loose objects(不在 pack 文件中的对象)
find .git/objects -type f ! -path '*/pack/*' ! -path '*/info/*'
# 2. 检查每个 object 的类型
for obj in $(find .git/objects -type f ! -path '*/pack/*' ! -path '*/info/*' | sed 's|.git/objects/||;s|/||'); do
echo "$obj: $(git cat-file -t $obj)"
done
# 3. 查看 stash index commit
git cat-file -p 8f5fcabc
# 输出:
# tree ...
# parent c21d6ee...
# author ...
# committer ...
#
# index on dev: c21d6ee 'dev'
# 4. 查看 stash merge commit
git cat-file -p 617655b9
# 输出:
# tree 415c698a...
# parent c21d6ee... (HEAD)
# parent 8f5fcabc... (index)
# author ...
# committer ...
#
# On dev: oim-server-manage-server.jar
# 5. 查看 tree 内容
git cat-file -p 415c698a
# 输出包含:
# 100644 blob 17b2de3380d238709558af466d701cdc724b8a0c oim-server-manage-server.jar
# 6. 提取 JAR 包
git show 17b2de3380d238709558af466d701cdc724b8a0c > oim-server-manage-server.jar
# 7. 验证文件大小和格式
ls -lh oim-server-manage-server.jar # 62MB
file oim-server-manage-server.jar # Zip archive data
Git Stash 结构说明
stash merge commit (双 parent)
├── parent 1: HEAD commit (c21d6ee 'dev')
└── parent 2: index commit (8f5fcabc)
└── parent: HEAD commit (c21d6ee)
- Index commit: 保存当前的 index 状态
- Merge commit: 包含实际的文件变更(JAR 包)
- 即使
git stash drop或删除 ref,commit 仍作为 loose objects 存在
Nginx Web 容器配置与登录分析
容器信息
- 名称: nginx-web
- 镜像: nginx:latest
- 端口映射: 80 -> 80, 443 -> 443
- 状态: 可通过
docker start nginx-web启动
Nginx 配置(/etc/nginx/conf.d/default.conf)
server {
listen 80;
# 静态文件目录
location / {
root /usr/share/nginx/html;
index index.html;
}
# 代理到后端 Spring Boot 服务
location /manage-server/ {
proxy_pass http://127.0.0.1:13000/;
}
# 应用协议接口
location /app-protocol/ {
root /tmp/;
}
}
登录 API 分析
| 项目 | 值 |
|---|---|
| API 路径 | /manage/index/login(nginx 代理路径 /manage-server/manage/index/login) |
| 请求方法 | POST |
| Content-Type | application/json |
| 请求体格式 | {"body":{"account":"用户名","password":"MD5(密码)"}} |
关键发现
- 前端 MD5 加密: 前端 JS 代码显示密码在发送前会进行
MD5()加密 - 后端直接比较 MD5: 反编译 IndexService.class 发现后端直接将传入的 password 与数据库中存储的 MD5 哈希值进行比较
- 用户类型限制: 登录逻辑要求
type字段必须为"1"或"2",否则返回"账号不存在!"。数据库中所有用户 type 均为"0" - 数据库连接: jar 包内 application.yml 配置的数据库为
CCY
干扰项排查(Docker MySQL ry 库)
现象
- Docker MySQL 容器中只包含
ry数据库 - 但 application.yml 指向
CCY数据库
排查过程
# 1. 查看 Docker MySQL 中的数据库
docker exec mysql_master mysql -u root -p123789 -e "SHOW DATABASES;"
# 输出:information_schema, mysql, performance_schema, ry
# 2. 查看 application.yml 中的数据库配置
cat /home/CCY/oim-server-manage/config/application.yml | grep -A 5 'datasource:'
# 输出:url: jdbc:mysql://172.23.194.157:3307/CCY
# 3. 结论:ry 是干扰项,实际使用 CCY 数据库
# 4. 需要导入 CCY.sql 创建 CCY 数据库
docker exec mysql_master mysql -u root -p123789 -e "CREATE DATABASE IF NOT EXISTS CCY;"
docker exec -i mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 < CCY.sql
知识点
- Docker 中的
ry数据库是干扰项 - 始终以 application.yml 配置为准
- 需要手动导入 SQL 文件创建正确的数据库
四、数据库关键表与字段规则
im_user 表(用户信息)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | VARCHAR(UUID) | 用户唯一标识 |
| account | VARCHAR | 登录账号 |
| name | VARCHAR | 姓名/名称(可能与 nickname 不同) |
| nickname | VARCHAR | 昵称 |
| mobile | VARCHAR | 手机号(含 +86 前缀) |
| flag | CHAR(1) | '0'=已删除, '1'=正常 |
| type | CHAR(1) | '1'或'2'可登录后台, '0'为普通用户 |
| password | VARCHAR | MD5哈希值 |
| cancelTime | DATETIME | 取消时间(逻辑删除时可能为 NULL) |
im_group_member 表(群成员)
| 字段 | 类型 | 说明 |
|---|---|---|
| groupId | VARCHAR | 群 ID |
| userId | VARCHAR | 用户 ID |
| position | INT | 1=群主, 2=管理员, 3=普通成员 |
"参与管理" = position IN ('1','2')
im_user_add_request 表(好友申请)
| 字段 | 类型 | 说明 |
|---|---|---|
| requestUserId | VARCHAR | 发送者用户 ID |
| requestUserName | VARCHAR | 发送者昵称(可能与 im_user.name 不一致) |
im_system_group_notice 表(系统群公告)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT | 公告 ID |
| notice | TEXT | 公告内容 |
Elasticsearch 索引
| 索引名称 | 说明 | 文档数量 |
|---|---|---|
| ccy_user_message_index | 用户私聊消息 | 10 |
| ccy_group_message_index | 群消息 | 3 |
| ccy_offline_message_index | 离线消息 | 12 |
ES xpack security bypass: 启动无认证容器挂载原数据目录 /root/elasticsearch-data
五、常用命令模板
MySQL 查询(中文需加编码参数)
# 标准查询格式
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "SQL语句"
# 示例:查询用户信息
docker exec mysql_master mysql -u root -p123789 CCY --default-character-set=utf8mb4 -e "
SELECT id, account, name, nickname, mobile FROM im_user WHERE name='xinchao';
"
JAR 包内嵌配置提取
# 从 JAR 包中提取 application.yml
unzip -p oim-server-manage-server.jar BOOT-INF/classes/application.yml
# 查看 JAR 包依赖(获取版本信息)
unzip -l oim-server-manage-server.jar | grep 'spring-boot'
Git loose objects 遍历(恢复被删除的 stash)
# 查找所有 loose objects
find .git/objects -type f ! -path '*/pack/*' ! -path '*/info/*'
# 检查 object 类型
git cat-file -t <hash> # 返回: commit, tree, blob, tag
# 查看 object 内容
git cat-file -p <hash>
# 从 blob 提取文件
git show <blob_hash> > output.jar
GitLab 日志分析
# Rails JSON 日志解析(Python)
zcat /var/log/gitlab/gitlab-rails/production_json.log* | python3 -c "
import sys, json
for line in sys.stdin:
obj = json.loads(line.strip())
# 筛选条件
if 'keyword' in str(obj).lower():
print(json.dumps(obj, indent=2))
"
# Nginx 访问日志
zcat /var/log/gitlab/nginx/gitlab_access.log* | grep "keyword"
PostgreSQL 连接(GitLab peer 认证)
su git -s /bin/bash -c "/opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -U gitlab -d gitlabhq_production -t -A -c \"SQL语句\""
六、经验总结
关键知识点回顾
- GitLab 数据库连接: PostgreSQL peer 认证,必须以系统用户
git身份连接 - bcrypt 密码破解: hashcat -m 3200,支持掩码攻击(-a 3)
- OIM 系统架构: Spring Boot + MyBatis-Plus + Redis + MySQL
- 干扰项识别: Docker 中的
ry数据库是干扰项,jar 包实际连接CCY数据库 - 时区转换: UTC + 8h = 中国时区(北京时间)
- Git Stash 取证:
git stash drop后 commit 仍作为 loose objects 存在于.git/objects/中,可通过遍历未打包 objects 恢复 - GitLab 自定义仓库路径: 通过
git_data_dirs配置在/opt/gitlab-ce/git-data,非默认/var/opt/gitlab - OIM 登录表为
im_user: 通过 MySQL general_log 捕获实际 SQL - Docker MySQL root 密码修改:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpass'; FLUSH PRIVILEGES; - CCY.sql 导入: 先创建数据库,然后导入 SQL 文件
- GitLab 仓库下载取证:
Projects::RepositoriesController#archive= 下载仓库ZIP - GitLab 管理员密码重置: root 可通过 Admin::UsersController 重置其他用户密码
常见陷阱
| 陷阱 | 说明 |
|---|---|
| 时区问题 | 日志中的时间多为 UTC,需 +8h 转换为 中国时区 |
| 干扰数据库 | Docker 中可能有多个数据库,需以 application.yml 为准 |
| 中文编码 | MySQL 查询含中文字段必须加 --default-character-set=utf8mb4 |
| 手机号格式 | im_user.mobile 含 +86 前缀,答案需去掉前缀 |
| 自定义路径 | GitLab 仓库可能在非默认路径,需检查 git_data_dirs 配置 |
| ES 认证 bypass | basic license 下 native realm 不可用,需挂载数据到无认证容器 |
取证技巧总结
- 日志关联分析: 结合多条日志(Rails + Nginx + Audit)还原事件时间线
- general_log 捕获 SQL: 通过模拟 API 请求 + MySQL general_log 发现后端数据库操作
- 跨表关联查询: 当直接搜索为空时,尝试在其他相关表中查找线索
- Git 对象遍历: loose objects 是恢复被删除数据的有效途径
- JAR 包分析: fat JAR 可通过 unzip/jar 命令查看内部结构和依赖版本
附录:答案汇总
| 题目 | 问题简述 | 答案 |
|---|---|---|
| Q36 | systemd 开机自启服务数量 | 34 |
| Q37 | 系统内核编译时间(中国时区) | 2024-06-04 22:43:51 |
| Q38 | GitLab 服务端口 | 9999 |
| Q39 | GitLab 登录失败次数 | 6 |
| Q40 | GitLab root 用户密码 | abc123654 |
| Q41 | 仓库第一次提交时间(中国时区) | 2025-11-06 11:07:02 |
| Q42 | root 用户电子邮件 | wangdefa888@gmail.com |
| Q43 | Git仓库被谁下载传播(用户名) | Mia |
| Q44 | git remote 远程服务器地址 | 172.23.194.159 |
| Q45 | OIM 后台管理服务端口 | 13000 |
| Q46 | Spring Boot 框架版本 | 1.5.8 |
| Q47 | 登录时查询的数据库表 | im_user |
| Q48 | 删除的用户数量 | 510 |
| Q49 | xinchao 最早管理的群名 | 测试 |
| Q50 | ES 群消息数量 | 3 |
| Q51 | "小雨末" 手机号 | 14499466022 |
| Q52 | 贷款利息 | 0.8 |
报告生成时间:2026年5月16日 工具支持:Hermes Agent