一、服务器取证
重构服务器
忠心感谢山警、小谢取证和406,谢谢你们
失败版连接(但是连上ssh了)
有4个镜像,是一个服务器集群Kubernetes (K8s)
实在是不会搭这种服务器,我们跟着山警和小谢的教程走一遍吧
https://mp.weixin.qq.com/s/xRqFqB1YFDs1oKWJK0MCTA?scene=1&click_id=4
https://mp.weixin.qq.com/s/APyP-mcd40kGCn2U1RKrZA
上来是先ip a看看网卡


然后是cat /etc/host看看hosts

看完之后,我们发现了有俩个node节点,因为是服务器集群,ip动了会很麻烦
所以我们选择保留ip地址,把nat的网段改成192.50.1/24


ping一下网关192.168.50.2
可以ping通
然后我们systemctl status sshd快速检查 SSHD(Secure Shell Daemon)服务的当前运行状态和关键配置信息

发现SSHD服务正在运行,所以我们可以用主机连ssh


ip就是ip,端口可以看到是22,FinalShell成功连上
然后再看看k8s的配置情况
kubectl get namespaces -A
kubectl get pods -A
kubectl get services -A



我这边的pods似乎是不存在error情况,如果存在的话可以使用命令
kubectl describe pods nfs-client-provisioner-79cc77f98-87xts -n nfs-storageclass
现在我们已经连上了FinalShell
在刚刚查service我们还看见了mysql

同时在finalshell可以看到这些配置文件,可以全部下下来看看

我们先把这些配置文件全部下载到本地方便查看
这些配置文件大致可以分成五部分

这样子五部分
下边引用一下山警的介绍
这里介绍一下k8s中的一些基本概念
- Deployment:
- 类型: 工作负载资源 (Workload Resource)
- 作用: 定义了应用程序的期望状态,负责管理和更新Pod(例如,创建、更新、扩缩容Pod)。它确保在任何给定时间都有指定数量的Pod在运行。
- PVC (Persistent Volume Claim) :
- 类型: 存储资源 (Storage Resource)
- 作用: 是用户对存储的需求声明。它请求特定大小和访问模式的持久化存储,并由Kubernetes动态或静态地与一个PV(Persistent Volume)进行绑定。
- Service:
- 类型: 网络资源 (Networking Resource)
- 作用: 定义了一组Pod的逻辑抽象,并为它们提供一个稳定的网络访问方式(一个固定的IP地址和DNS名称)。它使得应用程序的其他部分或其他服务能够发现并与这组Pod进行通信,而无需关心Pod的实际IP地址变化。
- ConfigMap:
- 类型: 配置资源 (Configuration Resource)
- 作用: 用于存储非敏感的配置数据,例如环境变量、命令行参数或配置文件。它将配置数据与应用程序镜像解耦,使得应用程序可以在不重新构建镜像的情况下轻松更改配置。
这些yaml就是为对应的服务配置了这些api资源对象
再次感谢山警公众号的指导
接下来我们先进行对于MySQL的重建

这边可以看到有一个configmap,一个deplovment和一个pvc
我们肯定要用mysql80的pvc
所以我们这边使用kubectl apply -f.yaml添加这些资源对象
kubectl apply -f mysql-c.yaml
kubectl apply -f mysql-d.yaml
kubectl apply -f mysql57-pvc.yaml
kubectl apply -f mysql80-pvc.yaml
kubectl apply -f mysql-services.yaml

都配置一下
之后再去看看kubectl get pods -A

额,怎么是pending
kubectl describe pod mysql80-5fc9f7b6f7-9lj97 -n default看看情况吧,主要看Events


???说少一个mysql80-pvc???我不是刚刚配完吗

噢不是没配,是mysql80-pvc 本身也处于 Pending状态,这意味着Kubernetes无法为它提供所需的存储卷。所以,依赖这个PVC的MySQL Pod自然也就无法启动
所以是名为 nfs-client的 StorageClass 动态制备PV(PersistentVolume)的过程失败了
我们看看nfs的情况吧systemctl status nfs

噢原来是压根没启动啊,完全不会,那就启动一下吧
sudo systemctl start nfs-server

好了嗷,这下成功running了
但是还是显示pending,我们问问看ai

