深入解析:WordPress LiteSpeed Cache 插件中的存储型 XSS 漏洞(CVE-2024-47374)
深入剖析影响 WordPress LiteSpeed Cache 插件的 CVE-2024-47374 漏洞、其影响,以及对我们检测方法的技术拆解。
引言
CVE-2024-47374 是一个影响 WordPress LiteSpeed Cache 插件的高危漏洞。该插件是一款一体化的站点加速插件,通过将频繁访问的数据存储在缓存中来帮助提升网站性能。这个存储型跨站脚本(XSS)漏洞影响该插件直至并包括 6.5.0.2 在内的所有版本。该缺陷一旦被利用,可能允许恶意行为者执行任意 JavaScript 代码。
技术细节
该漏洞源于插件处理 X-LSCACHE-VARY-VALUE HTTP 头的方式。该头部的值在解析时未经充分的净化和输出转义,从而允许注入 JavaScript 代码。该缺陷具体与插件的 CSS 优化功能相关。
存在漏洞的组件
CCSS 和 UCSS 生成函数 _ccss() 和 _load() 接受必要的参数和 HTTP 头来生成并存储数据。队列通过以下代码行创建:
litespeed-cache/src/css.cls.php中的_ccss()
private function _ccss()
{
global $wp;
$request_url = home_url($wp->request);
$filepath_prefix = $this->_build_filepath_prefix('ccss');
$url_tag = $this->_gen_ccss_file_tag($request_url);
$vary = $this->cls('Vary')->finalize_full_varies();
=============== Skip ================
// Store it to prepare for cron
Core::comment('QUIC.cloud CCSS in queue');
$this->_queue = $this->load_queue('ccss');
if (count($this->_queue) > 500) {
self::debug('CCSS Queue is full - 500');
return null;
}
$queue_k = (strlen($vary) > 32 ? md5($vary) : $vary) . ' ' . $url_tag;
$this->_queue[$queue_k] = array(
'url' => apply_filters('litespeed_ccss_url', $request_url),
'user_agent' => substr($ua, 0, 200),
'is_mobile' => $this->_separate_mobile(),
'is_webp' => $this->cls('Media')->webp_support() ? 1 : 0,
'uid' => $uid,
'vary' => $vary,
'url_tag' => $url_tag,
); // Current UA will be used to request
$this->save_queue('ccss', $this->_queue);
litespeed-cache/src/ucss.cls.php中的load()
public function load($request_url, $dry_run = false)
{
=============== Skip ================
$vary = $this->cls('Vary')->finalize_full_varies();
=============== Skip ================
// Store it for cron
$this->_queue = $this->load_queue('ucss');
if (count($this->_queue) > 500) {
self::debug('UCSS Queue is full - 500');
return false;
}
$queue_k = (strlen($vary) > 32 ? md5($vary) : $vary) . ' ' . $url_tag;
$this->_queue[$queue_k] = array(
'url' => apply_filters('litespeed_ucss_url', $request_url),
'user_agent' => substr($ua, 0, 200),
'is_mobile' => $this->_separate_mobile(),
'is_webp' => $this->cls('Media')->webp_support() ? 1 : 0,
'uid' => $uid,
'vary' => $vary,
'url_tag' => $url_tag,
); // Current UA will be used to request
$this->save_queue('ucss', $this->_queue);
请注意,$vary 变量是通过 $this->save_queue 函数存储的。$vary 变量由 finalize_full_varies 函数构造,其中包含来自 X-LSCACHE-VARY-VALUE HTTP 头的数据。
public function finalize_full_varies()
{
$vary = $this->_finalize_curr_vary_cookies(true);
$vary .= $this->finalize_default_vary(get_current_user_id());
$vary .= $this->get_env_vary();
return $vary;
}
/**
* Get request environment Vary
*
* @since 4.0
*/
public function get_env_vary()
{
$env_vary = isset($_SERVER['LSCACHE_VARY_VALUE']) ? $_SERVER['LSCACHE_VARY_VALUE'] : false;
if (!$env_vary) {
$env_vary = isset($_SERVER['HTTP_X_LSCACHE_VARY_VALUE']) ? $_SERVER['HTTP_X_LSCACHE_VARY_VALUE'] : false;
}
return $env_vary;
}
在管理面板中显示队列时,Vary Group 信息(派生自 $vary)会在管理页面上被直接打印出来,未经任何净化或转义。
根据插件厂商网站的说明,Vary Group 功能融合了 cache varies 和 user roles 的理念。该漏洞之所以出现,是因为用户可以通过 HTTP 头提供 Vary Group,而它随后会在管理页面上显示,却未经适当的净化。
以下是来自 litespeed-cache/tpl/page_optm/settings_css.tpl.php 的相关代码片段:
<?php if (!empty($ucss_queue)) : ?>
<div class="litespeed-callout notice notice-warning inline">
<h4>
<?php echo sprintf(__('URL list in %s queue waiting for cron', 'litespeed-cache'), 'UCSS'); ?> ( <?php echo count($ucss_queue); ?> )
<a href="<?php echo Utility::build_url(Router::ACTION_UCSS, UCSS::TYPE_CLEAR_Q); ?>" class="button litespeed-btn-warning litespeed-right">Clear</a>
</h4>
<p>
<?php $i = 0;
foreach ($ucss_queue as $k => $v) : ?>
<?php if ($i++ > 20) : ?>
<?php echo '...'; ?>
<?php break; ?>
<?php endif; ?>
<?php if (!is_array($v)) continue; ?>
<?php if (!empty($v['_status'])) : ?><span class="litespeed-success"><?php endif; ?>
<?php echo esc_html($v['url']); ?>
<?php if (!empty($v['_status'])) : ?></span><?php endif; ?>
<?php if ($pos = strpos($k, ' ')) echo ' (' . __('Vary Group', 'litespeed-cache') . ':' . substr($k, 0, $pos) . ')'; ?>
<?php if ($v['is_mobile']) echo ' <span data-balloon-pos="up" aria-label="mobile">📱</span>'; ?>
<?php if (!empty($v['is_webp'])) echo ' WebP'; ?>
<br />
<?php endforeach; ?>
</p>
</div>
这种缺乏净化的做法使攻击者能够将恶意脚本注入管理面板。
利用前提条件
要使该漏洞利用成功,必须启用以下两项特定的页面优化(Page Optimization)设置:
- CSS Combine:ON
- Generate UCSS:ON
CVE-2024-47374 的影响
该漏洞的影响重大,原因有以下几点:
高危:该漏洞的 CVSS 评分为 7.2,被归类为高危。
广阔的攻击面:LiteSpeed Cache 是一款热门的 WordPress 插件,安装在超过 6,000,000 个 WordPress 网站上。
管理员账户接管:如果管理员的会话被劫持,攻击者可能获得对该 WordPress 站点的完全控制。这是最严重的情形,因为它允许:
- 安装恶意插件或主题
- 修改站点内容
- 访问并窃取敏感数据
- 将被攻陷的站点作为跳板发起进一步攻击
会话劫持:该漏洞可被用于劫持已通过身份验证的用户会话,使攻击者能够以受害者的身份执行操作。
LiteSpeed Cache 中的存储型 XSS 漏洞允许攻击者注入并执行任意 JavaScript 代码。我们的检测脚本通过检查插件版本来识别存在漏洞的实例。让我们来看一下它:
VULNERABLE_VERSIONS = [
r"(?P<major_0_to_5>[0-5])\.(?P<minor>[0-9]+)(\.(?P<patch>[0-9]+))?",
r"(?P<major_6_0_to_4>6)\.(?P<minor_0_to_4>[0-4])(\.(?P<patch>[0-9]+))?",
r"(?P<major_6_5>6)\.5\.0(\.(?P<patch_0_to_2>[0-2]))$",
]
class CVE202447374Exploit(webexploit.WebExploit):
accept_request = definitions.Request(
method="GET", path="/wp-content/plugins/litespeed-cache/readme.txt"
)
check_request = definitions.Request(
method="GET", path="/wp-content/plugins/litespeed-cache/readme.txt"
)
accept_pattern = [re.compile("LiteSpeed Cache")]
match_pattern = [
re.compile(f"Stable tag: {version}") for version in VULNERABLE_VERSIONS
]
版本识别分析
VULNERABLE_VERSIONS 列表包含三个正则表达式,每个都用于匹配特定范围的存在漏洞的版本:
r"(?P<major_0_to_5>[0-5])\.(?P<minor>[0-9]+)(\.(?P<patch>[0-9]+))?":
- 该正则表达式匹配从
0.0.0到5.x.x的所有版本。 (?P<major_0_to_5>[0-5])捕获从 0 到 5 的主版本号。\.(?P<minor>[0-9]+)匹配次版本号。(\.(?P<patch>[0-9]+))?可选地匹配补丁版本,因为有些版本可能没有补丁号。
r"(?P<major_6_0_to_4>6)\.(?P<minor_0_to_4>[0-4])(\.(?P<patch>[0-9]+))?":
- 该正则表达式覆盖
6.0.x到6.4.x的版本。 (?P<major_6_0_to_4>6)专门匹配主版本 6。\.(?P<minor_0_to_4>[0-4])匹配次版本 0 到 4。- 补丁版本同样是可选的。
r"(?P<major_6_5>6)\.5\.0(\.(?P<patch_0_to_2>[0-2]))$":
- 该正则表达式非常具体,仅针对
6.5.0、6.5.0.1和6.5.0.2版本。 (?P<major_6_5>6)\.5\.0精确匹配6.5.0版本。(\.(?P<patch_0_to_2>[0-2]))$确保只匹配补丁版本 0、1 或 2,不匹配其他任何版本。
这种精确的版本匹配至关重要,因为该漏洞影响直至并包括 6.5.0.2 在内的所有版本。通过使用这些精心构造的正则表达式,脚本能够准确识别存在漏洞的版本,同时排除已修复的 6.5.1 版本及任何未来发布的版本。
目标识别与漏洞检查
脚本使用两个关键组件来识别目标并检查漏洞:
-
目标识别:
python accept_pattern = [re.compile("LiteSpeed Cache")]该模式检查readme.txt文件中是否存在LiteSpeed Cache。这是一种简单而有效的方式,用于确认目标 WordPress 站点上安装了LiteSpeed Cache插件。 -
漏洞检查:
python match_pattern = [ re.compile(f"Stable tag: {version}") for version in VULNERABLE_VERSIONS ]该方法创建一个正则表达式模式列表,每个模式都在readme.txt文件中查找Stable tag:行,并匹配其中与某个存在漏洞的版本相符的版本号。通过遍历这些模式,脚本可以快速判断所安装的版本是否存在漏洞。
文件请求策略
脚本针对位于 /wp-content/plugins/litespeed-cache/readme.txt 的 readme.txt 文件。选择该文件是因为:
- 在 WordPress 安装中,它通常是可公开访问的。
- 它以标准化格式(
Stable tag: X.X.X)包含版本信息。 - 访问该文件是非侵入式的,不会有修改或损坏目标系统的风险。
通过结合这些要素,该脚本提供了一种稳健、准确且安全的方法,用于检测易受 CVE-2024-47374 影响的 LiteSpeed Cache 实例。
缓解措施
为缓解该漏洞,网站管理员应将 LiteSpeed Cache 插件更新到 6.5.1 或更高版本。该版本于 2024 年 9 月 25 日发布,修复了 CVE-2024-47374 漏洞。
使用 OXO 测试该漏洞
如果您担心自己的实例可能存在漏洞,请按照以下步骤使用 OXO 工具运行测试:
通过 pip 安装 OXO:
pip install -U ostorlab
从 OXO agent 商店安装 asteroid agent:
oxo agent install agent/ostorlab/asteroid
使用 asteroid agent 运行扫描,命令如下:
oxo scan run --agent agent/ostorlab/asteroid link --url <target-URL> --method GET