bluecms v1.6 sp1 代码审计
2020-01-10 10:38:22 Author: xz.aliyun.com(查看原文) 阅读量:252 收藏

/include/common.inc.php
第30-36行
$_GET、$_POST、$_COOKIES、$_REQUEST使用deep_addslashes()函数过滤一遍,漏了$_SERVER

if(!get_magic_quotes_gpc())
{
    $_POST = deep_addslashes($_POST);
    $_GET = deep_addslashes($_GET);
    $_COOKIES = deep_addslashes($_COOKIES);
    $_REQUEST = deep_addslashes($_REQUEST);
}

追踪一下deep_addslashes()函数
/include/common.fun.php
第14-28行

function deep_addslashes($str)
{
    if(is_array($str))
    {
        foreach($str as $key=>$val)
        {
            $str[$key] = deep_addslashes($val);
        }
    }
    else
    {
        $str = addslashes($str);
    }
    return $str;
}

前台

/ad_js.php

12:$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
19:$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);

$ad_id没有使用单引号双引号包括所以addslashes()函数不起作用
getone()方法位于/include/mysql.class.php61行,作用是执行SQL语句并输出

function getone($sql, $type=MYSQL_ASSOC){
        $query = $this->query($sql,$this->linkid);
        $row = mysql_fetch_array($query, $type);
        return $row;
    }

$ad_id只是用trim()函数去除首尾的空格,故存在SQL注入漏洞

/guest_book.php(XF注入)

因为没有对$_SERVER进行过滤,所以使用X-Forwarded-For或者CLIENT-IP可以伪装ip进行SQL注入

全局搜索ip找到guset_book.php里面有关于ipSQL语句
第77-79行

$sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content) 
            VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')";
    $db->query($sql);

$online_ip就是getip()
追踪到common.fun.phpgetip()函数
第106-133行

function getip()
{
    if (getenv('HTTP_CLIENT_IP'))
    {
        $ip = getenv('HTTP_CLIENT_IP'); 
    }
    elseif (getenv('HTTP_X_FORWARDED_FOR')) 
    { 
        $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;
}

所以可以使用X-Forwarded-For或者CLIENT-IP进行SQL注入

评论区出现SQL注入结果

/comment.php(XF注入)

全局搜索getip

发现comment.php里面有一处SQL语句
第133-135行

$sql = "INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check) 
            VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '".getip()."', '$is_check')";
    $db->query($sql);

其它参数都有addslashes()函数过滤而getip()的值没有,所以存在SQL注入漏洞,和上面一样是insert型注入,就不演示了

admin/login.php(宽字节注入万能密码)

第22-23行

$admin_name = isset($_POST['admin_name']) ? trim($_POST['admin_name']) : '';
$admin_pwd = isset($_POST['admin_pwd']) ? trim($_POST['admin_pwd']) : '';

然后第31行判断

if(check_admin($admin_name, $admin_pwd))

追踪check_admin()函数到common.fun.php
176-188行

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;
    }
}

因为编码是gbk2312$name使用了addslashes()函数过滤,所以存在SQL注入漏洞,可造成万能密码进后台

/user.php(登录页面宽字节注入)

第77行

$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$user_name'");

$user_name使用了addslashes()函数过滤但是网页编码是gbk2312,所以存在宽字节注入

/user.php(注册页面insert型宽字节注入)

138行

$email  =   !empty($_POST['email']) ? trim($_POST['email']) : '';

160行

$sql = "INSERT INTO ".table('user')." (user_id, user_name, pwd, email, reg_time, last_login_time) VALUES ('', '$user_name', md5('$pwd'), '$email', '$timestamp', '$timestamp')";

$email使用单引号包围,有addslashes()函数过滤,网页编码是gbk2312所以存在宽字节注入

/user.php(注册页面宽字节注入)

第135行

$user_name  =   !empty($_POST['user_name']) ? trim($_POST['user_name']) : '';

第154-156行

if($db->getone("SELECT * FROM ".table('user')." WHERE user_name='$user_name'")){
        showmsg('该用户名已存在');
    }

故存在宽字节注入,但是$user_name有大于4小于16的长度限制,不好利用,有点鸡肋

后台

/admin/nav.php

63-70行

elseif($act=='edit')
 {
    $sql = "select * from ".table('navigate')." where navid = ".$_GET['navid'];
    $nav = $db->getone($sql);
    $smarty->assign('nav',$nav);
    $smarty->assign('act', $act );
    $smarty->display('nav_info.htm');
 }

$_GET['navid']直接接在后面,存在SQL注入漏洞

/admin/attachment.php

第78-85行

