第一届数证杯团体赛---服务器取证

文摘   2024-12-07 09:15   北京  

本次团体赛服务器考点比较新颖,主要涉及区块链取证、浏览器扩展程序分析,除了传统的服务器取证能力外,需要对区块链原理有些了解并且具备一定的代码审计能力。

本文主要是针对比赛题目进行分析和解题思路分享,只进行知识分享,不具一定的实战能力,后台不解答涉及可能侵害他人权利的问题,切勿用于违法犯罪活动。如果有工作方面的解答需求,请后台联系添加微信私聊。

环境构建

将镜像使用仿真软件或者手动进行仿真,重置密码。

点击右上角的图标 - Wired Connected - Wired Settings - Network - Wired - 点击齿轮 - IPv4 - IPv4 Method

Manual修改为Automatic(DHCP),点击Apply,在这里你也可以看到ens33网卡设置的静态IP地址。

返回桌面,点击右上角的图标 - Wired Connected - Turn Off

再点击右上角的图标 - Wired Off- Connect

这样便可以将服务器网络设置为DHCP并重新获取IP信息。

要想ssh连接服务器,我们还需要关闭防火墙。

systemctl stop ufw

之后便能愉快地连接服务器了。

通过一定的探索和后续题目的引导,可以知道整个题目的环境。

/home目录下存储着网站后台的前端web和后端project的代码。

/home/project/admin/nohup.out可以看到项目地址。

上网搜索可以知道这是一个虚拟货币的交易平台,也就是说嫌疑人构建了一个虚拟货币交易所。

/home/gass/Desktop/project/blockchain下有嫌疑人使用geth搭建的私有区块链网络。

因为上述服务都配有启动命令,我们直接执行启动命令将所有服务开启。

bash /home/project/admin/restart.sh && bash /home/project/cloud/restart.sh  && bash /home/gass/Desktop/project/blockchain/start.sh

注意,在启动bash /home/project/admin/restart.sh时可能会发送报错java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed,简单的解决方法是先手动连接一次数据库mysql -u root -p进行一次公私钥交换,数据库密码在下文的java源码分析中会提及,密码为123568

之后就是访问前端登陆界面。

查看nginx配置文件/etc/ngixn/ngixn.conf可以看到nginx监听的是8801端口。

前端/home/web中写死了127.0.0.1访问后端接口,方便起见,我们直接在虚拟机中访问前端登陆界面127.0.0.1:8801。(有点小晕)

前端界面也有个小坑,可以看到登陆表单显示的是一个用户名,一个验证码,但你f12查看html源码可以发现验证码表单实际上是密码表单,真正的验证码表单已被隐藏。

我们可以修改display将验证码显示出来。

接下来是绕密,也是跟第3、6、7题有关。

导出/home/project/admin/admin.jar,反编译jar包。

application.properties可以找到数据库密码为123568

直接可以连接服务器数据库。

全局搜索login找寻后台管理员登陆代码逻辑。

com.bizzan.bitrade.controller.system.EmployeeController#adminLogin实现了后台管理员的登陆逻辑。

密码使用MD5拼接盐值进行加密。

找到盐值定义的位置。

再通过全局搜索找到定义的常量。

直接拼接计算md5值。

将原有的root密码替换为计算值。

之后便能登陆后台root/123456

赛题

1. [填空题]请写出服务器系统内核版本;(答案格式:1.1.1-11-abcdefe)(1分)

uname -r
6.8.0-48-generic

2.[填空题]请写出服务器的ens33网卡的ip地址;(1分)

ifconfig
10.172.29.128

3.[填空题]请写出mysql数据库密码;(4分)

application.properties中设置了mysql数据库密码。

123568

4.[填空题]后台服务中注册中心的服务端口是多少?(答案格式:纯数字)(2分)

查看/home/project/cloud的启动日志可以知道这就是注册中心,服务端口为7000

7000

5.[填空题]服务器nginx日志中,哪个ip访问系统最为频繁?(答案格式:6.6.6.6)(6分)

awk '{print $1}' /var/log/nginx/access.log* | sort | uniq -c | sort -nr
56.111.197.176

6.[填空题]请写出平台管理员密码加密算法;(答案格式:aes)(3分)

环境搭建环节也已经提到,通过全局搜索login可以锁定后台登陆的代码逻辑,找到平台管理员密码为md5加密。

md5

7.[填空题]假设某管理员密码是123456,请问该管理员的密码在数据库中存储的值是多少?(答案格式:如有字母,全大写)(5分)

