laravel5_7 pop分析
前言
主要是在五度空间的比赛中碰到了laravel的题目,版本是5.7,赛后复现故尝试做一下总结。着实学到了不少关于找pop链的技巧。
环境
PHP版本是7.1.7,Nginx 1.14,操作系统osx 14.6 这个基本上不影响。
pop链分析
phpggc 链1,4
1和4链其实都是同一个类型的。理解起来比较简单,主要就是触发Faker\Generator的__call方法。
1 |
|
还有一个比较难用的点,就是通过Illuminate\Validation\Validator的callExtension方法来执行任意函数。
这里触发的是Validator的__call方法,但是有个方法名长度的限制。
1 | public function __call($method, $parameters) |
所以必须要类似于addCollection这样的方法才可以触发。
最后的poc
1 |
|
触发点只要是形如xxx->not_existed_mothod($arguments)
找到的几个触发点
Swift_Mime_SimpleMimeEntity的__destruct方法(需要swiftmailer组件)
1
2
3
4
5
6public function __destruct()
{
if ($this->cache instanceof Swift_KeyCache) {
$this->cache->clearAll($this->cacheKey);
}
}Symfony\Component\Routing\Loader\Configurator\ImportConfigurator 和 CollectionConfigurator
1
2
3
4
5//类似
public function __destruct()
{
$this->parent->addCollection($this->route);
}Illuminate\Contracts\Events\Dispatcher\PendingBroadcast
1 | public function __destruct() |
这里没必要给完整的pop链了,最后结果
主要思路就是找类似于$this->$client->no_exist_function($params)加上Faker\Generator的__call方法(该__call方法第一个参数可以完全控制)。
phpggc 链2
触发点和链1是一样的,但是这里利用了一个$function($p1,$p2)
1 | //namespace Illuminate\Events 中的Dispatcher |
然而system刚刚好有两个参数,所以可以被调用。如果这里的参数不对就会返回null。
phpggc 链3
很可惜不能用了。
phpggc 链5
链5和1,4最大不一样的地方在于,使用call_user_func执行了EvalLoader类的load方法,而在该方法中,存在eval执行代码从而达成目的。
来跟踪一下链5,首先是由还是由Illuminate\Broadcasting的PendingBroadcast
但这里不同的是,链5并不触发__call,这里构造调用了\Illuminate\Bus\Dispatcher类的dispatch方法。
继续跟进。
看看dispatchToQueue方法,这里直接使用call_user_func调用了Mockery\Loader\EvalLoder的load方法,
然后进入loader方法,这里要找一个不存在的classname。
使用<?php $code;?>执行代码,达到效果。
CVE-2019-9081
这个链是最特别的,也是学到最多东西的。
该链poc如下:
1 |
|
漏洞的触发点在,\Illuminate\Foundation\Testing\PendingCommand上。
在run函数,需要用一些技巧来过渡
mockConsoleOutput函数
GenericUser有可控的__get方法,可以用来过度getQuestion方法和unset($this->expectedQuestions[$i])方法。
由于Illuminate\Foundation\Application类集成了Container,而Container又实现了ArrayAccess接口,所以,当application类执行数组访问操作的时候会调用offsetGet方法。offsetGet调用make方法。
最后调用Container类的build方法,通过反射机制获取到一个Application对象。
Application对象的call方法。
这条链跟下来,发现其实主要的难点还是在生成一个新的Application对象的位置。
一个技巧是通过可控的__get方法,来绕过一些函数的验证。
总结
几条链跟下来收获颇多,一个点是找头,专注于__destruct,__wakeup函数发现触发点。一个是找利用点,例如call_user_func_array函数。中间的步骤可以找__call函数,或者沿着继承链向上找可利用函数来接上,还要记得活用类似于可以控制的__get这样的函数。