php debug模式漏洞,Laravel <= v8.4.2调试模式造成远程代码执行漏洞

2020年11月底, 在为我们的一个客户进行安全审计时, 我们发现了一个基于Laravel的网站. 虽然这个网站的安全状态很好, 但我们注意到它是在调试模式下运行的, 因此显示了大量的错误信息, 包括堆栈痕迹:

a065962ed775d91670eebd8ebf440fdc.png

经过进一步的检查, 我们发现这些堆栈痕迹是由Ignition生成的, 而Ignition是Laravel第6版开始的默认错误页面生成器. 在穷尽了其他漏洞载体之后, 我们开始对这个包进行更精确的检查.

Ignition <= 2.5.1

除了显示漂亮的堆栈痕迹, Ignition还附带了解决方案, 小段的代码可以解决你在开发应用时可能遇到的问题. 例如,如果我们在模板中使用一个未知变量,会发生这样的情况:

adfc57703bb8706163ec5c6c3b842661.png

通过点击 "使变量可选",我们模板中的{ { $username }}会自动被{ { $username ? '' }}. 如果我们检查我们的HTTP日志,我们可以看到被调用的端点:

1c203725656d2faa5662a391975d9bb2.png

除了解决方案的类名之外,我们还发送了一个文件路径和一个我们想要替换的变量名。这看起来很有趣。

让我们先检查一下类名向量:我们可以实例化任何东西吗?

class SolutionProviderRepository implements SolutionProviderRepositoryContract{...public function getSolutionForClass(string $solutionClass): ?Solution{if (! class_exists($solutionClass)) {return null;}if (! in_array(Solution::class, class_implements($solutionClass))) {return null;}return app($solutionClass);}}

不是:Ignition会确保我们指向的类实现了RunnableSolution。

那我们就来仔细看看这个类吧。负责这个的代码位于./vendor/facade/ignition/src/Solutions/MakeViewVariableOptionalSolution.php中。也许我们可以改变一个任意文件的内容?

class MakeViewVariableOptionalSolution implements RunnableSolution{...public function run(array $parameters = []){$output = $this->makeOptional($parameters);if ($output !== false) {file_put_contents($parameters['viewFile'], $output);}}public function makeOptional(array $parameters = []){$originalContents = file_get_contents($parameters['viewFile']); // [1]$newContents = str_replace('$'.$parameters['variableName'], '$'.$parameters['variableName']." ?? ''", $originalContents);$originalTokens = token_get_all(Blade::compileString($originalContents)); // [2]$newTokens = token_get_all(Blade::compileString($newContents));$expectedTokens = $this->generateExpectedTokens($originalTokens, $parameters['variableName']);if ($expectedTokens !== $newTokens) { // [3]return false;}return $newContents;}protected function generateExpectedTokens(array $originalTokens, string $variableName): array{$expectedTokens = [];foreach ($originalTokens as $token) {$expectedTokens[] = $token;if ($token[0] === T_VARIABLE && $token[1] === '$'.$variableName) {$expectedTokens[] = [T_WHITESPACE, ' ', $token[2]];$expectedTokens[] = [T_COALESCE, '??', $token[2]];$expectedTokens[] = [T_WHITESPACE, ' ', $token[2]];$expectedTokens[] = [T_CONSTANT_ENCAPSED_STRING, "''", $token[2]];}}return $expectedTokens;}...}

这段代码比我们预想的要复杂一些:读取给定的文件路径[1]后,将$variableName替换为$variableName ? '',初始文件和新文件都将被标记化[2]。如果我们的代码结构没有超出预期的变化,文件将被替换成新的内容。否则,makeOptional将返回false[3],新文件将不会被写入。因此,我们无法使用variableName做太多事情。

唯一剩下的输入变量是viewFile。如果我们对variableNam

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值