也在环境搭建中提及,通过搜索spark.system.md5.key,可以找到定义的盐值。

最后将123456与盐值进行拼接计算出结果。

985EB5B028065701341A478A9215E7B2

8.[填空题]已知某人卖出了5.2个ETH/USDT,请问他的二级推荐人可以获得多少个ETH佣金?(答案格式:写出数字即可,保留小数点后5位)(6分)

/home/project/exchange-core搜索佣金可以找到计算佣金的具体逻辑。

com.bizzan.bitrade.service.ExchangeOrderService#promoteReward中计算了一级推荐人和二级推荐人的推广佣金。

首先回去找一下传入的参数bigDecimal1的赋值。

可以看见其具体的赋值逻辑如下,分为买入和卖出以及对特殊会员的处理。

trade是一个ExchangeTrade实体对象,trade.getAmount()获取这次交易的总金额,再乘上coin.getFee()coinExchangeCoin实体对象,coin.getFee()获取该种虚拟货币的交易费率。

在数据表exchange_coin可以看到fee0.001。如果交易的是USDT的话,则为 amount * 0.001。

之后将bigDecimal1传入com.bizzan.bitrade.service.ExchangeOrderService#promoteReward进行处理。

二级推荐人佣金的计算逻辑如下。

fee也就是bigDecimal1BigDecimalUtils.getRate(jsonObject.getBigDecimal("two"))得到的值进行相乘。

找下jsonObject的定义,可以看到是解析的rewardPromotionSetting.getInfo()rewardPromotionSetting也是RewardPromotionSetting的实体对象。

直接在表reward_promotion_setting找下info,可以看到two为0.1,即fee * 0.1

所以如果是卖出了5.2个ETH/USDT,二级推荐人的佣金为 5.2 * 0.001 * 0.1 = 0.00052

0.00052

9.[填空题]请找到受害人“王涵”的手机号;(1分)

会员管理-会员管理 搜索 王涵获取手机号

15780139471

10.[填空题]请写出嫌疑人的违法交易网站的中文名称;(答案格式:2个汉字)(3分)

查看网站的title可知中文名为币严

币严

11.[填空题]请写出数据库中Recharge表的status字段中,0代表的中文含义;(1分)

直接看表注释即可。

未到账

12.[填空题]平台中所有账户中ETH余额最多的地址是多少?(答案格式:0x123F ... )(6分)

会员管理-余额管理内的数据是缺失的,需要从区块链中拿取数据。

直接在gethconsole中执行javascript代码。

var maxBalance =0;
var maxAddress ="";

var accounts = eth.accounts;

for(var i =0; i < accounts.length; i++){
   var balance = web3.eth.getBalance(accounts[i]);
   if(balance > maxBalance){
       maxBalance = balance;
       maxAddress = accounts[i];
   }
}

console.log("Address with the most ETH: "+ maxAddress);

在数据库验证下,该地址确实是某个会员的地址。

0x928f5963c03340077a8d2375657fb3395fe4a790

13.[填空题]区块链搭建工具是?(答案格式:abcd)(1分)

前面已经提到了,就是geth

geth

14.[填空题]区块链对外提供的的http端口是?(2分)

查看/home/gass/Desktop/project/blockchain/geth.log日志,可以看到区块链对外提供的端口为8545,本地也开启了8551端口。

8545

15.[填空题]服务器网站数据库使用的字符集为?(答案格式:如有字母,请小写)(1分)

直接查看建立数据库的sql。

utf8mb4

16.[填空题]由于服务器定时清理了交易数据,请找寻整个区块链中最大的交易金额(答案格式:0x123F ... )(6分)

还是写javascript脚本在gethconsole中执行获取整个区块链中最大的交易金额。

let blockCount = web3.eth.blockNumber;
console.log("当前区块链高度:", blockCount);

let maxTransactionAmount ={
   hash:"",
   value:-1,
   from:"",
   to:""
};

for(let i =0; i <= blockCount; i++){
   let block = web3.eth.getBlock(i,true);
   if(!block) continue;
   for(let transaction of block.transactions){
       let value = transaction.value;

       if(value > maxTransactionAmount.value){
           maxTransactionAmount.hash= transaction.hash;
           maxTransactionAmount.value= value;
           maxTransactionAmount.from= transaction.from;
           maxTransactionAmount.to= transaction.to;
       }
   }
}

