laravel5.7 反序列化漏洞复现

本文详细介绍了复现Laravel5.7框架中一个反序列化漏洞的过程,涉及PHP的反序列化、魔术方法、laravel命令执行等技术。通过构造特定的反序列化链,最终实现了远程代码执行。文章适合有一定开发基础并关注代码审计和安全研究的读者。

前言

之前接触yii2,接下来就遇到laravel5.7的反序列化了,跟着大师傅们的文章复现了一下laravel5.7的反序列化链,学习了一波。
CVE编号是CVE-2019-9081:

The Illuminate component of Laravel Framework 5.7.x has a deserialization vulnerability that can lead to remote code execution if the content is controllable, related to the __destruct method of the PendingCommand class in PendingCommand.php.

去github上下载源码:
laravel5.7,下载下来的可能回没有vendor目录,需要在根目录执行composer install就可以了。

然后就是构造一个反序列化的利用点了,在routes/web.php里面加一条路由:

Route::get('/unserialize',"UnserializeController@uns");

然后在App\Http\Controllers下面写一个控制器:

<?php

namespace App\Http\Controllers;

class UnserializeController extends Controller
{
   
   
    public function uns(){
   
   
        if(isset($_GET['c'])){
   
   
            unserialize($_GET['c']);
        }else{
   
   
            highlight_file(__FILE__);
        }
        return "uns";
    }
}

准备工作就做完了,开始分析反序列化链。

反序列化链分析

有一说一这条链真要完完全全进行分析的话,需要一定的开发水平,因为像我这样第一次接触laravel的0开发小白+代码审计小白,利用上注释,能清晰的理解这条链上三分之一的代码就很难得了,所以这条链的审计给我的体会就是学会打断点,忽略掉无用代码(我看不懂的就是无用的,笑),只要一路下去能顺利执行,就不要管中间那些代码是干啥的。

和laravel5.6相比,laravel5.7多了PendingCommand.php这个文件:
在这里插入图片描述
该类的作用是命令执行,并获取输出内容。
看一下这个新增的类,发现有一个__destruct()。经过了之前yii2的审计,现在看到__destruct()就很兴奋:
在这里插入图片描述

$this->hasExecuted默认是false的,所以可以直接进入run方法:

    /**
     * Execute the command.
     *
     * @return int
     */
    public function run()
    {
   
   
        $this->hasExecuted = true;

        $this->mockConsoleOutput();
        
        try {
   
   
            $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters);
        } catch (NoMatchingExpectationException $e) {
   
   
            if ($e->getMethodName() === 'askQuestion') {
   
   
                $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.');
            }

            throw $e;
        }

        if ($this->expectedExitCode !== null) {
   
   
            $this->test->assertEquals(
                $this->expectedExitCode, $exitCode,
                "Expected status code {
     
     $this->expectedExitCode} but received {
     
     $exitCode}."
            );
        }

        return $exitCode;
    }

文档注释上写着Execute the command,我差点都以为这是开发留的后门了。。。
不过我们要明确一点,我们最终的目的就是这里:

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

所以跟进到$this->mockConsoleOutput();

    /**
     * Mock the application's console output.
     *
     * @return void
     */
    protected function mockConsoleOutput()
    {
   
   
        $mock = Mockery::mock(OutputStyle::class.'[askQuestion]', [
            (new ArrayInput($this->parameters)), $this->createABufferedOutputMock(),
        ]);

        foreach ($this->test->expectedQuestions as $i => $question) {
   
   
            $mock->shouldReceive('askQuestion')
                ->once()
                ->ordered()
                ->with(Mockery::on(function ($argument) use ($question) {
   
   
                    return $argument->getQuestion() == $question[0];
                }))
                ->andReturnUsing(function () use ($question, $i) {
   
   
                    unset($this->test->expectedQuestions[$i]);

                    return $question[1];
                });
        }

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

一堆我看不懂的代码,不过问题不大,只要可以正常执行到命令执行的call函数,就问题不大,写个POC试试:

<?php
namespace Illuminate
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值