我们的 AI 引擎 Neutron 在加州大学伯克利分校的 CyberGym 基准测试中取得了 96.75% 的成绩。 了解更多

安全

安全

深入解析: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)设置:

  1. CSS Combine:ON
  2. 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 版本及任何未来发布的版本。

目标识别与漏洞检查

脚本使用两个关键组件来识别目标并检查漏洞:

  1. 目标识别: python accept_pattern = [re.compile("LiteSpeed Cache")] 该模式检查 readme.txt 文件中是否存在 LiteSpeed Cache。这是一种简单而有效的方式,用于确认目标 WordPress 站点上安装了 LiteSpeed Cache 插件。

  2. 漏洞检查: 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 文件。选择该文件是因为:

  1. 在 WordPress 安装中,它通常是可公开访问的。
  2. 它以标准化格式(Stable tag: X.X.X)包含版本信息。
  3. 访问该文件是非侵入式的,不会有修改或损坏目标系统的风险。

通过结合这些要素,该脚本提供了一种稳健、准确且安全的方法,用于检测易受 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

标签:

xss, kev, security, wordpress