elseif($_REQUEST['act'] == 'del')
 {
    $sql = "DELETE FROM ".table('attachment')." WHERE att_id = ".$_GET['att_id'];
    if(!$db->query($sql)){
        showmsg('删除附加属性出错', true);
    }
    showmsg('删除附加属性成功','attachment.php', true);
 }

$att_id直接接在后面,存在SQL注入漏洞

/admin/ad.php

第101行

$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';

第106行

$ad = $db->getone("SELECT ad_id, ad_name, time_set, start_time, end_time, content, exp_content FROM ".table('ad')." WHERE ad_id=".$ad_id);

$ad_id直接接在后面,存在SQL注入漏洞

总结

后台注入大多都是直接拼接或者宽字节造成的,挺多的所以这里略了

/user.php

注册了一个用户在个人信息里面出现了一些注册信息,查看源代码看是否存在存储型XSS
135-139行

$user_name      =   !empty($_POST['user_name']) ? trim($_POST['user_name']) : '';
$pwd            =   !empty($_POST['pwd']) ? trim($_POST['pwd']) : '';
$pwd1           =   !empty($_POST['pwd1']) ? trim($_POST['pwd1']) : '';
$email          =   !empty($_POST['email']) ? trim($_POST['email']) : '';
$safecode       =   !empty($_POST['safecode']) ? trim($_POST['safecode']) : '';

对邮箱$email只有个trim()以及addslashes(),所以存在存储型XSS,直接在网页表单写入payload会被前端检测无法提交,所以抓包改

/user.php

第266行

$content = !empty($_POST['content']) ? filter_data($_POST['content']) : '';

评论的内容采用filter_data()函数过滤
追踪filter_data()函数,位于common.fun.php第985-988行

function filter_data($str)
{
    $str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str);
    return $str;
}

很明显漏了img标签,所以使用img标签即可,payload:<p><img src=1 onerror=alert(1)></p>
这里必须抓包改,不然会有一个&nbsp干扰XSS payload导致无法执行

/user.php

第742-751行

elseif ($act == 'pay'){
    include 'data/pay.cache.php';
    $price = $_POST['price'];
    $id = $_POST['id'];
    $name = $_POST['name'];
    if (empty($_POST['pay'])) {
        showmsg('对不起,您没有选择支付方式');
    }
    include 'include/payment/'.$_POST['pay']."/index.php";
 }

$_POST['pay']前后加了文件,可以使用../进行目录遍历,后面的/index.php如果php版本低于5.3.4magic_quotes_gpc=off则可以使用%00截断,导致任意文件包含。还可以使用.号路径长度截断,Windows下目录最大长度为256字节,Linux下目录最大长度为4096字节
可配合用户头像上传上传图片马使用

/user.php

第779-785行

if (!empty($_POST['face_pic1'])){
        if (strpos($_POST['face_pic1'], 'http://') != false && strpos($_POST['face_pic1'], 'https://') != false){
           showmsg('只支持本站相对路径地址');
         }
        else{
           $face_pic = trim($_POST['face_pic1']);
        }

它本来的意思是想不能包含http://或者https://应该用!==,但是他用了!=,根据php弱类型strpos()返回值为0是和false相等的,故能够绕过造成SSRF漏洞

/user.php

第787-789行

if(file_exists(BLUE_ROOT.$_POST['face_pic3'])){
            @unlink(BLUE_ROOT.$_POST['face_pic3']);
        }

face_pic1face_pic2为空时,输入的任意存在文件能被删除
我新建了一个test.php文件在网站根目录下

burpsuite抓包传入路径

test.php已被删除

/user.php

第615-617行

if (file_exists(BLUE_ROOT.$_POST['lit_pic'])) {
        @unlink(BLUE_ROOT.$_POST['lit_pic']);
    }

很明显的任意文件删除

刚入坑审计,这是审计的第二个cms,目前使用的就是rips以及Seay扫一下可能存在漏洞的地方,有的漏洞是扫不出来的需要自己去发现,找SQL注入可以全局搜索一下SELECT、UPDATE、INSERT、DELETE等关键字,还可以使用查找危险函数的方法找漏洞比如unlink()函数可能存在任意文件删除。有的时候看代码太过繁琐抽象可以尝试功能点审计,比如找到一处上传或者留言板等,去看对应的代码,对变量进行回溯,看是否可控。像我这样刚入坑审计的菜鸟无疑是很枯燥和困难的,代码复杂难懂量大,但是方法不难,所以更多的还是耐心、仔细和坚持。文章中有不足和错误的地方还望师傅们指正。


文章来源: http://xz.aliyun.com/t/7074
如有侵权请联系:admin#unsafe.sh