Bluecmsv1.6-代码审计

前言

之前一直说想学一下代码审计,但是由于懒还有代码审计确实比较难入门,真是一块难啃的骨头。但是没办法,现在有时间了学一下。我看网上大佬推荐的都是从bluecms1.6进行代码审计入门的,我们也来看看。

思路

思路其实就都差不多,大家也能搜到,就没什么好说的了,就以下几种嘛

  • 根据敏感关键字回溯参数传递过程。

  • 查找可控变量,正向追踪变量传递过程。

  • 寻找敏感功能点,通读功能点代码。

  • 直接通读全文代码。

反正明面话是说大家选一个自己最喜欢的思路就行,哈哈哈!但是我相信很多人还有一脸懵逼,我一个小白我哪知道选哪个。作为我也是小白刚入门,我说说我的思路,大家可以参考参考。

  1. 基本拿到源码首先看一下目录结构,看出来是什么类型,什么框架
  2. 看一下index.php,一般再开头都会有引用文件,然后进入引用的公共文件看看一些过滤函数呀,稍微优点印象进行,因为等会看正文的时候还是会回来再看看的。然后看看数据库的配置文件呀,有没有可能数据库就是gbk编码呢,这样是不是可以考虑以下有没有宽字节注入呢。
  3. 其实没有捷径可以走,我是通过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一把梭看看。

image

2.publish.php

文件上传漏洞

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参数删除任意文件。

image

这个payload能够删除跟publish.php同目录下的所有文件,但是我试了一下,我发现它能够删除D盘根目录下的文件,通过../../../能够删除上级目录下的文件,能够突破www目录。

3.user.php

任意文件包含漏洞

 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了,后面好像还真有一个上传图片马的漏洞,大家等会往下看。

image

直接穿越两级目录包含了首页的index.php文件。

存储型XSS漏洞

image

我们发现编辑资料页面的参数除了sex强制转化为int,address进行了html实体编码,其他的基本没有做过滤,然后直接代入了sql语句中插入,我们可以插入XSS弹窗测试,但是最后测试发现只有email字段能够成功弹窗,查看数据库文件发现是其他字段的长度太小了,插入的语句被截断了。

image

任意文件删除

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赋值成删除的文件就行,抓包进行修改。

image

我们删除上级目录的123.txt,删除成功了,这个也是能够突破www目录的限制的,能直接删除D盘根目录文件。

文件上传漏洞

我发现编辑资料的地方存在一个文件上传,分析一下发现只能够上传图片马。文件上传它调用了img_upload函数过滤,跟踪进去看看首先限制了图片上传的类型是四种:image/jpegimage/gifimage/pngimage/pjpeg,当然了这个我们是可以伪装的,接着往下看他会获取文件的后缀也设置了一个白名单,必须是这四个:jpggifpngpjpeg,这里我们可以用%00截断来上传文件,但是上传之后他好像会按时间经常赋值文件名和加上jpg后缀,所以就是一个图片马。%00截断是php5.3.29以下才生效,后面的版本修复了,我这个实验版本是5.2,当然好像还有其他上传方式,好像有phar利用,到时候去研究一下。

任意文件删除

image

这里应该是存在一个任意文件删除的,但是上面的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大概这样:

image

注册处存在存储型XSS漏洞

 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中定义的函数

image

image

我们可以通过伪造ip注入sql语句,直接上sqlmap。

image

5.guest_book.php

SQL注入漏洞

image

同样的问题,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#

image

6.admin/ad_phone.php

存储型XSS漏洞

image

我们可以看到什么的参数都没有过滤,只要时间参数通过-分隔开来成了一个数组去检测,所以按理说其他的contenttitlecolor都是存在XSS的,但是我实际上只有前面两个触发了XSS,color字段被截断了,我发现是数据库的这个字段的长度只有10,所以没有触发成功。

7.ann.php

存储型XSS

 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

image

admin/attachment.php

SQL注入漏洞,XSS漏洞

XSS就不说了大家都知道,SQL注入漏洞存在位置:

image

测试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

admin/card.php

SQL注入跟XSS,一样的漏洞,原理也一样

admin/tpl_manage.php

任意文件包含

漏洞位置:

image

这里的tpl_name参数是用户可控的,直接用fopen函数打开了这个路径,我们只需要控制$file变量进行任意文件读取。

任意文件写入

漏洞位置:

image

这里我们act变量赋值为do_edit,然后tpl_name就是我们写入的文件名,tpl_content就是我们写入的文件内容,这里的判断逻辑是如果tpl_name不存在,就会在/templates/default目录下面写入tpl_name文件,并把tpl_content的内容写入进去。

暂时就这样吧,漏洞太多了,基本都是重复的,一个功能写错了好多地方都用的一个函数,这次收获还不错。慢慢啃吧

posted @ 2022-06-24 17:36  胖三斤1  阅读(216)  评论(0编辑  收藏  举报
Live2D