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 二次注入:
不过,数据库都重装了,即使能获取原来数据库表的数据,操作也相当繁琐。
发表评论 取消回复