欸我说。。不会四个全要一起仿真开着才行吧。。。
我试试看吼。。

好我全打开了
这边那些pending啥的是全没了,变成一个新的看不懂的了
不对啊。。。mysql怎么还是pending。。ContainerCreating又是啥状态。。

实在不行我们先delete删除一下然后再开好了
kubectl delete pod mysql80-5fc9f7b6f7-9lj97 -n default

重启依旧pending。。说明确实是出问题了,可能存在污名等

好!有人说是要这个样子调,我直接全删了我们重来一遍!
成功版连接
(我的意思是和山警这种正常了)

我去,这样子打开之后真的和山警的一模一样是三个error了,MySQL也好起来了
终于可以继续跟着教程走了
三个error,当然是分别查看了
kubectl describe pods nfs-client-provisioner-79cc77f98-87xts -n nfs-storageclass
kubectl describe pods redis-8b84f48-5pdqx
kubectl describe pods captcha-bot-6b4d85b765-25xq6
主要看Events,按顺序分别如下



我们一个个看
首先第一个nfs-client-provisioner-79cc77f98-87xts,分析出来差不多是nfs的问题
我们知道了四台服务器,一个master,两个node,那那个计算机04其实就是nfs
去04看看nfs的情况
systemctl status nfs

这边可以看到其实nfs是在动的,但是就算delete重启还是显示error

这个时候没招了,想到去nmap一下,发现了filtered
应该是防火墙的问题,我们继续在04虚拟机输入指令systemctl stop firewalld

OK去掉之后再nmap一下发现确实没了
这个时候delete一下pod就有了
kubectl delete pod nfs-client-provisioner-79cc77f98-87xts -n nfs-storageclass

变成这样子了

kubectl edit deployment kubernetes-dashboard -n kubernetes-dashboard ** ** 
赶紧把这玩意去了

好了回归error了嘻嘻
没事嗷,现在redis和nfs都起起来了
后边再说这个captcha,我们先起mysql
连接mysql
好我们终于可以到这一步了,感动中国

还是跟之前一样,我们提取本地文件
然后装上
kubectl apply -f mysql-c.yaml
kubectl apply -f mysql-d.yaml
kubectl apply -f mysql57-pvc.yaml
kubectl apply -f mysql80-pvc.yaml
kubectl apply -f mysql-services.yaml

这一个轮回的mysql活的很安稳,终于可以继续了
同时在mysql-d.yaml这边还有密码

我们就能拿navicat连上了



上边是连ssh,下边是连数据库,两步走


感动中国
登Kubernetes

接下来我们登Kubernetes,这边发现已经是开着的了

可以看到dashboard端口开在30001
https://192.168.50.80:30001/
直接登录网站

问我们要token
kubectl create token dashboard-admin -n kube-system

填进去就好了

做服务器真的很让人感动,因为每推进一步都很兴奋
在这边我们能看到Deployments也是俩开着一个关着

接下来来重构发卡网站吧!
重构发卡网站

在Deployment这边我们没能看到所谓的发卡网站,可能已经删除

但在PVC里我们看到是有dujiaoka的

但就算点进去也找不到网站

然而我们能在虚拟机04,也就是data1上找到一个备份压缩包
tar -xvf dujiaoka.tar
ls
mv dujiaoka /data/k8s_data/default
cd /data/k8s_data/default

还原之后使用docker images检查node1 node2节点的镜像

发现都没有这边root目录下找到的配置文件需要的 webdevops/php-nginx:7.4 镜像
但是我们能在master节点发现这个镜像
所以就要把这个镜像导出然后传输到工作节点载入
[root@master ~]# docker save -o php-nginx.tar webdevops/php-nginx:7.4
[root@master ~]# scp php-nginx.tar node1:/tmp
[root@master ~]# scp php-nginx.tar node2:/tmp
[root@node1 ~]# cd /tmp;docker load -i php-nginx.tar
[root@node2 ~]# cd /tmp;docker load -i php-nginx.tar

传输过去,然后配置上

当然之后也可以docker images看看

导入完成后,运行php-nginx-deployment.yaml 配置文件创建pod
kubectl apply -f php-nginx-deployment.yaml


我去,红的

