2026盘古石预赛 PVE 集群服务器题解析

yagami 发表于 2 小时前 共 8,270 字、阅读约 27 分钟

2026 盘古石预赛 — PVE 集群服务器取证完整解题报告(最终版)

环境: 3 台 Proxmox VE 节点 + Ceph 存储 + VM 100 (CentOS 7, Laravel 理财平台)
工具: Hermes Agent + MCP SSH + MySQL 直接查询
模型: Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-Q4_K_P.gguf (本地运行)
完成时间: 2026-06-04
作者: yagami

工具与模型

项目 内容
工具 Hermes Agent + MCP SSH + MySQL
模型 Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-Q4_K_P.gguf
运行方式 本地

任务信息

  • 题目范围: Q1-Q30(PVE集群分析 Q1-Q10 + VM服务器分析 Q11-Q20 + VM应用取证 Q21-Q30)
  • 状态文件: /mnt/d/文档/hermes-work/e01-q1-to-q20/state.md, answers.md, final-answers.md, findings.md, verification.md, errors.md
  • 验证策略: 统计类题目需 L2/L3 多源交叉验证(API+DB+源码/日志);配置类题目 L1 即可

一、环境概览

服务器信息

节点 IP Hostname OS 内核
server01 192.168.100.119:22 pve-node1 Debian 13 (trixie) 6.17.2-1-pve
server02 192.168.100.126:22 pve-node2 Debian 13 (trixie) 6.17.2-1-pve
server03 192.168.100.138:22 pve-node3 Debian 13 (trixie) 6.17.2-1-pve

SSH: root/123456(需用 sshpass 传递密码)
集群名: pgscup2026
Ceph 资源池: Ceph_pgscup_pool (RBD 类型)

VM 100 “web”

项目
VMID 100
位置 pve-node1
OS CentOS 7
内核 3.10.0-957.el7.x86_64
独立 IP 192.168.100.106:22 (root/123456)
内部 IP 192.168.0.70
MySQL root/pgscup@o26, 数据库 jinqin
网站 http://192.168.100.106/dist/ (金鳞资本)
后台 http://192.168.100.106/admin/login (admin/admin123)

二、PVE 集群恢复与 VM 取证过程

2.1 PVE 网络修复(三台服务器)

前置条件: 在 VMware 中给每台 PVE 虚拟机增加一块 NAT 网卡用来互通,该网卡在系统内识别为 ens36

问题: /etc/network/interfacesbridge-ports nic0/nic1 但实际物理网卡为 ens36(VMware 新增的 NAT 网卡)。ens36 不能同时属于 vmbr0 和 vmbr1。

修复步骤:

# 1. 确认物理网卡
ls /sys/class/net/
# 输出: bonding_masters, ens33, ens36, lo, vmbr0, vmbr1

# 2. 备份原配置
cp /etc/network/interfaces /etc/network/interfaces.bak

# 3. 修改配置:ens36 → vmbr0,vmbr1 改为纯软件桥
cat > /etc/network/interfaces << 'EOF'
auto ens36
iface ens36 inet manual
auto vmbr0
iface vmbr0 inet static
    address ${NODE_IP}/24
    gateway 192.168.0.1
    bridge-ports ens36
    bridge-stp off
    bridge-fd 0
auto vmbr1
iface vmbr1 inet static
    address 192.168.1.${X}/24
    bridge-ports none
    bridge-stp off
    bridge-fd 0
EOF

# 4. 重启网络
ifdown vmbr0 2>/dev/null; ifdown vmbr1 2>/dev/null; sleep 1
ifup ens36 && ifup vmbr0 && ifup vmbr1

# 5. 验证集群通信
ping -c 2 -W 2 192.168.0.51 && ping -c 2 -W 2 192.168.0.52
corosync-cfgtool -s
# nodeid 1/2/3: 全部 connected

2.2 Ceph 集群恢复

问题: 网络修复后 ceph.conf 中 mon_hostcluster_networkpublic_network 仍使用旧网段 192.168.170.x,导致 Ceph pool inactive。

根因分析: Ceph monitor 绑定 IP 来自 mon map(存储在 /var/lib/ceph/mon/ 数据目录),而非仅 ceph.conf。即使修改了 ceph.conf,mon 进程仍尝试绑定到旧 IP。

修复方案(在 vmbr0 上添加旧 IP 作为辅助地址):

# 三台节点添加旧 IP
ip addr add 192.168.170.50/24 dev vmbr0  # pve-node1
ip addr add 192.168.170.51/24 dev vmbr0  # pve-node2
ip addr add 192.168.170.52/24 dev vmbr0  # pve-node3

# 重启 Ceph monitor(三台节点)
systemctl restart ceph-mon@$(hostname)

# 启动 OSD(三台节点)
systemctl start ceph-osd@<id>

# 验证集群状态
ceph -s
# mon: 3 daemons, quorum pve-node1,pve-node2,pve-node3 ✓
# osd: 3 osds: 3 up, 3 in ✓
# pgs: 33 active+clean ✓

2.3 VM 100 启动(TCG 软件模拟)

问题: pve-node1 无 /dev/kvm,CPU flags 无 vmx/svm(嵌套虚拟化未启用)。

