cms 脉络

程序目录结构

审计思路

后台登录页面 SQL 注入

报错注入

伪造登录

文件上传(一)

文件上传(二)

任意文件删除+重装漏洞


beecms 4.0 后台存在多个漏洞,登录页面存在一个 SQL 注入,可以伪造账号登录到后台,后台的管理功能存在文件上传和任意文件删除。

找到后台之后的 getshell 思路:利用 SQL 注入伪造账号登录到后台,然后上传 webshell。

 登录成功并跳转。

上传文件,然后抓包分析,发现请求地址是 admin/admin_pic_upload.php,到这个文件定位上传文件的处理功能:

if(is_uploaded_file($v)){
    $pic_info['tmp_name']=$v;
	$pic_info['size']=$_FILES['up']['size'][$k];
	$pic_info['type']=$_FILES['up']['type'][$k];
	$pic_info['name']=$_FILES['up']['name'][$k];
	$pic_name_alt=empty($is_alt)?'':$pic_alt[$k];
	$is_up_size = $_sys['upload_size']*1000*1000;    $value_arr=up_img($pic_info,$is_up_size,array('image/gif','image/jpeg','image/png','image/jpg','image/bmp','image/pjpeg','image/x-png'),$up_is_thumb,$up_thumb_width,$up_thumb_height,$logo=1,$pic_name_alt);
	
    //处理上传后的图片信息
	$pic_name=$value_arr['up_pic_name'];//图片名称空
	$pic_ext=$value_arr['up_pic_ext'];//图片扩展名
	$pic_title = $pic_alt[$k];//图片描述
	$pic_size = $value_arr['up_pic_size'];//图片大小
	$pic_path = $value_arr['up_pic_path'];//上传路径
	$pic_time = $value_arr['up_pic_time'];//上传时间
	$pic_thumb = iconv('GBK','UTF-8',$value_arr['thumb']);//缩略图
	$cate = empty($pic_cate)?1:$pic_cate;//图片栏目
	
    //入库
    $sql="insert into ".DB_PRE."uppics (pic_name,pic_ext,pic_alt,pic_size,pic_path,pic_time,pic_thumb,pic_cate) values ('".$pic_name."','".$pic_ext."','".$pic_title."','".$pic_size."','".$pic_path."','".$pic_time."','".$pic_thumb."',".$cate.")";
    $mysql->query($sql);
}

先获取一些文件的基本信息,然后执行 up_img(),这个函数就是处理上传文件并移动的地方,跟进:

function up_img($file,$size,$type,$thumb=0,$thumb_width='',$thumb_height='',$logo=1,$pic_alt=''){
		if(file_exists(DATA_PATH.'sys_info.php')){include(DATA_PATH.'sys_info.php');}
		if(is_uploaded_file($file['tmp_name'])){
		if($file['size']>$size){
			msg('图片超过'.$size.'大小');
		}
		$pic_name=pathinfo($file['name']);//图片信息
		
		$file_type=$file['type'];
		if(!in_array(strtolower($file_type),$type)){
			msg('上传图片格式不正确');
		}
		$path_name="upload/img/";
		$path=CMS_PATH.$path_name;
		if(!file_exists($path)){
			@mkdir($path);
		}
		$up_file_name=empty($pic_alt)?date('YmdHis').rand(1,10000):$pic_alt;
		$up_file_name2=iconv('UTF-8','GBK',$up_file_name);
		$file_name=$path.$up_file_name2.'.'.$pic_name['extension'];
		
		if(file_exists($file_name)){
			msg('已经存在该图片,请更改图片名称!');//判断是否重名
		}
		
		$return_name['up_pic_size']=$file['size'];//上传图片大小
		$return_name['up_pic_ext']=$pic_name['extension'];//上传文件扩展名
		$return_name['up_pic_name']=$up_file_name;//上传图片名
		$return_name['up_pic_path']=$path_name;//上传图片路径
		$return_name['up_pic_time']=time();//上传时间
		unset($pic_name);
		//开始上传
		if(!move_uploaded_file($file['tmp_name'],$file_name)){
			msg('图片上传失败','',0);
		}
        .....
}

只做了文件大小和 MIME 类型的校验,所以能绕过,只需要 burpsuite 改一下 Content-Type 即可。

上传脚本后,接着是找到脚本的文件名和路径,这可以在 HTML 代码中找到:

拼接 upload 目录访问:

与上传图片类似,上传附件的处理在一个 up_file() 函数中:

<?php
echo "Hello World !";?>function up_file($file,$size,$type,$path='',$name='') {
	$return_arr=array();
	if(is_uploaded_file($file['tmp_name'])) {
		if($file['size']>$size) {
			msg('文件超过'.$size.'大小');
		}
		$pic_name=pathinfo($file['name']);
		$file_type=$pic_name['extension'];
		$return_arr['ext'] = $pic_name['extension'];
		//扩展名
		$return_arr['size'] = $file['size'];
		//大小
		if(!in_array($file_type,$type)) {
			msg('上传文件格式不正确'.$file_type);
		}
		$path=empty($path)?CMS_PATH."upload/file/":CMS_PATH.$path.'/';
		if(!file_exists($path)) {
			@mkdir($path);
		}
		$name=$pic_name['filename'].'-'.date('YmdHis');
		$name2=iconv('UTF-8','GBK',$name);
		$file_name=$path.$name2.'.'.$pic_name['extension'];
		$file_name2=$path.$name.'.'.$pic_name['extension'];
		if(file_exists($file_name)) {
			msg('已经存在该附件,请更改附件名称!');
			//判断是否重名
		}
		unset($pic_name);
		if(!move_uploaded_file($file['tmp_name'],$file_name)) {
			msg('文件上传失败');
		}
		$return_name=str_replace(CMS_PATH,"",$file_name2);
		//$return_name=CMS_SELF.$return_name;
		$return_arr['file'] = $return_name;
		//上传文件路径
		$return_arr['time'] = time();
		//上传时间
	} else {
		msg('文件不能为空');
	}
	//存储相关信息
	return $return_arr;
}

做了文件大小和文件扩展名的校验,对于文件扩展名校验的绕过,可以在后台的“允许上传的文件类型”添加 php:

这样一来就能上传 php 脚本了。

删除成功。

配合这个漏洞,如果目标网站没有删除 install 目录,那么就可以删除掉 install.lock 文件,然后访问 install 目录执行重装功能。不过,在重装时写入的数据库配置信息经过 addslashes() 转义,并且配置文件的代码用了单引号:

如果是双引号,可以写入 ${ eval($_POST['cmd'])},而这里是单引号,所以无法 getshell。但是,可以造成 SQL 二次注入:

不过,数据库都重装了,即使能获取原来数据库表的数据,操作也相当繁琐。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部