本篇文章由知柯™️信息安全&CSDN博主鸿渐之翼联合发布,转载请标明出处!
深圳市狩猎者网络安全技术有限公司旗下安全团队
CSDN:@知柯信息安全
知柯信息安全,用心呵护能的安全!Professional in Software Security
关于我们:知柯信息安全简介
基于长安杯的例题,本文结合裸聊APP
网络配置:
将所有的虚拟机运行在vmnet1中,将Vmnet1网卡改成192.168.110.1这样就可以不用修改主机IP
检材二,负载均衡服务器:192.168.110.110
检材三,web3:192.168.110.113
2021年4月25日,上午8点左右,警方接到被害人金某报案,声称自己被敲诈数万元;经询问,昨日金某被嫌疑人诱导裸聊,下载了某“裸聊”软件,导致自己的通讯录和裸聊视频被嫌疑人获取,对其进行敲诈,最终金某不堪重负,选择了报警;警方从金某提供的本人手机中,定向采集到了该“裸聊”软件的安装包–zhibo.apk(检材一),请各位回答下列问题:(题目中需要通过分析出来的答案对检材二三四五解压,解压密码为IP的情况,需要在密码后增加-CAB2021,例:192.168.100.100-CAB2021)
1 请计算检材一Apk的SHA256值
2.该APK的应用包名为:
这里不是软件名称,需要用手机取证软件来分析。
3.该APK程序在封装服务商的应用唯一标识(APPID)为
这个其实是第三方的调证值
4.该APK具备下列哪些危险权限(多选题):ABCDE
A.读取短信.B.读取通讯录.C.读取精确位置.D.修改通讯录.E.修改短信.
5.该APK发送回后台服务器的数据包含一下哪些内容(多选题):
A.手机通讯录.B.手机应用列表.C.手机号码.D.验证码.E.GPS定位信息.
6.该APK程序回传通讯录时,使用的http请求方式为()
将apk文件放到模拟器里,对fiddler进行配置,然后在手机上下载安全证书进行抓包
可以看抓到了目标服务器的地址
并且可以看到是用post的方式进行传参
7.该APK程序的回传地址域名为【标准格式:www.abc.com】 :www.honglian7001.com
8.该APK程序代码中配置的变量apiserver的值为【标准格式:www.abc.com/abc】
9.分析该APK,发现该程序还具备获取短信回传到后台的功能,短信上传服务器接口地址为【标
准格式:www.abc.com/abc】
10.经分析,发现该APK在运行过程中会在手机中产生一个数据库文件,该文件的文件名为
11.经分析,发现该APK在运行过程中会在手机中产生一个数据库文件,该数据库的初始密码为
12.检材二的原始硬盘的SHA256值为:
这个没什么好做的
13.查询涉案于案发时间段内登陆服务器的IP地址为【标准格式:111.111.111.111】
这个题的重点是得先知道案发时间是啥时候,已知的时间点是报案时间为4月25日,而根据金先生所述他是昨天下的裸聊软件
所以我们基本可以确定案发时间是4月24
14.请对检材二进行分析,并回答该服务器在集群中承担的主要作用是(负载均衡服务器)【格式:文件存储】
通过查看history查看命令(通过仿真软件或者仿真都可以看到)
通过对历史命令的分析可以发现,使用者在疯狂的使用这个文件夹,所以cd过去看他的readme
通过读他的rm可以了解到const大概就是端口号配置文件所在的地方,而ADProxy.js是反向代理目标地址的配置文件
15.上一题中,提到的主要功能对应的服务监听的端口为:80
进入配置文件可以直切看到这些信息
16.上一题中,提到的服务所使用的启动命令为:
在history中可以发现app.js在被平凡的运行,而且它占用的是80端口
node app.js & //node是nodejs运行代码的代码的命令,&是在后台运行
使用netstat -napt就可以只看到80端口正在被node占用
17.经分析,该服务对于请求来源IP的处理依据是:根据请求源IP地址的第(三)位进行判断
/**
* 反向代理
*
*/
module.exports = function(_brain, _app) {
/* INCLUDE */
const path = _brain.A.path;
const async = _brain.A.async;
const proxy = require('http-proxy-middleware');
const net = require('net');
/* DEFINE */
const _tag = path.basename(__filename, ".js");
var _isBanned = false;
var _isStarted = false;
if(!_brain.A.checkIsNull(_brain.C.autorun_config[_tag], _tag)){
_isStarted = _brain.C.autorun_config[_tag];
}
/* DEFINE PROXY */
const _proxy50 = {
protocol: 'http:',
host: '192.168.110.111',
port: 80
}
const _proxy100 = {
protocol: 'http:',
host: '192.168.110.112',
port: 80
}
const _proxy100p = {
protocol: 'http:',
host: '192.168.110.113',
port: 80
} //18行到33行的代码定义了三个对象
/* Private Function */
/**
* Service Running
*/
var service = function (){
if(!_isStarted) return;
// proxy middleware options
const _proxyer_chronus = proxy({
target: '/', // target host
changeOrigin: true, // needed for virtual hosted sites
ws: true, // proxy websockets
router: function(req) {
var clientIP = req.get("x-forwarded-for") //46行是一个关键点,程序通过返回的IP数据包的XFF字段来获取IP地址
if (clientIP == undefined) {
clientIP = req.connection.remoteAddress
} //49行将接收到的IP以点分割成四段,进入下面的判断
var clientIPArr = clientIP.split(".")
if (clientIPArr.length == 4) {
var clientIP3Int = parseInt(clientIPArr[2]) //52定义一个变量,值从分段后的第三段获得
global.logger.warn('[Proxy_RequestHeader] -> ' + JSON.stringify(req.headers));
global.logger.warn('[Proxy_ClientIP] -> ' + clientIP);
if (clientIP3Int <= 50) {
global.logger.warn('[Proxy_Destination] -> ' + JSON.stringify(_proxy50));
return _proxy50
} else if (clientIP3Int <= 100) {
global.logger.warn('[Proxy_Destination] -> ' + JSON.stringify(_proxy100));
return _proxy100
} else {
global.logger.warn('[Proxy_Destination] -> ' + JSON.stringify(_proxy100p));
return _proxy100p
}
}
}
})
_app.all('/*', _proxyer_chronus);
};
/**
* Service Killing
*/
var serviceKiller = function (){
};
/* Public Function */
/* 返回_tag */
var getTag = function (){
return _tag;
};
/* 判断服务是否开启 */
var isStarted = function (){
return _isStarted;
};
/* 判断服务是否被意外禁止 */
var isBanned = function (){
return _isBanned;
};
/* 服务开关 */
var startServer = function (callBack){
_isStarted = true;
service();
if(callBack)
callBack(100, _tag + ' Started');
};
var stopServer = function (callBack){
_isStarted = false;
serviceKiller();
if(callBack)
callBack(100, _tag + ' Stopped');
};
/* Service AutoRun */
if(_isStarted){
startServer();
}else{
stopServer();
}
return{
getTag : getTag,
isStarted : isStarted,
isBanned : isBanned,
startServer : startServer,
stopServer : stopServer,
};
}
从这里我们就可以判断此程序是通过源地址的第三位来进行判断
18.经分析,当判断条件小于50时,服务器会将该请求转发到IP为()的服务器上【标准格式:
111.111.111.111】
这里依旧是对上述代码进行分析,小于50对应的是对象“_proxy50”,对应的IP是’192.168.110.111’
19.分析,该服务器转发的目标服务器一共有几台【标准格式:9】
根据上述代码的条件可以得出目标服务器是三台
20.请分析,受害者通讯录被获取时,其设备的IP地址为【标准格式:111.111.111.111】
如果仔细观察history的历史命令可以发现honglianjingsai目录下是有日志文件的并且还被查看过
已知案发时间实在4月24日,我们cd过去,ls可以发现当天的日志只有一个
查看日志后发现当天被转发的IP总共有三个,
192.168.110.142
192.168.110.252
192.168.110.203
一开始这个题是做不了的,但做到后面,我们一旦确定了案发的准确时间(精确到分秒)就可以找到ip
21.请分析,受害者的通讯录被窃取之后,经由该服务器转发到了IP为()的服务器上【标准格
式:111.111.111.111】
这题无论是通过查日志
还是根据之前的代码进行分析,我们都可以知道转发的服务器是:192.168.110.113
22.检材三的原始硬盘的SHA256值为:
不想算,但这里有坑,这三个服务器是负载均衡转发的三个目标服务器,目前已知服务器所转发的对象,是第三个服务器,所以我们要算的是第三台服务器的ip
23.请分析第21题中,所指的服务器的开机密码为:
通过火眼证据分析可以看到shell,里面有密码的记录
24.嫌疑人架设网站使用了宝塔面板,请问面板的登陆用户名为:hl123
确定是web3镜像之后,直接仿真按照之前的配网方法拿到虚拟局域网vmnet1,就可以直接用了
直接在真是机输入内网面板地址,在登录界面会遇到一个问题,其密码是错误的,这里有两种方法:
方法一:bt,输入5,输入想要修改的密码
方法二:输入命令
cd /www/server/panel && python tools.py panel 123456
25.请分析用于重置宝塔面板密码的函数名为 set_panel_pwd
这题的分析思路在于tool.py这个脚本,可以看到上一题的方法二中修改密码的命令调用的起始页是tools.py这个脚本导出来做代码审计
可以发现tools.py里面对应的是bt命令下的所有功能,下面是import包含的库
import sys,os
panelPath = '/www/server/panel/'
os.chdir(panelPath) //将当前工作目录切换到指定路径
sys.path.insert(0,panelPath + "class/") //sys.path模块可以动态修改系统路径
import public,time,json
if sys.version_info[0] == 3: raw_input = input
我们主要需要关注的是设置面板密码的部分:
在第5行可以看到明文password被md5加密后传到public.password_salt函数中
#设置面板密码
def set_panel_pwd(password,ncli = False):
import db //这里调用了在class目下db模块
sql = db.Sql()
result = sql.table('users').where('id=?',(1,)).setField('password',public.password_salt(public.md5(password),uid=1))
username = sql.table('users').where('id=?',(1,)).getField('username')
if ncli:
print("|-用户名: " + username)
print("|-新密码: " + password)
else:
print(username)
class下的public模块,在tools.py中被调用的模块代码
def md5(strings):
return Md5(strings)
def password_salt(password,username=None,uid=None):
'''
@name 为指定密码加盐
@author hwliang<2020-07-08>
@param password string(被md5加密一次的密码)
@param username string(用户名) 可选
@param uid int(uid) 可选
@return string
'''
chdck_salt()
if not uid:
if not username:
raise Exception('username或uid必需传一项')
uid = M('users').where('username=?',(username,)).getField('id')
salt = M('users').where('id=?',(uid,)).getField('salt')
return md5(md5(password+'_bt.cn')+salt)
public中的调用的函数
def chdck_salt(): //此函数描述了盐的生成方式
'''
@name 检查所有用户密码是否加盐,若没有则自动加上
@author hwliang<2020-07-08>
@return void
'''
if not M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'users','%salt%')).count():
M('users').execute("ALTER TABLE 'users' ADD 'salt' TEXT",())
u_list = M('users').where('salt is NULL',()).field('id,username,password,salt').select()
if isinstance(u_list,str):
if u_list.find('no such table: users') != -1:
rep_default_db()
if not M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'users','%salt%')).count():
M('users').execute("ALTER TABLE 'users' ADD 'salt' TEXT",())
u_list = M('users').where('salt is NULL',()).field('id,username,password,salt').select()
for u_info in u_list:
salt = GetRandomString(12) #12位随机
pdata = {
}
pdata['password'] = md5(md5(u_info['password']+'_bt.cn') + salt)
pdata['salt'] = salt
M('users').where('id=?',(u_info['id'],)).update(pdata)
调用了rep_default_db模块,里面调用了文件
def rep_default_db():
db_path = '/www/server/panel/data/'
db_file = db_path + 'default.db'
db_tmp_backup = db_path + 'default_' + format_date("%Y%m%d_%H%M%S") + ".db"
panel_backup = '/www/backup/panel'
bak_list = os.listdir(panel_backup)
if not bak_list: return False
bak_list = sorted(bak_list,reverse=True)
db_bak_file = ''
for d_name in bak_list:
db_bak_file = panel_backup + '/' + d_name + '/data/default.db'
if not os.path.exists(db_bak_file): continue
if os.path.getsize(db_bak_file) < 17408: continue
break
if not db_bak_file: return False
ExecShell("\cp -arf {} {}".format(db_file,db_tmp_backup))
ExecShell("\cp -arf {} {}".format(db_bak_file,db_file))
return True
26.请分析宝塔面板登陆密码的加密方式所使用的哈希算法为 md5
分析上述代码可知
27.请分析宝塔面板对于其默认用户的密码一共执行了几次上题中的哈希算法
三次
28.请分析当前宝塔面板密码加密过程中所使用的salt值为【区分大小写】v87ilhAVumZL
通过SQLite查看文件写入的db文件的users表可以获得答案
29.请分析该服务器,网站源代码所在的绝对路径为/www/wwwroot/www.honglian7001
30.请分析,网站所使用的数据库位于IP为(192.168.110.115)的服务器上(请使用该IP解压检材五,并重构网
站)【标准格式:111.111.111.111】
31.请分析,数据库的登陆密码为【区分大小写】 wxrM5GtNXk5k5EPX
看上图
题目要求重构网站,我们直接在宝塔上运行发现没有连接数据库,所以我们主要目标是连接数据库,而数据库的文件可以看到是三个raid文件,raid重组:
通过ufs可以快速算出raid的参数,操作如下:
打开文件选中那三个原始镜像文件:
open就行:
open就行:
依次选中加入raid
导出后就可以直接用仿真软件做成虚拟机文件
重构成功后我们打开网址进行测试,可以发现已经连接成功
但是当我们用premium连接数据库的时候却报错了,这里是出题人设置的坑,他建了一个空用户导致我们连接异常,但我们可以直接进入服务器后台修改my.cnf。在后面加上命令
skip-grant-tables
systemctl restart mysqld
此时直接用数据库软件连接就可以了,根据之前做题可以知道
账号:www_honglian7001
密码:wxrM5GtNXk5k5EPX
32.请尝试重构该网站,并指出,该网站的后台管理界面的入口为/admin【标准格式:/web】
可以尝试对审计网站源代码,也可以查看取证软件中的历史记录或日志看该网页的访问记录
33.已该涉案网站代码中对登录用户的密码做了加密处理。请找出加密算法中的salt值【区分大
小写】lshi4AsSUrUOwWV
34.请分析该网站的管理员用户的密码为:
这个题目的做法有点怪异官方的出题人是说把整个目录都导出来,然后直接用vs对整个目录进行搜索,索索的关键字为“password”。
首先xftp导出整个目录
然后丢到vscode里面
然后直接用搜索功能,可以看到有好几个日志,修改了很多次密码,但最后一次改成了,security
此时我们可以知道
账号:admin
密码:security
补充知识点:
当我们找不到密码时也是可以登入后台的,方法是通过数据库软件找到admin对应的密码位置
投稿&加入团队:
CPO:白羽 [email protected]
关注微信公众号:知柯信息安全获得更多咨询