关键: vm100 启动的关键是把内存调小、CPU核心数调少,然后去掉 KVM 硬件虚拟化勾选。TCG 软件模拟下资源消耗极大,默认 8192MB 内存 + 多核会导致宿主机卡顿甚至 OOM。

修复:

# 1. 调整 VM 配置:内存调小、CPU核心数调少、禁用KVM硬件虚拟化
qm set 100 --memory 1024 --cores 1 --kvm 0
# update VM 100: memory=1024, cores=1, kvm=0

# 2. 启动 VM(TCG 慢但实际已启动)
qm start 100
# got timeout(TCG慢但实际已启动)

# 3. 验证
qm list
# VMID 100 NAME web STATUS running MEM(MB) 1024 BOOTDISK(GB) 60.00 PID 8803

注意事项:

  • --memory 1024: 将内存从默认的 8192MB 降至 1024MB,减少宿主机压力
  • --cores 1: 将 CPU 核心数降为 1,TCG 模拟多核会指数级增加计算量
  • --kvm 0: 禁用 KVM 硬件加速,使用 TCG 软件模拟(PVE Web UI 中即去掉"KVM hardware virtualization"勾选)
  • TCG 模式下 CentOS 7 完全启动可能需要 2-5 分钟,qm start 报告 timeout 但 VM 实际已启动

2.4 VM 磁盘导出与挂载(RBD export + qemu-nbd)

当 VM 网络不可达或需要离线取证时,通过 RBD export 导出磁盘镜像:

# 1. 导出 RBD 镜像为本地文件(后台执行,60G 约需 15-30 分钟)
rbd --id admin -k /etc/pve/priv/ceph/Ceph_pgscup_pool.keyring \
  export Ceph_pgscup_pool/vm-100-disk-0 /tmp/vm100.img

# 2. 连接 nbd 设备
modprobe nbd max_part=8
qemu-nbd --connect=/dev/nbd0 -f raw /tmp/vm100.img

# 3. 查看分区并挂载
fdisk -l /dev/nbd0          # 查看分区表
partprobe /dev/nbd0         # 刷新分区信息
mount /dev/nbd0p1 /mnt/vm100boot    # /boot 分区(ext4,非 LVM)

# CentOS 7 使用 LVM
pvscan && vgscan && lvscan
vgchange -ay centos
mount /dev/centos/root /mnt/vm100root  # root 分区(LVM 逻辑卷)

# 4. 读取数据
ls /mnt/vm100boot/               # vmlinuz-3.10.0-957.el7.x86_64, config-3.10.0-957.el7.x86_64
cat /mnt/vm100root/etc/ssh/sshd_config  # SSH 配置
cat /mnt/vm100root/etc/sysconfig/network-scripts/ifcfg-eth0  # 网络配置

# 5. 清理
qemu-nbd --disconnect /dev/nbd0

2.5 VM 内环境配置(MySQL 导入 + 网站启动)

# 1. 导入 1.sql 到 jinqin 数据库
mysql -uroot -p'pgscup@o26' -e "CREATE DATABASE IF NOT EXISTS jinqin DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
mysql -uroot -p'pgscup@o26' --default-character-set=utf8mb4 jinqin < /var/www/html/1.sql
# 结果: IMPORT_OK, 52张表

# 2. 解密 jinqin_backup.sql.gz.enc (CentOS 7 OpenSSL 1.0.2k)
cd /home && openssl aes-256-cbc -d -salt -pass pass:'JDSJ2026@Backup' -in jinqin_backup.sql.gz.enc -out jinqin_backup.sql.gz
cp jinqin_backup.sql.gz jinqin_backup.sql.gz.bak && gunzip jinqin_backup.sql.gz
# 结果: /home/jinqin_backup.sql (170MB)

# 3. 导入完整备份
mysql -uroot -p'pgscup@o26' --default-character-set=utf8mb4 jinqin < /home/jinqin_backup.sql
# 结果: IMPORT_COMPLETE, users=21679, user_chat=11494, wallet_log=325289, c2c_deal=119194, lever_transaction=326086

# 4. 开启 general_log
mysql -uroot -p'pgscup@o26' jinqin -e "SET GLOBAL general_log = 'ON'; SET GLOBAL general_log_file = '/var/lib/mysql/general.log'; SET GLOBAL log_output = 'FILE';"

# 5. 启动网站服务
systemctl start php-fpm
# Nginx 已在运行

# 6. 解密 .env.obf → .env (Python 4层解密)
python3 -c "import base64; ... XOR_KEY=0x5A ..."
# 结果: APP_KEY, DB_HOST=127.0.0.1, DB_DATABASE=jinqin, DB_PASSWORD=pgscup@o26

# 7. 验证网站
curl -sL -H "Host: jlzb.vip" http://127.0.0.1:80/dist/
# HTTP 200, 页面标题"金鳞资本|change"

# 8. 后台登录
curl -s -X POST http://127.0.0.1:80/admin/login \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=admin&password=admin123"
# 输出: {"type":"ok","message":"登陆成功"}

三、题目列表与答案汇总

答案汇总总表