发现缺失configmap
我们这边执行kubectl apply -f dujiaoka-c.yaml 创建configMap

然后在面板中重启发现还是报错,嘻嘻
其实是和镜像有关
我们docker tag ac09 webdevops/php-nginx:7.4 修改标签名字
在node1节点和node2节点都干一边

修好了!!!!
(wp说captcha-bot由于没有互联网,是无法正常启动,这无需处理,好吧)
接下来就能访问网站咯~
http://192.168.50.80:31669/

我感谢天,感谢地,感谢所有人
然后就可以做题了
还有就是我们在火眼分析的时候我的建议是不要多镜像分析

还是分开来分析比较好
1、node1节点的磁盘设备SHA256值前六位是?(字母全大写,答案格式:AAAAAA)( )
搭完就能知道
node1节点是虚拟机02

所以我们看看这个磁盘设备的SHA256即可,火眼直接算

FC9A341213AC06448213480AA639834A472D7138B70FA9A3A495A469B0281BE5
前六位就是FC9A34
2、集群配置了多少个node节点?(答案格式:1)( )

cat /etc/hosts看hosts的时候就看见了有俩
3、嫌疑人于什么时间修改master节点的root密码?(使用双位数格式,答案格式:00:00:00)( )
都这样子问了,我们肯定是看看日志,过滤master和passwd

过滤完就一条了
所以是09:35:59
4、Docker的安装日期是?(使用双位数格式,答案格式:01月01日)( )

在历史命令里定位关键词docker和install可以看到这边是用的yum安装的Docker
所以我们应该是去看看yum.log
我们去master的机子上运行一下
grep "Installed:" /var/log/yum.log | grep docker-ce

所以可以看到安装时间是04月08日
5、Docker通过配置守护进程以使用全局代理,该代理地址的端口是?(答案格式:1)( )
通过配置守护进程,那自然是去看配置文件了
一般是这样子的HTTP_PROXY=这种
我们在master节点上直接cat /lib/systemd/system/docker.service
当然直接问ai,ai也会给指令,直接输入即可

所以端口就是4780
6、发卡网站使用的Mysql数据库对外访问端口是?(答案格式:1)( )
kubectl get svc -A直接在master看mysql端口就好

这边是30627
7、发卡网站部署使用的镜像名称是?(答案格式:root/root)( )

搭网站的时候就能看见配置文件,虽然网站里也有吧
webdevops/php-nginx
8、当前Telegram群管机器人使用的容器ID的前六位是?(答案格式:123abc)( )
我们做到有docker容器了,在node1和node2节点,所以去这俩地方找
群管机器人,那应该是bot吧

搜到了

检验一下确实是没问题
所以id是8fadf590e1a8404ee09bb866f09547d699bbddd825b1a8dff5722aaef720994d
前六位8fadf5
9、发卡网站使用的缓存数据库是?(答案格式:mysql)( )

我们在重构网站的时候明确用到了Redis

所以答案就是redis

当然了,网站根目录的.env文件直接写了
10、集群中配置的发卡网站代码运行所在的物理目录是?(答案格式:/root/root)( )

我们已经知道了发卡网站就是dujiaoka
查看其PVC配置文件
可以看到nfs.io/storage-path: "dujiaoka"

即物理目录在nfs服务器物理目录下的/dujiaoka目录下

在kubernetes上我们可以看到nfs服务器物理目录是/data/k8s_data/default
所以总体合起来就是/data/k8s_data/default/dujiaoka
11、Telegram群管机器人配置的API代理域名是?(答案格式:[www.xxx.com])( )

telegram群管机器人基本可以确定就是这个captcha-bot了

但是这边并没有明确写清楚api代理域名到底是多少
我们需要过去看看
在data1机子上

我们进config看看配置文件

这边编码有点问题,ssh连接就好了
但是还是很明显能看见api的代理域名
http://kk.xilika.cc
12、嫌疑人在Telegram上创建的群名称是?(答案格式:比武群)( )
直接看配置文件看不见

我们搭mysql的时候就注意到有个mysql数据库就叫captchabot
这边点开看看

