bluecms v1.6 sp1 代码审计
网站目录结构
网站基本防护
/include/common.inc.php
第30-36行
对$_GET、$_POST、$_COOKIES、$_REQUEST
使用deep_addslashes()
函数过滤一遍,漏了$_SERVER
1 | if(!get_magic_quotes_gpc()) |
追踪一下deep_addslashes()
函数
/include/common.fun.php
第14-28行
1 | function deep_addslashes($str) |
SQL注入漏洞
前台
/ad_js.php
1 | 12:$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : ''; |
$ad_id
没有使用单引号双引号包括所以addslashes()
函数不起作用getone()
方法位于/include/mysql.class.php
第61
行,作用是执行SQL
语句并输出
1 | function getone($sql, $type=MYSQL_ASSOC){ |
$ad_id
只是用trim()
函数去除首尾的空格,故存在SQL
注入漏洞
/guest_book.php(XF注入)
因为没有对$_SERVER
进行过滤,所以使用X-Forwarded-For
或者CLIENT-IP
可以伪装ip
进行SQL
注入
全局搜索ip
找到guset_book.php
里面有关于ip
的SQL
语句
第77-79行
1 | $sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content) |
$online_ip
就是getip()
追踪到common.fun.php
中getip()
函数
第106-133行
1 | function getip() |
所以可以使用X-Forwarded-For
或者CLIENT-IP
进行SQL
注入
评论区出现SQL
注入结果
/comment.php(XF注入)
全局搜索getip
发现comment.php
里面有一处SQL
语句
第133-135行
1 | $sql = "INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check) |
其它参数都有addslashes()
函数过滤而getip()
的值没有,所以存在SQL
注入漏洞,和上面一样是insert
型注入,就不演示了
admin/login.php(宽字节注入万能密码)
第22-23行
1 | $admin_name = isset($_POST['admin_name']) ? trim($_POST['admin_name']) : ''; |
然后第31行判断
1 | if(check_admin($admin_name, $admin_pwd)) |
追踪check_admin()
函数到common.fun.php
176-188行
1 | function check_admin($name, $pwd) |
因为编码是gbk2312
,$name
使用了addslashes()
函数过滤,所以存在SQL
注入漏洞,可造成万能密码进后台
/user.php(登录页面宽字节注入)
第77行
1 | $row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$user_name'"); |
$user_name
使用了addslashes()
函数过滤但是网页编码是gbk2312
,所以存在宽字节注入
/user.php(注册页面insert型宽字节注入)
138行
1 | $email = !empty($_POST['email']) ? trim($_POST['email']) : ''; |
160行
1 | $sql = "INSERT INTO ".table('user')." (user_id, user_name, pwd, email, reg_time, last_login_time) VALUES ('', '$user_name', md5('$pwd'), '$email', '$timestamp', '$timestamp')"; |
$email
使用单引号包围,有addslashes()
函数过滤,网页编码是gbk2312
所以存在宽字节注入
/user.php(注册页面宽字节注入)
第135行
1 | $user_name = !empty($_POST['user_name']) ? trim($_POST['user_name']) : ''; |
第154-156行
1 | if($db->getone("SELECT * FROM ".table('user')." WHERE user_name='$user_name'")){ |
故存在宽字节注入,但是$user_name
有大于4小于16的长度限制,不好利用,有点鸡肋
后台
/admin/nav.php
63-70行
1 | elseif($act=='edit') |
$_GET['navid']
直接接在后面,存在SQL注入漏洞
/admin/attachment.php
第78-85行
1 | elseif($_REQUEST['act'] == 'del') |
$att_id
直接接在后面,存在SQL注入漏洞
/admin/ad.php
第101行
1 | $ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : ''; |
第106行
1 | $ad = $db->getone("SELECT ad_id, ad_name, time_set, start_time, end_time, content, exp_content FROM ".table('ad')." WHERE ad_id=".$ad_id); |
$ad_id
直接接在后面,存在SQL注入漏洞
总结
后台注入大多都是直接拼接或者宽字节造成的,挺多的所以这里略了
XSS漏洞
/user.php
注册了一个用户在个人信息里面出现了一些注册信息,查看源代码看是否存在存储型XSS
135-139行
1 | $user_name = !empty($_POST['user_name']) ? trim($_POST['user_name']) : ''; |
对邮箱$email
只有个trim()
以及addslashes()
,所以存在存储型XSS,直接在网页表单写入payload会被前端检测无法提交,所以抓包改
/user.php
第266行
1 | $content = !empty($_POST['content']) ? filter_data($_POST['content']) : ''; |
评论的内容采用filter_data()
函数过滤
追踪filter_data()
函数,位于common.fun.php
第985-988行
1 | function filter_data($str) |
很明显漏了img
标签,所以使用img
标签即可,payload:<p><img src=1 onerror=alert(1)></p>
这里必须抓包改,不然会有一个 
干扰XSS payload
导致无法执行
文件包含漏洞
/user.php
第742-751行
1 | elseif ($act == 'pay'){ |
$_POST['pay']
前后加了文件,可以使用../
进行目录遍历,后面的/index.php
如果php
版本低于5.3.4
且magic_quotes_gpc=off
则可以使用%00
截断,导致任意文件包含。还可以使用.号路径长度截断,Windows
下目录最大长度为256
字节,Linux
下目录最大长度为4096
字节
可配合用户头像上传上传图片马使用
SSRF漏洞
/user.php
第779-785行
1 | if (!empty($_POST['face_pic1'])){ |
它本来的意思是想不能包含http://
或者https://
应该用!==
,但是他用了!=
,根据php弱类型strpos()
返回值为0是和false相等的,故能够绕过造成SSRF漏洞
任意文件删除
/user.php
第787-789行
1 | if(file_exists(BLUE_ROOT.$_POST['face_pic3'])){ |
face_pic1
和face_pic2
为空时,输入的任意存在文件能被删除
我新建了一个test.php文件在网站根目录下burpsuite
抓包传入路径test.php
已被删除
/user.php
第615-617行
1 | if (file_exists(BLUE_ROOT.$_POST['lit_pic'])) { |
很明显的任意文件删除
总结
刚入坑审计,这是审计的第二个cms,目前使用的就是rips
以及Seay
扫一下可能存在漏洞的地方,有的漏洞是扫不出来的需要自己去发现,找SQL注入可以全局搜索一下SELECT、UPDATE、INSERT、DELETE
等关键字,还可以使用查找危险函数的方法找漏洞比如unlink()
函数可能存在任意文件删除。有的时候看代码太过繁琐抽象可以尝试功能点审计,比如找到一处上传或者留言板等,去看对应的代码,对变量进行回溯,看是否可控。像我这样刚入坑审计的菜鸟无疑是很枯燥和困难的,代码复杂难懂量大,但是方法不难,所以更多的还是耐心、仔细和坚持。文章中有不足和错误的地方还望师傅们指正。