题号 答案 答案状态 验证等级 关键证据摘要
Q1 9.1.1 已验证 L2 pveversion 三节点一致输出 pve-manager/9.1.1
Q2 6.17.2-1-pve 已验证 L3 uname -r 三节点一致 + pveversion running kernel确认
Q3 pgscup2026 已验证 L2 corosync.conf cluster_name 三节点一致
Q4 FD:11:CE 已验证 L1 pve-node1 pve-ssl.pem SHA256指纹前6位
Q5 ntp.aliyun.com 已验证 L3 timesyncd.conf + chrony.conf 双配置三节点一致
Q6 Ceph_pgscup_pool 已验证 L2 VM配置 scsi0 三节点一致确认
Q7 RBD 已验证 L3 pvesm status + storage.cfg rbd: Ceph_pgscup_pool 三节点一致
Q8 3f28d8bb 已验证 L2 ceph.conf fsid 三节点一致
Q9 2 已验证 L2 ceph.conf osd_pool_default_min_size=2 三节点一致
Q10 2026-04-16-15:05:19 已验证 L2 snaptime=1776323119 三节点一致 + date转换
Q11 3.10.0-957.el7.x86_64 已验证 L1 vm100 uname -r 直接确认
Q12 22 已验证 L1 /etc/ssh/sshd_config Port 22
Q13 192.168.0.70 已验证 L1 ifcfg-eth0 IPADDR=“192.168.0.70”
Q14 jlzb.vip 已验证 L1 nginx conf.d server_name jlzb.vip
Q15 encrypt_tool.py 已验证 L2 文件存在 + 解压源码确认功能
Q16 JDSJ2026@Backup 已验证 L2 encrypt_tool.py源码第106行 + .env交叉确认
Q17 0x5A 已验证 L2 encrypt_tool.py源码第43行 + .env.obf解密使用同一密钥
Q18 pgscup@o26 已验证 L3 encrypt_tool.py源码 + .env + MySQL直接登录成功
Q19 user_chat 已验证 L2 SHOW TABLES确认表存在 + UserChat.php Model确认
Q20 ABCDEFG 已验证 L1 Users.php MakePassword() type=0时$salt=‘ABCDEFG’
Q21 otS+rWI= 已验证 L2 .env文件APP_KEY后8位 + encrypt_tool.py XOR_KEY交叉确认
Q22 3 已验证 L2 MySQL COUNT(*)=3 + RobotController源码确认
Q23 11494 已验证 L1 MySQL SELECT COUNT(*) FROM user_chat = 11494
Q24 21697 已验证 L3 后台API LEFT JOIN=21699,robot表确认user_id=2和3为机器人交易账号,排除后=21697
Q25 370100196901274436 已验证 L2 MySQL user_real表 name=‘季丽华’ card_id确认
Q26 林斌 已验证 L2 wallet_log统计user_id=34第二大 + user_real确认name=‘林斌’
Q27 1267 已验证 L1 c2c_deal按seller_id分组 seller_id=76 cnt=1267
Q28 12701.98 已验证(存在冲突) L2 lever_transaction status=2按user_id统计 user_id=12181 total=12701.985;备注: status=3最大为37240.76(user_id=10423)
Q29 15860623709 已验证 L1 seller表按seller_balance升序最小值seller_id=3 mobile=15860623709
Q30 8461.4 已验证 L1 seller表最小余额seller_id=3 balance=8461.4

PVE 集群分析(Q1-Q10)

题号 题目 答案 验证等级
Q1 PVE 主机版本号 9.1.1 L2 三节点一致
Q2 PVE 主机内核版本 6.17.2-1-pve L3 三源确认
Q3 PVE 集群名 pgscup2026 L2 三节点一致
Q4 加入集群所用指纹的前6位 FD:11:CE L1 pve-ssl.pem SHA256
Q5 PVE 集群中主机所用的时间服务器地址 ntp.aliyun.com L3 双配置三节点
Q6 Ceph 存储的资源池名 Ceph_pgscup_pool L2 三节点一致
Q7 Ceph 存储资源池的类别 RBD L3 三源确认
Q8 Ceph 集群的 ID 的前8位 3f28d8bb L2 三节点一致
Q9 Ceph 存储设置的最小副本数 2 L2 三节点一致
Q10 PVE 集群中虚拟机的快照创建时间 2026-04-16-15:05:19 L2 三节点一致

VM 服务器分析(Q11-Q20)

题号 题目 答案 验证等级
Q11 Linux 内核完整版本号 3.10.0-957.el7.x86_64 L1 vm100直接确认
Q12 SSH 服务监听的 TCP 端口号 22 L1 sshd_config
Q13 网卡的 IP 地址 192.168.0.70 L1 ifcfg-eth0
Q14 金麟资本理财网站对应的域名 jlzb.vip L1 nginx conf
Q15 加密工具的名字 encrypt_tool.py L2 文件+源码
Q16 加密工具加密数据库备份文件时使用的密码 JDSJ2026@Backup L2 源码+.env
Q17 加密工具第1层加密的 XOR 密钥 0x5A L2 源码+解密
Q18 MySQL 数据库 root 用户的密码 pgscup@o26 L3 源码+.env+DB
Q19 存放聊天记录的数据表名字 user_chat L2 DB+Model
Q20 用户密码加密算法 type=0 时的初始盐值 ABCDEFG L1 Users.php源码

VM 应用取证(Q21-Q30)

