您当前的位置: 首页 > 

Snakin_ya

暂无认证

  • 2浏览

    0关注

    107博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

[BUUCTF][强网杯 2019]Upload

Snakin_ya 发布时间:2022-01-22 01:18:23 ,浏览量:2

考点

代码审计

反序列化

解题 信息搜集

首先打开是一个登录框,尝试sql无果

image-20211227103816167

注册登录,发现一个文件上传页面

image-20211227104719238

先试试文件上传,会将jpg文件转换为png,文件名随机生成

dirsearch扫一下目录,有备份文件www.tar.gz

解压后是一个tp5的框架

代码审计

打开文件后有两个断点

application/web/controller/Index.php

image-20220101012716789

在访问大部分页面时都会调用到login_check方法,该方法将传入的用户信息反序列化,再到数据库中进行检查

application/web/controller/Register.php

image-20220101012658339

析构方法,判断是否注册,未注册则跳转到主页

再查看一下文件上传部分的代码

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:

            
关注
打赏
1650510800
查看更多评论
0.0377s