Key Information 关键信息
- Sonar’s Vulnerability Research Team has discovered an issue that led to multiple XSS vulnerabilities in the popular Content Management System Joomla.
Sonar 的漏洞研究团队发现了一个导致流行的内容管理系统 Joomla 中存在多个 XSS 漏洞的问题。 - The issue discovered with the help of SonarCloud affects Joomla’s core filter component and is tracked as CVE-2024-21726.
在 SonarCloud 的帮助下发现的问题影响 Joomla 的核心过滤器组件,并被跟踪为 CVE-2024-21726。 - Attackers can leverage the issue to gain remote code execution by tricking an administrator into clicking on a malicious link.
攻击者可以利用该问题诱骗管理员单击恶意链接来获得远程代码执行。 - The underlying PHP bug is an inconsistency in how PHP’s mbstring functions handle invalid multibyte sequences.
潜在的 PHP 错误是 PHP 的 mbstring 函数处理无效多字节序列的方式不一致。 - The bug was fixed with PHP versions 8.3 and 8.4, but not backported to older PHP versions.
该错误已在 PHP 8.3 和 8.4 版本中修复,但未向后移植到较旧的 PHP 版本。 - Joomla released a security announcement and published version 5.0.3/4.4.3, which mitigates the vulnerability.
Joomla发布了安全公告并发布了5.0.3/4.4.3版本,缓解了该漏洞。
Joomla 乔姆拉
Joomla is a free and open-source Content Management System (CMS) used for building websites and online applications. Roughly 2% of all websites use Joomla, which makes it one of the most popular CMSs with millions of deployments worldwide.
Joomla 是一个免费的开源内容管理系统 (CMS),用于构建网站和在线应用程序。大约 2% 的网站使用 Joomla,这使其成为最受欢迎的 CMS 之一,在全球拥有数百万次部署。
The widespread usage of Joomla and the fact that most deployments are publicly accessible makes it a valuable target for threat actors. Just recently, Joomla was targeted in an attack against different organizations via an improper access control vulnerability (CVE-2023-23752).
Joomla 的广泛使用以及大多数部署均可公开访问的事实使其成为威胁行为者的宝贵目标。就在最近,Joomla 通过不当访问控制漏洞 (CVE-2023-23752) 成为针对不同组织的攻击目标。
In this article, we dive into an interesting XSS issue detected by SonarCloud, which led us down the rabbit hole to the discovery of a bug in PHP. We will explain how an inconsistency in PHP’s mbstring functions can be leveraged by attackers to bypass Joomla’s input sanitization introducing multiple XSS vulnerabilities.
在本文中,我们深入研究了 SonarCloud 检测到的一个有趣的 XSS 问题,它使我们陷入了兔子洞,发现了 PHP 中的一个错误。我们将解释攻击者如何利用 PHP mbstring 函数的不一致来绕过 Joomla 的输入清理,从而引入多个 XSS 漏洞。
Impact 影响
Joomla versions 5.0.2/4.4.2 and below are prone to multiple XSS vulnerabilities. Attackers tricking an administrator into clicking on a malicious link can gain remote code execution (RCE):
Joomla 5.0.2/4.4.2 及以下版本容易出现多个 XSS 漏洞。攻击者诱骗管理员点击恶意链接可以获得远程代码执行(RCE):
Joomla version 5.0.3/4.4.3 mitigates the issue regardless of the PHP version. The underlying PHP bug was fixed with PHP versions 8.3 and 8.4, but not backported to older PHP versions.
无论 PHP 版本如何,Joomla 版本 5.0.3/4.4.3 都可以缓解该问题。 PHP 版本 8.3 和 8.4 修复了底层 PHP 错误,但未向后移植到较旧的 PHP 版本。
We strongly recommend updating Joomla to the latest version as well as keeping your PHP version up-to-date.
我们强烈建议将 Joomla 更新到最新版本并保持您的 PHP 版本为最新。
Technical Details 技术细节
In our continuous effort to help secure open-source projects and improve our Clean Code solution, we regularly scan open-source projects via SonarCloud and evaluate the findings. When scanning Joomla, SonarCloud reported an interesting XSS issue:
在我们不断努力帮助保护开源项目并改进我们的清洁代码解决方案的过程中,我们定期通过 SonarCloud 扫描开源项目并评估结果。在扫描 Joomla 时,SonarCloud 报告了一个有趣的 XSS 问题:
View this issue on SonarCloud
在 SonarCloud 上查看此问题
This small code snippet is taken from a settings page on the admin panel. According to the raised issue, the query parameter forcedItemType
is reflected in the output, which introduces an XSS vulnerability.
这个小代码片段取自管理面板上的设置页面。根据提出的问题,查询参数 forcedItemType
反映在输出中,这引入了XSS漏洞。
Please notice that the third argument of the get
method used to retrieve the query parameter is set to string
. This value determines which filters should be applied to the query parameter. Under the hood, the get
method uses the Joomla\Filter\InputFilter
class to sanitize potentially malicious input, which should prevent an XSS attack.
请注意,用于检索查询参数的 get
方法的第三个参数设置为 string
。该值确定应将哪些过滤器应用于查询参数。在底层, get
方法使用 Joomla\Filter\InputFilter
类来清理潜在的恶意输入,这应该可以防止 XSS 攻击。
The filter logic is quite complex and uses a method called cleanTags
to remove all HTML tags that are not explicitly allowed. For query parameters, no tags are allowed at all.
过滤器逻辑相当复杂,并使用名为 cleanTags
的方法来删除所有未明确允许的 HTML 标记。对于查询参数,根本不允许使用任何标签。
Thus, for the following example input:
因此,对于以下示例输入:
…, the <script>
tags are removed, which results in this output:
…, <script>
标签被删除,这会导致以下输出:
The cleanTags
method performs this sanitization by determining the position of any opening tags (<
) and then removing all data following until and including the corresponding closing tag (>
):
cleanTags
方法通过确定任何开始标记 ( <
) 的位置来执行此清理,然后删除直到并包括相应的结束标记 ( >
) 之后的所有数据):
The characters before an opening tag (e.g., some-text
in the example above) are extracted by determining the offset of the opening tag ($tagOpenStart
) via StringHelper::strpos
and then using StringHelper::substr
to extract it:
通过 StringHelper::strpos
确定开始标记 ( $tagOpenStart
) 的偏移量来提取开始标记之前的字符(例如上例中的 some-text
),然后使用 StringHelper::substr
来提取它:
For the example string some-text<script>alert(1)</script>
, the first call to StringHelper::substr
returns the string some-text
, which is appended to the $preTag
variable:
对于示例字符串 some-text<script>alert(1)</script>
,第一次调用 StringHelper::substr
返回字符串 some-text
,该字符串附加到 $preTag
变量中:
On the second iteration, the string alert(1)
is added:
在第二次迭代中,添加字符串 alert(1)
:
The $preTag
variable used to collect all sanitized substrings is later returned as the final result:
用于收集所有已清理子字符串的 $preTag
变量稍后将作为最终结果返回:
The StringHelper::strpos
and StringHelper::substr
methods are just wrappers around the respective PHP mbstring functions mb_strpos
and mb_substr
.
StringHelper::strpos
和 StringHelper::substr
方法只是各自 PHP mbstring 函数 mb_strpos
和 mb_substr
的包装器。
When determining if this sanitization is safe, we noticed that both PHP functions, mb_strpos,
and mb_substr
, handle invalid UTF-8 sequences differently. When mb_strpos
encounters a UTF-8 leading byte, it tries to parse the following continuation bytes until the full byte sequence is read. If an invalid byte is encountered, all previously read bytes are considered one character, and the parsing is started over again at the invalid byte:
在确定这种清理是否安全时,我们注意到 PHP 函数 mb_strpos,
和 mb_substr
处理无效 UTF-8 序列的方式不同。当 mb_strpos
遇到 UTF-8 前导字节时,它会尝试解析以下连续字节,直到读取完整的字节序列。如果遇到无效字节,则之前读取的所有字节都被视为一个字符,并在无效字节处重新开始解析:
Thus, the following call to mb_strpos
returns the index 4
:
因此,以下对 mb_strpos
的调用返回索引 4
:
This index is the position of the opening angle bracket <
(3c
) character within the string.
该索引是左尖括号 <
( 3c
) 字符在字符串中的位置。
mb_substr
, on the other hand, skips over continuation bytes when encountering a leading byte:
另一方面,当遇到前导字节时, mb_substr
会跳过连续字节:
This means that for mb_substr,
the first four bytes are considered one character and the opening angle bracket <
(3c
) character has the index 2
. Thus, the following call to mb_substr
returns "\xf0\x9fAAA<B"
when using the index returned by mb_strpos
:
这意味着对于 mb_substr,
,前四个字节被视为一个字符,并且左尖括号 <
( 3c
) 字符的索引为 2
.因此,当使用 mb_strpos
返回的索引时,以下对 mb_substr
的调用将返回 "\xf0\x9fAAA<B"
:
Because of this inconsistency between both functions, Joomla’s sanitization extracts not only the text before an opening angle bracket but also the opening angle bracket itself and the following character when encountering this invalid UTF-8 byte sequence:
由于两个函数之间存在这种不一致,Joomla 的清理功能在遇到此无效 UTF-8 字节序列时不仅会提取左尖括号之前的文本,还会提取左尖括号本身和以下字符:
An attacker can insert multiple invalid UTF-8 sequences, which effectively offset the index returned by StringHelper::strpos
way beyond the opening angle bracket and thus include arbitrary HTML tags in the sanitized output. This completely bypasses the sanitization applied by Joomla. Since this issue affects Joomla’s core filter functionality, which is used all over the whole code base, this leads to multiple XSS vulnerabilities.
攻击者可以插入多个无效的 UTF-8 序列,这些序列有效地将 StringHelper::strpos
返回的索引偏移到左尖括号之外,从而在清理后的输出中包含任意 HTML 标签。这完全绕过了 Joomla 所应用的清理。由于此问题影响 Joomla 的核心过滤功能(该功能在整个代码库中使用),因此会导致多个 XSS 漏洞。
One of the resulting XSS vulnerabilities can for example be leveraged by an attacker to craft a malicious link. When an administrator clicks on this link, the injected JavaScript payload can be used to customize a template and insert arbitrary PHP code. Thus, an attacker can gain remote code execution (RCE) by tricking an administrator into clicking on the malicious link.
例如,攻击者可以利用由此产生的 XSS 漏洞之一来制作恶意链接。当管理员单击此链接时,注入的 JavaScript 有效负载可用于自定义模板并插入任意 PHP 代码。因此,攻击者可以通过欺骗管理员单击恶意链接来获得远程代码执行 (RCE)。
Patch 修补
Joomla addressed the issue by replacing the usage of the mbstring functions with PHP’s regular string functions:
Joomla 通过用 PHP 的常规字符串函数替换 mbstring 函数的使用来解决这个问题:
The difference between these functions is that PHP’s regular string functions are not multibyte aware and operate on single bytes. Since multibyte awareness is not required for the applied sanitization, these functions should be preferred.
这些函数之间的区别在于 PHP 的常规字符串函数不支持多字节,而是对单字节进行操作。由于所应用的清理不需要多字节感知,因此应该首选这些函数。
We also reported the inconsistent behavior of the mbstring functions to the PHP maintainers, since we consider it as unintended. The PHP maintainers provided a patch, which makes the behavior consistent by not skipping over continuation bytes when encountering a leading byte. Unfortunately, the issue was not classified as security-relevant, which means that the patch is not backported to older versions of PHP.
我们还向 PHP 维护人员报告了 mbstring 函数的不一致行为,因为我们认为这是无意的。 PHP 维护者提供了一个补丁,该补丁通过在遇到前导字节时不跳过连续字节来使行为保持一致。不幸的是,该问题未被归类为与安全相关的问题,这意味着该补丁不会向后移植到旧版本的 PHP。
More background information on the behavior of the PHP mbstring functions and the patch can be found in the excellent explanation from Alex Dowad in the related commit message.
有关 PHP mbstring 函数和补丁的行为的更多背景信息可以在相关提交消息中 Alex Dowad 的精彩解释中找到。
Timeline 时间线
DATE 日期 | ACTION 行动 |
2023-11-22 | We report the vulnerability to the Joomla! Security Strike Team 我们向 Joomla! 报告该漏洞。安全突击队 |
2023-11-28 | The Joomla! Security Strike Team confirms our findings. 乔姆拉!安全打击小组证实了我们的发现。 |
2023-12-01 | We report the inconsistent mbstring function behavior to the 我们将不一致的 mbstring 函数行为报告给 PHP maintainers. PHP 维护者。 |
2023-12-10 | The PHP maintainers provide a patch, which is applied to PHP 维护者提供了一个补丁,该补丁适用于 PHP 8.3 and 8.4. PHP 8.3 和 8.4。 |
2024-02-20 | Joomla releases version 5.0.3/4.4.3, which mitigates the issue Joomla 发布了 5.0.3/4.4.3 版本,缓解了该问题 regardless of the PHP version. 与 PHP 版本无关。 |
2024-02-20 | Coordinated release of security announcement by Joomla and Sonar. Joomla 和 Sonar 协调发布安全公告。 |
2024-02-23 | Full technical details added. 添加了完整的技术细节。 |
Summary 概括
In this article, we explained how SonarCloud led us to an interesting XSS finding in the popular CMS Joomla. During our analysis of the issue, we discovered an inconsistency in how PHP’s mbstring functions handle invalid multibyte sequences. Attackers could leverage this behavior to bypass the sanitization performed by Joomla’s core filter leading to multiple XSS vulnerabilities.
在本文中,我们解释了 SonarCloud 如何引导我们在流行的 CMS Joomla 中发现一个有趣的 XSS。在分析该问题的过程中,我们发现 PHP 的 mbstring 函数处理无效多字节序列的方式不一致。攻击者可以利用此行为绕过 Joomla 核心过滤器执行的清理,从而导致多个 XSS 漏洞。
Finally, we would like to thank the Joomla! Security Strike Team for quickly responding to our notification, collaborating on a corresponding patch, and informing all users.
最后,我们要感谢Joomla!安全打击团队快速响应我们的通知,协作开发相应的补丁,并通知所有用户。
Also, thanks a lot to Alex Dowad for quickly addressing the issue from the PHP side!
另外,非常感谢 Alex Dowad 从 PHP 方面快速解决了这个问题!
Related Blog Posts 相关博客文章
- WordPress Core – Unauthenticated Blind SSRF
WordPress 核心 – 未经身份验证的盲 SSRF - WordPress < 5.8.3 – Object Injection Vulnerability
WordPress < 5.8.3 – 对象注入漏洞 - Grav CMS 1.7.10 – Code Execution Vulnerabilities
Grav CMS 1.7.10 – 代码执行漏洞 - Ghost CMS 4.3.2 – Cross-Origin Admin Takeover
Ghost CMS 4.3.2 – 跨源管理员接管
原文始发于Stefan Schiller:Joomla: PHP Bug Introduces Multiple XSS Vulnerabilities
转载请注明:Joomla: PHP Bug Introduces Multiple XSS Vulnerabilities | CTF导航