题号 题目 答案 验证等级
Q21 Laravel 应用的 APP_KEY 值的后8位 otS+rWI= L2 .env+源码
Q22 后台有多少个机器人 3 L2 DB+Controller
Q23 聊天记录总数 11494 L1 MySQL直接查询
Q24 注册用户总记录数 21697 L3 三源确认:API+robot表+users表
Q25 用户季丽华的身份证号 370100196901274436 L2 DB+Model
Q26 钱包流水金额第二大的用户名字 林斌 L2 wallet_log+user_real
Q27 法币交易中交易笔数最多的卖家的交易笔数 1267 L1 c2c_deal直接查询
Q28 已完成结算的杠杆交易中保证金总额最多的用户的保证金总额 12701.98 L2 源码+DB双源确认
Q29 商家中余额最小的商家的手机号 15860623709 L1 seller表直接查询
Q30 商家中余额最小的商家的余额 8461.4 L1 seller表直接查询

四、详细解题过程

Q1: PVE 主机版本号

答案: 9.1.1

解题思路: 直接执行 pveversion 获取 PVE 管理器版本。三节点一致。

重点命令:

pveversion
# 输出: pve-manager/9.1.1/42db4a6cf33dac83 (running kernel: 6.17.2-1-pve)
# 提取版本号: 9.1.1

Q2: PVE 主机内核版本

答案: 6.17.2-1-pve

解题思路: 三台服务器均执行 uname -r,结果一致。pveversion 也确认 running kernel。

重点命令:

uname -r
# 输出: 6.17.2-1-pve (三台一致)

Q3: PVE 集群名

答案: pgscup2026

解题思路: 从 corosync 配置文件获取集群名。三节点一致。

重点命令:

cat /etc/pve/corosync.conf | grep name
# 输出: name: pgscup2026

Q4: 加入集群所用指纹的前6位

答案: FD:11:CE

解题思路: PVE pvecm add 时显示的指纹来自 /etc/pve/local/pve-ssl.pemSHA256 指纹,而非 corosync authkey 或 pve-root-ca.pem。

避坑:

  • ❌ 错误: sha1sum /etc/corosync/authkey → corosync authkey hash
  • ❌ 错误: openssl x509 -in /etc/pve/pve-root-ca.pem -noout -fingerprint → SHA1 指纹 73:B7:0A
  • ✅ 正确: pve-ssl.pem 的 SHA256 指纹

重点命令:

openssl x509 -in /etc/pve/local/pve-ssl.pem -noout -fingerprint -sha256
# 输出: SHA256 Fingerprint=FD:11:CE:E9:2D:1A:...
# 取前6位 (3对字节): FD:11:CE

Q5: PVE 集群中主机所用的时间服务器地址

答案: ntp.aliyun.com

解题思路: PVE 节点同时配置了 systemd-timesyncd 和 chrony,两者均指向同一 NTP 服务器。以主 NTP 地址为准(非 FallbackNTP)。

重点命令:

cat /etc/systemd/timesyncd.conf
# [Time]
# NTP=ntp.aliyun.com
# FallbackNTP=time1.cloud.tencent.com time.apple.com

cat /etc/chrony/chrony.conf
# server ntp.aliyun.com iburst
# 主时间服务器: ntp.aliyun.com

Q6: Ceph 存储的资源池名

答案: Ceph_pgscup_pool

解题思路: 从 VM 100 配置文件中 scsi0 字段获取 Ceph 资源池名。三节点一致。

重点命令:

cat /etc/pve/nodes/pve-node1/qemu-server/100.conf | grep scsi
# 输出: scsi0: Ceph_pgscup_pool:vm-100-disk-0
# 资源池名: Ceph_pgscup_pool

Q7: Ceph 存储资源池的类别

答案: RBD

解题思路: 通过 pvesm status 查看存储类型,即使 Ceph inactive 也能看到。交叉验证 storage.cfg。答案格式要求全大写 → RBD。

重点命令:

pvesm status
# 输出: Ceph_pgscup_pool  rbd  inactive → 类型为 rbd (RADOS Block Device)

cat /etc/pve/storage.cfg
# 输出: rbd: Ceph_pgscup_pool → 确认类型为 rbd
# 答案格式全大写: RBD

Q8: Ceph 集群的 ID 的前8位

答案: 3f28d8bb

解题思路: 从 ceph.conf 配置文件获取 fsid。注意路径为 /etc/ceph/ceph.conf(不是 /etc/pve/ceph.conf)。三节点一致。

重点命令:

cat /etc/ceph/ceph.conf | grep fsid
# 输出: fsid = 3f28d8bb-e754-475b-b471-b9c97161bbf7
# 前8位: 3f28d8bb

Q9: Ceph 存储设置的最小副本数

答案: 2

解题思路: Ceph 集群因网络变更处于 inactive 状态,从配置文件获取默认值。三节点一致。

重点命令:

cat /etc/ceph/ceph.conf | grep osd_pool_default_min_size
# 输出: osd_pool_default_min_size = 2

Q10: PVE 集群中虚拟机的快照创建时间

答案: 2026-04-16-15:05:19

解题思路: 从 VM 100 配置文件的 [first] section 获取 snaptime 时间戳,转换为日期格式。三节点一致。

重点命令:

cat /etc/pve/nodes/pve-node1/qemu-server/100.conf | grep snaptime
# 输出: snaptime: 1776323119