很明显可以看到群名称就叫西门庆交流群
13、统计嫌疑人在Telegram上创建的群中2025年6月之后成功入群的人数为?(答案格式:1)( )
** 在数据库搜索就好了**
SELECT count(*) FROM captchabot.user_captcha_record AS ucr
WHERE captcha_status = 1 AND captcha_success_time >= '2025-06-01 00:00:00';

人数为2422
14、据嫌疑人交代曾在发卡网上删除过一条订单数据,请找出该删除订单的订单号是?(答案格式:请按实际值填写)( )
删除的数据,直接找是找不到的
所以我们想到要去看看有没有日志
正好注意到/data/k8s_data/default/mysql80路径下存在两个binlog文件
即mysql的二进制日志

我们把这俩拿出来之后转sql文件
mysqlbinlog --no-defaults -vv --base64-output=DECODE-ROWS G:\电子取证题目\2025数证杯初赛\03-服务器取证\binlog.000001> G:\电子取证题目\2025数证杯初赛\03-服务器取证\demo1.sql
mysqlbinlog --no-defaults -vv --base64-output=DECODE-ROWS G:\电子取证题目\2025数证杯初赛\03-服务器取证\binlog.000002> G:\电子取证题目\2025数证杯初赛\03-服务器取证\demo2.sql
注意这边如果想要解析,一定要下对应版本的MySQL

在navicat我们已经知道了是8.0.43的
所以我们下一个这个版本的mysql
https://blog.csdn.net/m0_62615283/article/details/150004572
可以跟着这个走


然后就能成功转化出sql文件了
在demo2.sql里我们搜索DELETE

成功找到订单号
4V8XNK8Q02MD5D2R
15、发卡网站上2025年6月之后订单交易成功的总金额是?忽略被删除的数据(答案格式:1)( )

明显在dujiaoca数据库的orders表里
我们sql检索一下

主要是检索我们的status,时间和金额
SELECT SUM(actual_price)
FROM `orders`
WHERE `status` = 4
AND updated_at >= '2025-06-01 00:00:00'
AND deleted_at IS NULL;

六月以后,是包括六月的,很神奇吧
所以是295202
16、发卡网站的后台访问路径是?(答案格式:/root)( )
需要我们查看.env文件,就在网站根目录
我不是很理解为什么这边我们用ls是看不见的,但是find能搜到啊

cat看看就好了
所以后台访问路径就是/admin


所以我们其实可以登录后台了
17、计算出用户密码算法中Salt的值,并进行Base64编码,结果是?(答案格式:请按实际值填写)( )

独角数卡是一个开源项目

是laravel框架的
Laravel框架默认使用 bcrypt算法来哈希密码,而 BcryptHasher.php这个文件正是Laravel中负责实现 bcrypt密码哈希的核心类
所以我们去看看vendor/laravel/framework/src/Illuminate/Hashing/BcryptHasher.php,就在dujiaoka目录下,这个全路径有点长

cat一下

可以看到Base64编码的内容
我们可以明白这个函数的意思
function getSalt()
{
$a = 'sdahjklhl212jkljass';
$b = hash('sha256', $a, true); // 计算SHA256哈希(原始二进制数据)
$c = substr($b, 0, 16); // 取前16字节作为密钥
$d = base64_decode('xPfGJQaE1zE5d+8='); // Base64解码固定字符串
$e = '';
for ($i = 0; $i < strlen($d); $i++) { // 遍历$d的每个字符
$e .= chr(ord($d[$i]) ^ ord($c[$i])); // 异或操作,结果追加到$e
}
return $e; // 返回盐值
}
我们运行一下就能得到盐值了
<?php
function getSalt()
{
$a = 'sdahjklhl212jkljass';
$b = hash('sha256', $a, true);
$c = substr($b, 0, 16);
$d = base64_decode('xPfGJQaE1zE5d+8=');
$e = '';
for ($i = 0; $i < strlen($d); $i++) {
$e .= chr(ord($d[$i]) ^ ord($c[$i]));
}
return $e;
}
echo base64_encode(getSalt());
?>

返回了盐值
lAID2ktDeRlGbcg=
18、发卡网站配置的邮件发送人地址是?(答案格式:abc@abc.com)( )
我们没有发卡网站的账密,无法登录,因此想要登录的话只能进行绕密处理
这边对刚刚的php文件进行修改

vim进去,然后把这一行改为下图

**因为这边是看parent::