console.log("最大的交易哈希是:", maxTransactionAmount.hash);
console.log("最大的交易金额是:", maxTransactionAmount.value);
console.log("发送方地址:", maxTransactionAmount.from);
console.log("接收方地址:", maxTransactionAmount.to);
0xbb218c4bd443824260673a92b575f6c249085b6e482d89f1445fdb4ba487b9f2

17.[填空题]请写出嫌疑人在chrome上使用的钱包名称;(答案格式:如有字母全小写)(2分)

打开chrome,可以看到是MetaMask

metamask

18.[填空题]请写出chrome钱包插件使用的pbkdf2加密算法的轮次;(答案格式:纯数字)(4分)

ChromeMetaMask插件进行调试。

每次输入错误密码会返回Incorrect password,通过这个去搜索登陆的主要逻辑。

打上断点,可以看到变量中保有pbkdf2的轮次信息,为600000

600000

19.[填空题]Chrome钱包密码的算法中对iv的加密方式是什么?(答案格式:如有字母请小写,如md5)(4分)

h函数传入了e密钥以及r加密信息等数据。

执行crypto.subtle.decryptr中的加密数据进行解密,解密算法为AES-GCM

之后在对解密数据进行JSON.parse解析,倘若解析不成功说明解密不成功,触发Incorrect password报错。

从上面的分析可以看出对iv的加密方式为aes

aes

20.[填空题]已知服务器中嫌疑人的钱包登录密码为八位纯数字生日1994 ****,请写出该密码;(6分)

传入的密钥e已经是派生的密钥,我们原始传入的密码还没有看见。

h函数下方的p函数很像通过PBKDF2进行密钥派生的逻辑,打个断点看一下。

p函数的e传入的是我们的原始密码123456r作为PBKDF2算法的salt,与上文中的一致。

并且可以看到PBKDF2密钥派生使用的哈希算法为SHA-256

加密数据、ivsalt、轮次都有了,写个脚本来爆破密码。

import base64
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
import re


data_base64 = "4OBSCQ3fpgiiQG1CUT2KVKU9Sma1ixgcZ1xBb+XeQXlX9yFbyj6HgpPH4vKktB39FPVD5wlV0fFrKkrB4YvkwS4y0P2y15GrSMvJ7ZPV2FdT+o7/s9ydryf4j/dvWssWhlpIf8+Z/GTWxrd0pEKCumJ0SgM7pNCn+LPufqgAAc8Phk1V2G78YFFn27hoPalU+mfyLirBvbcNCe7PZhUEf02OB9HJxc6NL8VGHZ0mugf8CMCU4CfoMWBjGB358XwYgqVCAYfPeP612BcqH/2qGsf4v5MUynaoWjR3CDxg6z5n/SzvayET9KxzpnP5/YwrI1Kr6KSuX8hfWa4G7Qect7gRcJ5OSP9vjDAE0Oa7+2RoOvSuDhONrit9JD1j3PlF/HLHjCWcAxFPAqQHnaXHUT7+O/UR/nHBBUjwZqXcA3NvY6Up9gEyp7v252JKw/ybv9PYsNVBNNzaOCHM+2vLu4AEdhsJjEmzz1BMnl2a10lX3PIxT6g+eVdHNVOkeESS7Xiufrh1BNEXemU+/Mj8zOzC8X3sC+h7k6V+j8FO5gFFIsGVsehmhjQ0g3hv5OjHLu+8UbJ19HVC6nzyopbHF1EbgVc4bEfnsqxpBQT4xGY27MQLFa2SlcpRpue1NpZWdhV2C8/wTSBmcgnm3PHWgvBiuA=="
salt_base64 = "fhlH2383hn7sqEKiLN8zSqv/F/v9x0s3xj/1zBI1zkA="
iv_base64 = "oi49chysOL0hAXfqbviWIA=="
iteration_count = 600000

data = base64.b64decode(data_base64)
salt = base64.b64decode(salt_base64)
iv = base64.b64decode(iv_base64)


for year inrange(1994,1995):
   for month inrange(1,13):
       for day inrange(1,32):
           password =f"{year}{month:02}{day:02}"
           key = PBKDF2(password, salt, dkLen=32, count=iteration_count, hmac_hash_module=SHA256)
           cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
           decrypted_data = cipher.decrypt(data)
           if re.findall(b"{[\x20-\x7E]+}", decrypted_data):
               print("正确的密码:", password)
               exit()
           print(password)

可以成功登陆。

金星路406取证人
这是位于大兴区黄奕路金星406的取证爱好者,这是一个致力于学习电子数据取证的团体~~
 最新文章