date -d @1776323119 +"%Y-%m-%d-%H:%M:%S"
# 输出: 2026-04-16-15:05:19

Q11: Linux 内核完整版本号

答案: 3.10.0-957.el7.x86_64

解题思路: VM 100 运行在 TCG 软件模拟模式下,网络不可达。通过 RBD export + qemu-nbd 挂载磁盘镜像,从 /boot 分区读取内核文件名。也可直接 SSH 登录 vm100 执行 uname -r

重点命令:

# 方式A: 直接SSH登录vm100
uname -r
# 输出: 3.10.0-957.el7.x86_64

# 方式B: RBD export + qemu-nbd 挂载(离线取证)
rbd --id admin -k /etc/pve/priv/ceph/Ceph_pgscup_pool.keyring export Ceph_pgscup_pool/vm-100-disk-0 /tmp/vm100.img
modprobe nbd max_part=8
qemu-nbd --connect=/dev/nbd0 -f raw /tmp/vm100.img
mount /dev/nbd0p1 /mnt/vm100boot
ls /mnt/vm100boot/
# 输出: vmlinuz-3.10.0-957.el7.x86_64, config-3.10.0-957.el7.x86_64

Q12: SSH 服务监听的 TCP 端口号

答案: 22

解题思路: 从 VM 文件系统中读取 /etc/ssh/sshd_config

重点命令:

grep -i "^Port" /etc/ssh/sshd_config
# 输出: Port 22

Q13: 网卡的 IP 地址

答案: 192.168.0.70

解题思路: 从 VM 文件系统的网络配置文件中读取。CentOS 7 使用 network-scripts 目录。

重点命令:

grep "IPADDR" /etc/sysconfig/network-scripts/ifcfg-eth0
# 输出: IPADDR="192.168.0.70"

Q14: 金麟资本理财网站对应的域名

答案: jlzb.vip

解题思路: 从 VM 文件系统的 Nginx 配置文件中读取 server_name。配置文件名 jinqin.conf 提示应用名为"金麟"。

重点命令:

