之前一直说想学一下代码审计,但是由于懒还有代码审计确实比较难入门,真是一块难啃的骨头。但是没办法,现在有时间了学一下。我看网上大佬推荐的都是从bluecms1.6进行代码审计入门的,我们也来看看。
思路思路其实就都差不多,大家也能搜到,就没什么好说的了,就以下几种嘛
-
根据敏感关键字回溯参数传递过程。
-
查找可控变量,正向追踪变量传递过程。
-
寻找敏感功能点,通读功能点代码。
-
直接通读全文代码。
反正明面话是说大家选一个自己最喜欢的思路就行,哈哈哈!但是我相信很多人还有一脸懵逼,我一个小白我哪知道选哪个。作为我也是小白刚入门,我说说我的思路,大家可以参考参考。
- 基本拿到源码首先看一下目录结构,看出来是什么类型,什么框架
- 看一下index.php,一般再开头都会有引用文件,然后进入引用的公共文件看看一些过滤函数呀,稍微优点印象进行,因为等会看正文的时候还是会回来再看看的。然后看看数据库的配置文件呀,有没有可能数据库就是gbk编码呢,这样是不是可以考虑以下有没有宽字节注入呢。
- 其实没有捷径可以走,我是通过seay代码审计工具扫描之后,一个文件一个文件的进行审计的,这个虽然比较费时间,但是却能够很好的打下基本功。
好了bluecms都是网上各位大佬审计烂了,哈哈哈!我就不说明什么目录结构解释了,相信大家一搜都有。我直接开始审计吧,说实话我一开始是跟着网上的大佬文章进行审计的,但是大佬的文章一般只是审计一些经典案例的漏洞,并不是所有的漏洞呀,我们既然是新手,学习当然要抱着学到底的态度啦!虽然过程中可能有很多函数大家不知道是什么意思,我也不知道,毕竟我相信大多数人并没有做过php开发,但是没事,不懂我们搜呀,就这样一个一个的慢慢搜啃下来,我相信审计个几个经典cms之后大家就熟能生巧了。好了,废话不说了!开干!
工具- Seay源代码审计系统
链接:https://github.com/f1tz/cnseay
漏洞审计 1.ad_js.php SQL注入漏洞$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
思路:我们可以看到这个sql语句拼接了一个$ad_id
变量,我们往前看看这个变量是通过GET方式输入的,所以这个变量我们可控,并且中途并没有做什么过滤。所以这里存在数字型的SQL注入,直接sqlmap
一把梭看看。
elseif($act == 'do_upload')
{
include_once BLUE_ROOT . "include/upload.class.php";
$image = new upload();
if(isset($_FILES['upload_file']['error']) && $_FILES['upload_file']['error'] == 0)
{
$upload_pic = $image->img_upload($_FILES['upload_file']);
}
template_assign('add_pic', $upload_pic);
$smarty->caching = false;
$smarty->display('upload.htm');
}
这个地方应该是有文件上传的,但是前端页面没有提交按钮,我醉了,不急我们后面分析还会有的,一般一个cms里面文件上传的功能写的都差不多,一错全错哈哈哈!直接一把梭。
任意文件删除elseif($act == 'del_pic')
{
$id = $_REQUEST['id'];
$db->query("DELETE FROM ".table('post_pic').
" WHERE pic_path='$id'");
if(file_exists(BLUE_ROOT.$id))
{
@unlink(BLUE_ROOT.$id);
}
}
这里id参数是用户输入的,可控并且没有任何过滤就调用unlink
函数,这个函数是删除文件的,所以我们可以构造id参数删除任意文件。
这个payload能够删除跟publish.php
同目录下的所有文件,但是我试了一下,我发现它能够删除D盘根目录下的文件,通过../../../
能够删除上级目录下的文件,能够突破www目录。
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";
}
这里的pay参数是我们输入的,它只是检测了pay是否为空,不为空就代入include里面,这个操作造成了文件包含漏洞,我们可以通过../
包含上级目录的文件,如果有文件上传漏洞的话,上传一个图片马进去,就造成连锁反应,直接连webshell了,后面好像还真有一个上传图片马的漏洞,大家等会往下看。
直接穿越两级目录包含了首页的index.php文件。
存储型XSS漏洞我们发现编辑资料页面的参数除了sex
强制转化为int,address
进行了html实体编码,其他的基本没有做过滤,然后直接代入了sql语句中插入,我们可以插入XSS弹窗测试,但是最后测试发现只有email
字段能够成功弹窗,查看数据库文件发现是其他字段的长度太小了,插入的语句被截断了。
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
参数是不是为空,是为空去检测face_pic3
参数是否存在,如果存在就调用unlink
函数删除文件,而且这两个参数都是用户可控的。下面我们只要把face_pic1
赋值空,把face_pic3
赋值成删除的文件就行,抓包进行修改。
我们删除上级目录的123.txt,删除成功了,这个也是能够突破www目录的限制的,能直接删除D盘根目录文件。
文件上传漏洞我发现编辑资料的地方存在一个文件上传,分析一下发现只能够上传图片马。文件上传它调用了img_upload
函数过滤,跟踪进去看看首先限制了图片上传的类型是四种:image/jpeg
,image/gif
,image/png
,image/pjpeg
,当然了这个我们是可以伪装的,接着往下看他会获取文件的后缀也设置了一个白名单,必须是这四个:jpg
,gif
,png
,pjpeg
,这里我们可以用%00截断来上传文件,但是上传之后他好像会按时间经常赋值文件名和加上jpg后缀,所以就是一个图片马。%00截断是php5.3.29以下才生效,后面的版本修复了,我这个实验版本是5.2,当然好像还有其他上传方式,好像有phar利用,到时候去研究一下。
这里应该是存在一个任意文件删除的,但是上面的sql语句会报错,因为bluecms的源码数据库里面没有company_image这个表。
任意文件删除 //如果没有图片,则将信息缩略图设置为默认图片
if (file_exists(BLUE_ROOT.$_POST['lit_pic'])) {
@unlink(BLUE_ROOT.$_POST['lit_pic']);
这段在user.php的614行,啊啊啊啊怎么这么多文件删除,这里lit_pic
用户可控且没有做过滤,只要我们在上面一步步构造变量下来,然后到这里控制lit_pic
为要删除的文件即可任意文件删除。
payload大概这样:
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')";
我们发现注册的代码输入的变量都没有经过过滤,但是对用户名有长度限制,密码一般不考虑,我们在邮箱字段输入xss语句,对邮箱的验证在前端,我们抓包直接改进行提交之后触发xss。
4. comment.php SQL注入配置文件中对POST,GET,COOKIES,REQUEST参数都做了gpc处理,唯独漏了SERVER,而且网站正好通过这个变量获取IP地址,直接搜全局搜索getip函数,看哪里使用了,这个函数在配置文件comment.fun.php中定义的函数
我们可以通过伪造ip注入sql语句,直接上sqlmap。
5.guest_book.php SQL注入漏洞同样的问题,online_ip实际就是获取在线ip,其实还是调用的getip函数,前面的配方。直接构造闭合注入。
payload:x-forwarded-for:127.0.0.1',database())-- -
到现在为止外部文件基本审完了,累死我了,当然可能会漏掉一些,或者利用难度大点的我还没达到那个水平。有大神看出来可以指点一下。下面开始审admin文件夹里面的文件吧。
5.admin/login.php我们一般访问admin都是先访问登陆页面,我们看看登录页有什么漏洞吧,一般都会有万能密码的SQL注入,这里好像也有。
SQL注入漏洞在login.php中我们看到没有对username和password做过滤,直接用check_admin
函数来判断用户名密码,我们跟进去看看,函数里面也没有进行过滤而是直接代入SQL语句了,SQL语句如下:
$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");
可以看到用的单引号注入,我们只需要通过宽字节闭合掉单引号就能够万能密码登录了
payload:admin%df' or 1=1#
我们可以看到什么的参数都没有过滤,只要时间参数通过-
分隔开来成了一个数组去检测,所以按理说其他的content
,title
,color
都是存在XSS的,但是我实际上只有前面两个触发了XSS,color
字段被截断了,我发现是数据库的这个字段的长度只有10,所以没有触发成功。
elseif($act == 'do_add'){
$title = !empty($_POST['title']) ? trim($_POST['title']) : '';
$color = !empty($_POST['color']) ? trim($_PST['color']) : '';
$cid = $_POST['cid'];
$content = !empty($_POST['content']) ? trim($_POST['content']) : '';
if($title == '' || $content == '' || empty($cid)){
showmsg('信息填写不完整');
}
if(!$db->query("INSERT INTO ".table('ann')." (ann_id, cid, author, title, color, content, add_time, click) VALUES ('', '$cid', '".$_SESSION['admin_name']."', '$title', '$color', '$content', '$timestamp', '1')")){
showmsg('添加新信息出错', true);
}else{
showmsg('添加新信息成功', 'ann.php', true);
}
}
title和content字段都存在存储型XSS,color按理说也存在,但是数据库的该字段长度只有10,如果构造10以内的xss应该就能触发。
因为变量没过滤,所以这里还存在SQL注入漏洞,我这里举例延时注入,它的延时时间会×3倍,这个网站上基本有存储型XSS的地方都有这种SQL注入,payload都差不多,大家可以自行去试试,太多了太多了。
payload:
title=%3Cscript%3Ealert%281%29%3C%2Fscript%3E&color=&cid=1&content=1%df'+and+sleep(2)+or+1=1#&ann_id=3&act=do_edit
sqlmap语句:
sqlmap -r 1.txt --tamper unmagicquotes --current-db --batch -v 3 -p content --level 3
admin/attachment.php
SQL注入漏洞,XSS漏洞
XSS就不说了大家都知道,SQL注入漏洞存在位置:
测试payload:
att_name=%3Cscript%3Ealert%281%29%3C%2Fscript%3E&modelid=123&is_required=1&att_type=1&unit=1%df'+and+sleep(5)+or+1=1#&att_val=&show_order=0&act=doedit
漏洞位置:
这里的tpl_name
参数是用户可控的,直接用fopen函数打开了这个路径,我们只需要控制$file变量进行任意文件读取。
漏洞位置:
这里我们act变量赋值为do_edit,然后tpl_name就是我们写入的文件名,tpl_content就是我们写入的文件内容,这里的判断逻辑是如果tpl_name不存在,就会在/templates/default目录下面写入tpl_name文件,并把tpl_content的内容写入进去。
暂时就这样吧,漏洞太多了,基本都是重复的,一个功能写错了好多地方都用的一个函数,这次收获还不错。慢慢啃吧
有什么错误或者改进意见欢迎评论或发给我噢!大家一起共同学习!大佬多指教!!!!