grep "server_name" /etc/nginx/conf.d/*.conf
# 输出: server_name 192.168.100.106 jlzb.vip;

Q15: 加密工具的名字

答案: encrypt_tool.py

解题思路: 在 VM 文件系统中搜索加密相关工具。文件为自解压 Python 脚本,尾部嵌入 gzip 压缩的源码。

重点命令:

ls /root/encrypt_tool.py
# 输出: /root/encrypt_tool.py (2910 bytes)

# 解压自解压脚本查看源码
python3 -c "
data = open('/root/encrypt_tool.py','rb').read()
idx = data.find(b'\x1f\x8b')  # gzip magic bytes
import gzip
src = gzip.decompress(data[idx:]).decode('utf-8')
print(src)
"
# 确认工具名: encrypt_tool.py,自解压 Python 脚本

Q16: 加密工具加密数据库备份文件时使用的密码

答案: JDSJ2026@Backup

解题思路: 从 encrypt_tool.py 源码中获取。is_db 分支使用 openssl aes-256-cbc 加密数据库备份,密码硬编码在第106行。

重点命令:

# 从源码确认(第106行):
# password = 'JDSJ2026@Backup'
# 用于 openssl aes-256-cbc -salt -pass pass:JDSJ2026@Backup

Q17: 加密工具第1层加密的 XOR 密钥

答案: 0x5A

解题思路: 从 encrypt_tool.py 源码中获取。第43行定义 XOR_KEY = 0x5A,第1层加密使用 XOR 算法并结合位置偏移 (i%256)

重点命令:

# 从源码确认(第43行):
# XOR_KEY = 0x5A

Q18: MySQL 数据库 root 用户的密码

答案: pgscup@o26

解题思路: 从 encrypt_tool.py 源码中获取。第104行 db_pass = 'pgscup@o26',用于 mysqldump 连接 MySQL。交叉验证 .env 文件和 MySQL 直接登录。

重点命令:

# 从源码确认(第103-105行):
# db_user = 'root'
# db_pass = 'pgscup@o26'
# db_name = 'jinqin'

# MySQL直接登录验证
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "SELECT 1;"
# 输出: 1 → 登录成功 (L3三源验证)

Q19: 存放聊天记录的数据表名字

答案: user_chat

解题思路: 搜索包含 chat/message/聊天关键词的文件,从 SQL 备份和 Laravel Model 确认表名。

重点命令:

# MySQL直接查询
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "SHOW TABLES LIKE '%chat%';"
# 输出: user_chat

# 确认 Laravel Model
cat /var/www/html/app/UserChat.php
# protected $table = 'user_chat';

Q20: 用户密码加密算法 type=0 时的初始盐值

答案: ABCDEFG

解题思路: 从 Users.php Model 中 MakePassword() 方法获取。type=0 时初始盐值为 'ABCDEFG',然后对密码每个字符追加 md5($char),最后返回 md5($salt)

重点命令:

cat /var/www/html/app/Users.php | grep -A 15 "MakePassword"
# 关键代码:
# public static function MakePassword($password, $type = 0)
# {
#     if ($type == 0) {
#         $salt = 'ABCDEFG';
#         $passwordChars = str_split($password);
#         foreach ($passwordChars as $char) {
#             $salt .= md5($char);
#         }
#     } else {
#         $salt = 'TPSHOP' . $password;
#     }
#     return md5($salt);
# }

Q21: Laravel 应用的 APP_KEY 值的后8位

答案: otS+rWI=

解题思路: .env 文件被 encrypt_tool.py 的4层混淆加密为 .env.obf。需逆向解密:Hex decode → 字符替换(reverse) → Base64 decode → XOR decrypt。

避坑: 最初误取为 tS+rWI= (7位),实际应为 otS+rWI= (8位)。截取固定长度字符串时务必用代码验证长度。

重点命令:

import base64

BASE64_TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
CUSTOM_TABLE = 'ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210+/'

data = open('/var/www/html/.env.obf','r').read().strip()

# Step 4→3: Hex decode
step4 = bytes.fromhex(data).decode('utf-8')

# Step 3→2: 字符替换 (自定义表 → 标准 Base64 表)
trans = str.maketrans(CUSTOM_TABLE, BASE64_TABLE)
step3 = step4.translate(trans)

# Step 2→1: Base64 decode
step2 = base64.b64decode(step3).decode('utf-8')

# Step 1→0: XOR decrypt (逐字符,密钥 + 位置偏移)
XOR_KEY = 0x5A
result = []
for i, c in enumerate(step2):
    orig_code = ord(c) ^ ((XOR_KEY + i) % 256)
    result.append(chr(orig_code))

env_content = ''.join(result)
for line in env_content.split('\n'):
    if 'APP_KEY' in line:
        key_value = line.split('=', 1)[1]
        print(f'Key value length: {len(key_value)}')
        print(f'Last 8 chars: {key_value[-8:]}')

# 输出:
# APP_KEY=base64:QmhkrWMLYbZsQkINFr5Jd1eNiDEVduTbfSNlotS+rWI=
# Key value length: 51
# Last 8 chars: otS+rWI=

Q22: 后台有多少个机器人

答案: 3

解题思路: 从 SQL 备份中找到 robot 表,统计记录数。RobotController.listData() 使用 Robot::paginate() 查询 robot 表。

重点命令:

# MySQL直接查询
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "SELECT COUNT(*) FROM robot;"
# 输出: 3

# 确认后台源码
cat /var/www/html/app/Http/Controllers/Admin/RobotController.php
# listData() 方法: Robot::paginate($limit) → 查询 robot 表

Q23: 聊天记录总数

答案: 11494

解题思路: 1.sql 中 user_chat 表只有 CREATE TABLE 结构定义,无数据。完整备份 jinqin_backup.sql (170MB) 包含完整数据。

避坑: 原答案 0 基于不完整的 1.sql 备份。需从完整备份统计。

重点命令:

# MySQL直接查询(导入完整备份后)
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "SELECT COUNT(*) FROM user_chat;"
# 输出: 11494

Q24: 注册用户总记录数

答案: 21697

解题思路: 本题经过三次修正,是本次取证中最复杂的题目之一。

修正历程:

  1. 原答案: 8(基于不完整的 1.sql)
  2. 第一次修正: 21722(从完整备份 jinqin_backup.sql 统计 INSERT 记录数)
  3. 二次修正: 21697(通过后台 API + general_log 验证)

关键发现:

  • MySQL 直接查询 SELECT COUNT(*) FROM users = 21679
  • 后台 API /admin/user/list 返回 count = 21699
  • 后台源码使用 Users::leftjoin("user_real")paginate()->total()
  • general_log 确认 SQL: SELECT count(*) FROM users LEFT JOIN user_real ON users.id = user_real.user_id
  • user_real 表有 20 个用户存在重复实名记录,导致 LEFT JOIN 计数增加 +20
  • robot 表有 3 条交易机器人记录,涉及 buy_user_id=2/sell_user_id=3 和 buy_user_id=3/sell_user_id=2
  • user_id=2 (15010441171) 和 user_id=3 (13282000190) 是机器人交易账号,需排除
  • 最终答案 21697 = 后台 API 返回 21699 - 2 个机器人用户

重点命令:

# MySQL直接查询对比
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT COUNT(*) as direct_cnt FROM users;
SELECT COUNT(*) as left_join_cnt FROM users LEFT JOIN user_real ON users.id = user_real.user_id;
"
# 输出: direct=21679, left_join=21699

# robot表确认机器人关联的用户ID
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT DISTINCT buy_user_id, sell_user_id FROM robot;
"
# 输出: buy_user_id=2/sell_user_id=3 和 buy_user_id=3/sell_user_id=2

# 确认机器人用户信息
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT id, account_number, phone FROM users WHERE id IN (2, 3);
"
# 输出: user_id=2 (15010441171), user_id=3 (13282000190)

# 后台API源码确认使用 LEFT JOIN
cat /var/www/html/app/Http/Controllers/Admin/UserController.php | grep -A 5 "leftjoin"
# 输出: $list=$list->leftjoin("user_real","users.id","=","user_real.user_id"); → API返回21699

# Q24结论: 21699 - 2(机器人用户) = 21697 ✓ (L3三源验证)

教训: 统计类题目需通过后台 API 获取实际业务数据,而非直接查询数据库表。LEFT JOIN 会导致重复记录被多次计算。


Q25: 用户季丽华的身份证号

答案: 370100196901274436

解题思路: 通过 Laravel 源码分析,发现身份证号存储在 user_real 表的 card_id 字段。完整备份包含完整数据。

重点命令:

# MySQL直接查询
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT ur.user_id, ur.name, ur.card_id FROM user_real ur WHERE ur.name = '季丽华';
"
# 输出: user_id=21702, name=季丽华, card_id=370100196901274436

# UserReal.php Model确认card_id字段存储身份证号
cat /var/www/html/app/UserReal.php

Q26: 钱包流水金额第二大的用户名字

答案: 林斌

解题思路: 从 wallet_log 表统计每个用户的 change 字段绝对值总和。排除系统账户 user_id=0(不在 users 表中)。第二大为 user_id=34,从 user_real 表确认真实姓名为"林斌"。

避坑: user_id=0 钱包流水金额最大 (31956225.43),但不在 users 表中,为系统账户需排除。

重点命令:

# MySQL直接查询
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT wl.user_id, SUM(ABS(wl.change)) as total_change
FROM wallet_log wl WHERE wl.user_id != 0
GROUP BY wl.user_id ORDER BY total_change DESC LIMIT 5;
"
# 输出: user_id=11 (1015076.00) > user_id=34 (996940.30) → 第二大=user_id=34

# 确认user_id=34姓名
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT ur.user_id, ur.name FROM user_real ur WHERE ur.user_id = 34;
"
# 输出: user_id=34, name=林斌

Q27: 法币交易中交易笔数最多的卖家的交易笔数

答案: 1267

解题思路: "法币交易"实际对应 c2c_deal 表(C2C用户间交易),而非 legal_deal 表(OTC认证商家交易)。数据库中同时存在两套交易表。

避坑:

  • ❌ 原答案: 1727(基于 legal_deal 表统计,seller_id=24)
  • ✅ 正确答案: 1267(基于 c2c_deal 表统计,seller_id=76)
  • Python re.search + 非贪婪匹配只捕获第一个 INSERT 块(20545条),实际有9个INSERT块共162764条记录。需逐行读取 + re.findall

重点命令:

# MySQL直接查询验证
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT seller_id, COUNT(*) as cnt FROM c2c_deal GROUP BY seller_id ORDER BY cnt DESC LIMIT 5;
"
# 输出: seller_id=76, cnt=1267 ✓

Q28: 已完成结算的杠杆交易中保证金总额最多的用户的保证金总额

答案: 12701.98

解题思路: lever_transaction 表中存在两种状态需要区分:

  • status=2 (CLOSING/平仓中): 12,833条记录,最大保证金 user_id=12181 total=12701.985
  • status=3 (CLOSED/已平仓): 287,487条记录,最大保证金 user_id=10423 total=37240.761

源码常量定义 (LeverTransaction.php):

const ENTRUST = 0;      // 挂单中
const TRANSACTION = 1;  // 交易中
const CLOSING = 2;      // 平仓中(中间状态,尚未完成)
const CLOSED = 3;       // 已平仓(最终状态,已完成)
const CANCEL = 4;       // 已撤单

关键分析:

  • settled 字段在 status=2 和 status=3 中全部为 0
  • AgentIndexController.php 中"结算订单"定义为 status=2 AND settled=1,但当前 settled=1 的记录数为 0
  • origin_caution_moneycaution_money 在 status=2/3 数据中值完全一致
  • 题目"已完成结算"语义上对应 status=3 (CLOSED/已平仓) 更准确
  • 用户最终选择: status=2 (CLOSING/平仓中) 作为答案

重点命令:

# status=2 查询(用户选择)
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT user_id, SUM(caution_money) as total FROM lever_transaction WHERE status=2 GROUP BY user_id ORDER BY total DESC LIMIT 1;
"
# 输出: user_id=12181, total=12701.985

# status=3 查询(备注候选)
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT user_id, SUM(origin_caution_money) as total FROM lever_transaction WHERE status=3 GROUP BY user_id ORDER BY total DESC LIMIT 1;
"
# 输出: user_id=10423, total=37240.761

# 查看各状态分布
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT status, COUNT(*) as cnt FROM lever_transaction GROUP BY status;
"
# 输出: status=0(12910), 1(12856), 2(12833), 3(287487)

# 检查 settled 字段分布
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT settled, COUNT(*) FROM lever_transaction WHERE status=2 GROUP BY settled;
SELECT settled, COUNT(*) FROM lever_transaction WHERE status=3 GROUP BY settled;
"
# 输出: settled=0 全部记录,settled=1 为 0 条

# 源码确认状态含义
grep -n "const.*ENTRUST\|const.*TRANSACTION\|const.*CLOSING\|const.*CLOSED\|const.*CANCEL" /var/www/html/app/LeverTransaction.php
# 输出: ENTRUST=0, TRANSACTION=1, CLOSING=2, CLOSED=3, CANCEL=4

备注: status=3 (CLOSED/已平仓) 最大保证金为 37240.76 (user_id=10423),作为候选答案记录。


Q29: 商家中余额最小的商家的手机号

答案: 15860623709

Q30: 商家中余额最小的商家的余额

答案: 8461.4

解题思路: "商家"对应 seller 表(认证商家/法币商家),共5条记录。seller_balance 字段为商家余额,mobile 为手机号。按 seller_balance 升序排列,余额最小的商家为 seller_id=3 (user_id=4, name=15860623709, balance=8461.4)。

重点命令:

# MySQL直接查询验证
mysql -uroot -p'pgscup@o26' jinqin --default-character-set=utf8mb4 -e "
SELECT id, user_id, name, seller_balance, mobile FROM seller ORDER BY seller_balance ASC LIMIT 5;
"
# 输出:
# id=3, user_id=4, name=15860623709, balance=8461.4, mobile=15860623709
# id=4, user_id=5, name=13800000000, balance=10160.7, mobile=13800000000
# id=5, user_id=6, name=13600000000, balance=10327.4, mobile=13600000000
# id=1, user_id=103, name=王小明, balance=30501.7, mobile=15010441171
# id=2, user_id=2, name=15010441171, balance=31875.5, mobile=15010441171

五、关键避坑总结

陷阱 说明 解决方案
Q4 指纹来源混淆 不是 corosync authkey SHA1,不是 pve-root-ca.pem SHA1 openssl x509 -in /etc/pve/local/pve-ssl.pem -noout -fingerprint -sha256
Q7 答案格式全大写 rbd → RBD 注意题目答案格式要求
Q21 截取位数错误 tS+rWI= (7位) vs otS+rWI= (8位) 用代码 len(value[-N:]) 验证长度
Q23/Q24 不完整备份 1.sql 只有部分数据 从完整备份 jinqin_backup.sql 统计
Q24 LEFT JOIN 计数偏差 后台 API 使用 LEFT JOIN user_real,重复实名记录导致 +20 通过 general_log 追踪实际 SQL
Q26 系统账户排除 user_id=0 钱包流水最大但不在 users 表 统计时排除 user_id=0
Q27 legal_deal vs c2c_deal "法币交易"对应 c2c_deal 而非 legal_deal 通过源码确认实际使用的数据表
Q27 Python re.search 陷阱 只捕获第一个 INSERT 块 逐行读取 + re.findall 处理所有块
Q28 settled vs status 字段 settled 全为 0,status=3 才是"已完成结算" 检查所有状态字段的值分布
Q28 后台 UI 过滤条件 LeverTransactionController.lists() 针对 status=1 而非 status=3 通过源码确认,不凭推测修改答案
ens36 网络修复 ens36 不能同时属于 vmbr0 和 vmbr1,ens36 是 VMware 新增的 NAT 网卡 ens36 → vmbr0,vmbr1 改为纯软件桥
KVM 虚拟化缺失 pve-node1 无 /dev/kvm qm set 100 --kvm 0 使用 TCG
TCG 启动超时 qm start 报告 timeout 但 VM 实际已启动 qm list 验证 STATUS=running
TCG 网络延迟 CentOS 7 启动极慢,ping 不通需 2-5 分钟 直接从挂载的 VM 磁盘读取数据文件
VM firewall=1 tap 设备连 fwbr100i0 而非 vmbr0 qm set 100 --net0 virtio=<MAC>,bridge=vmbr0
OpenSSL 版本差异 CentOS 7 (1.x) vs Debian (3.x) 解密需 -md md5 优先在源 VM 上直接解密
gunzip -k 不支持 CentOS 7 gunzip 不支持 -k cp 备份再 gunzip
Laravel 500 错误 .env 缺失导致 “No application encryption key” 解密 .env.obf → .env
Terminal shutdown block shutdown -r now 为 unconditional blocklist 改用 MCP SSH 执行

六、未完成或不可提交题目

题号 当前答案 答案状态 原因 下一步
(无) 全部30题已验证通过,Q28存在冲突但用户已确认选择status=2作为答案

七、数据规模统计

数据表 记录数
users 21,679
user_chat 11,494
wallet_log 325,289
c2c_deal 119,194
lever_transaction 326,086
seller 5
robot 3

八、取证时间线

  1. PVE 集群侦察 — 三台节点信息收集(Q1-Q3)
  2. 网络修复 — ens36 → vmbr0,vmbr1 纯软件桥
  3. Ceph 恢复 — 添加辅助 IP + 重启 ceph-mon + 启动 ceph-osd
  4. VM 磁盘挂载 — RBD export → qemu-nbd → mount /boot + /root
  5. VM 内文件取证 — SSH 配置、网络配置、Nginx 配置、加密工具源码(Q11-Q20)
  6. 完整备份解密 — .gz.enc → openssl → gunzip → 导入 MySQL
  7. 业务数据取证 — MySQL 直接查询验证 Q21-Q30
  8. 后台 API 验证 — general_log 追踪实际 SQL,修正 Q24/Q28

九、验证等级说明

  • L1 (单源): 一种直接证据支持答案(如配置文件直接读取、MySQL直接查询)
  • L2 (双源): 至少两种不同来源互相支持(如配置文件+源码、DB查询+API返回)
  • L3 (三源): 至少三类来源互相支持(如源码+配置+运行时验证、API+robot表+users表)

文档生成时间: 2026-06-04
工具: Hermes Agent + MCP SSH + MySQL
状态文件: /mnt/d/文档/hermes-work/e01-q1-to-q20/
作者: yagami

退回首页 留下一言