目录导航
WordPress 插件公开了许多接口,例如:
- AJAX 端点 (
/wp-admin/admin-ajax.php
) - 管理菜单页面 (
/wp-admin/admin.php?page=...
) - PHP 文件(在
/wp-content/plugins/
)目录中, - REST 路由 (
/wp-json/...
)。
这些接口具有一致的信任边界:我们知道不可信输入的去向,并且可以检测在该输入上执行了哪些操作。
例如,如果您访问一个.php
文件,提供适当的参数,并导致一个文件被删除,您就知道这是一个漏洞。您知道您控制哪些参数以及您不控制哪些参数——例如,您可以将登录的管理员重定向到具有任意 GET 参数的管理员菜单页面,但您不控制他们的 cookie。
因此,可以半自动扫描所有 WordPress 插件中的多类漏洞。
我写了一个工具:
- 多次执行每个 AJAX 端点、菜单页面、REST 路由或文件,
- 将payloads注入 GET、POST 等数组或 REST 参数(下一节将详细介绍如何完成),
- 用一堆难看的正则表达式1分析输出以检测:
- 调用 WordPress 函数(例如
wp_delete_post
), - 崩溃(“没有这样的文件或目录”,“您的 SQL 语法有错误”,…),
- XSS(回显包含“或<的已知有效载荷),
- 等等。
- 调用 WordPress 函数(例如
这种方法可以转移到其他 CMS 插件生态系统,但不能直接转移到 Python 包。如果 Python 包允许您删除任意文件,则它可能是也可能不是漏洞,具体取决于包角色和您的特定设置。
注入参数
在 PHP 中_GET
,_POST
、_SERVER
、_COOKIE
、 和_REQUEST
数组包含各种请求参数(例如 GET 和 POST 数据、cookie、服务器配置和标头)。我已将它们替换为允许访问任何密钥的对象 – 并以定义的概率从预定义的有效负载列表中返回有效负载。
假设 AJAX 路由由以下函数处理:
public function delete_saved_block() {
$block_id = (int) sanitize_text_field($_REQUEST['block_id']);
$deleted_block = wp_delete_post($block_id);
wp_send_json_success($deleted_block);
}
有一定的可能性,$_REQUEST['block_id']
将成为预定义有效负载列表中的任何有效负载,从而允许检测到wp_delete_post
被攻击者控制的值调用。
即使参数名称很难猜到,这种方法也可以轻松注入有效负载——该工具不区分id
和 secret_parameter_65e3c14a1d
。
一些键需要手动排除(例如$_SERVER['HTTP_AUTHORIZATION']
or $_GET['doing_wp_cron']
),因为它们的值是由 WordPress 处理的,并且提供它们会导致无法访问插件代码。
此外,有一定的概率会返回一个随机类型的数组而不是字符串有效负载:
- 带有字符串有效负载的单例数组,
- 递归地,允许访问任何键的对象,
- 单例数组:随机有效载荷 → 随机有效载荷。
检测漏洞
该工具可以检测以下漏洞:
- 各种崩溃,
- 有潜在危险的操作,
- 信息泄露。
其中一些检查会导致大量 CVE(例如 XSS 检查),而另一些则不会(例如,旨在捕获eval()
不受信任代码的语法错误检查)。
跨站脚本
为了检测 XSS,实施了检查以检测到被回显的有效负载(或通过不阻止 XSS 的转义回显,例如以 为前缀"
)\
。
崩溃
检测到以下类型的崩溃:
错误和“没有这样的文件或目录”或“未能打开流”错误消息,fopen()
/file_get_contents()
/require()
/require_once()
/include()
/include_once()
unlink()
错误信息,call_user_func()
相关的崩溃,- SQL 错误消息,
unserialize()
错误,- 解析/语法错误以检测
eval()
调用, - “找不到命令”错误消息,
simplexml_load_string()
错误信息2。
信息泄露
分析输出以观察是否显示已知的用户电子邮件或文件名。
WordPress 操作
WordPress 已被检测到:
- 调用
maybe_unserialize
, - 调用
update_option
// ,update_site_option
_delete_option
- 调用
wp_insert_user
, - 调用
wp_insert_post
// ,wp_update_post
_wp_delete_post
- 调用
wp_mail
, - 调用
query
(这个产生了特别大量的误报,需要额外过滤), - 调用
get_users
(这个是在意外发现 CVE-2021-25110后添加的,攻击者可以通过精心设计的用户搜索查询泄露任意用户电子邮件)。
附加检查
模糊测试后,管理面板、主页和帖子页面被爬网以查找已知有效负载的出现。例如,这 允许 在social-networks-auto-poster-facebook-twitter-g
.
对 PHP 的更改
修补equality
我已经修补了 PHP,以便任何值和已知有效负载之间的相等比较true
以 1/3 的概率返回。原谅我这个。
使用此补丁,我能够检测到以下漏洞:
if ($_GET['action'] == 'please-remove-post') {
wp_delete_post($_GET['id']);
}
不幸的是,这也导致了大量的误报。误报例如以以下形式:
if (in_array($order, array("ASC", "DESC"), true)) {
query("(...) ORDER BY $order");
}
我使用的这个问题的唯一解决方案是浏览这些误报和诅咒。进一步的研究可能会导致提出其他解决方案。
其他变化
此外,我已经修补了 PHP 解释器,以便:
- 当
base64_decode
对已知有效载荷执行时,再次返回此有效载荷, - 当
json_decode
对已知有效负载执行时,返回一个对象,该对象在访问任何键时返回有效负载。这些是用作例如$_GET
数组的相同对象, - 执行重定向时,会显示相关信息,以便检测 Open Redirect 漏洞。
测试
测试驱动的方法在开发过程中至关重要。测试检查该工具是否会发现一个已知漏洞。例如,我可以编写一个测试来检查:
在 3.3.23 版本中对sassy-social-share插件的
wp_ajax_heateor_sss_import_config
端点进行 模糊测试时,该工具应检测到在攻击者控制的有效负载上调用该端点。maybe_unserialize()
假阳性与假阴性
这种方法产生了大量的误报。这是一个深思熟虑的决定,因为我想整理多个报告而不是遗漏漏洞。
另一种方法是编写额外的过滤逻辑。例如,有多个报告回显了 HTML 有效负载 – 但在检查它们时,我观察到Content-Type
添加了正确的 JSON 标头。这是可以自动检查的情况之一。
其他
Fuzzing 在 Docker 容器中执行,为每个插件重新创建。
断开网络很重要,因为很多插件调用其他 Web 服务,我想避免在那里发送随机有效负载。
我发现将插件模糊测试和输出分析分开也很有帮助。因为输出是用很多正则表达式分析的,所以出现了错误。因此,相对快速的重新扫描可以加快开发速度。
结果(最后更新:2022-02-14)
由于时间限制,我只关注最流行的插件。截至目前,该工具发现的以下漏洞已经修复并发布:
ID | 插件 | CVE | 插件安装数量 | 漏洞类型 | 链接 |
---|---|---|---|---|---|
1 | updraftplus | CVE-2021-25022 | 3,000,000 | Reflected XSS | WPScan |
2 | code-snippets | CVE-2021-25008 | 500,000 | Reflected XSS | WPScan |
3 | woocommerce-pdf-invoices-packing-slips | CVE-2021-24991 | 300,000 | Reflected XSS | WPScan |
4 | ad-inserter | CVE-2022-0288 | 200,000 | Reflected XSS | WPScan |
5 | complianz-gdpr | CVE-2022-0193 | 200,000 | Reflected XSS | WPScan |
6 | custom-facebook-feed | CVE-2021-25065 | 200,000 | Reflected XSS | WPScan |
7 | loginpress | CVE-2022-0347 | 200,000 | Reflected XSS | WPScan |
8 | use-any-font | CVE-2021-24977 | 200,000 | Arbitrary CSS append + stored XSS | WPScan |
9 | white-label-cms | CVE-2022-0422 | 200,000 | Reflected XSS | WPScan |
10 | wp-cerber | CVE-2022-0429 | 200,000 | Stored XSS | WPScan |
11 | capability-manager-enhanced | CVE-2021-25032 | 100,000 | Arbitrary settings update | WPScan |
12 | chaty | CVE-2021-25016 | 100,000 | Reflected XSS | WPScan |
13 | cmp-coming-soon-maintenance | CVE-2022-0188 | 100,000 | Possibility to add arbitrary CSS | WPScan |
14 | download-manager | CVE-2021-24969 | 100,000 | Stored XSS | WPScan |
15 | download-manager | CVE-2021-25069 | 100,000 | Reflected XSS | WPScan |
16 | email-subscribers | CVE-2022-0439 | 100,000 | Blind SQL Injection | WPScan |
17 | modern-events-calendar-lite | CVE-2021-24925 | 100,000 | Reflected XSS | WPScan |
18 | modern-events-calendar-lite | CVE-2021-24946 | 100,000 | Blind SQL injection | WPScan |
19 | modern-events-calendar-lite | CVE-2021-25046 | 100,000 | Stored XSS | WPScan |
20 | paid-memberships-pro | CVE-2021-25114 | 100,000 | Blind SQL Injection | WPScan |
21 | ti-woocommerce-wishlist | CVE-2022-0412 | 100,000 | Blind SQL Injection | WPScan |
22 | webp-converter-for-media | CVE-2021-25074 | 100,000 | Open redirect | WPScan |
23 | woocommerce-products-filter | CVE-2021-25085 | 100,000 | Reflected XSS | WPScan |
24 | wpvivid-backuprestore | CVE-2021-24994 | 100,000 | Stored XSS | WPScan |
25 | social-networks-auto-poster-facebook-twitter-g | CVE-2021-24975 | 90,000 | Stored XSS | WPScan |
26 | social-networks-auto-poster-facebook-twitter-g | CVE-2021-25072 | 90,000 | CSRF post removal | WPScan |
27 | themify-portfolio-post | CVE-2022-0200 | 80,000 | Reflected XSS (logged-in POST 3) | WPScan |
28 | woo-product-feed-pro | CVE-2021-24974 | 80,000 | Stored XSS | WPScan |
29 | woo-product-feed-pro | CVE-2022-0426 | 80,000 | Reflected XSS (logged-in POST 3) | WPScan |
30 | booking | CVE-2021-25040 | 60,000 | Reflected XSS | WPScan |
31 | mappress-google-maps-for-wordpress | CVE-2022-0208 | 60,000 | Reflected XSS | WPScan |
32 | permalink-manager | CVE-2022-0201 | 60,000 | Reflected XSS | WPScan |
33 | powerpack-lite-for-elementor | CVE-2021-25027 | 60,000 | Reflected XSS | WPScan |
34 | real-cookie-banner | CVE-2022-0445 | 60,000 | CSRF settings reset and deleting all GDPR consents | WPScan |
35 | wd-instagram-feed | CVE-2021-25047 | 60,000 | Reflected XSS | WPScan |
36 | woocommerce-currency-switcher | CVE-2021-25043 | 60,000 | Reflected XSS | WPScan |
37 | woocommerce-currency-switcher | CVE-2022-0234 | 60,000 | Reflected XSS | WPScan |
38 | wp-responsive-menu | CVE-2021-24971 | 60,000 | Stored XSS | WPScan |
39 | wp-rss-aggregator | CVE-2021-24988 | 60,000 | Stored XSS | WPScan |
40 | wp-rss-aggregator | CVE-2022-0189 | 60,000 | Reflected XSS (logged-in POST 3) | WPScan |
41 | ditty-news-ticker | CVE-2022-0533 | 50,000 | Reflected XSS | WPScan |
42 | event-tickets | CVE-2021-25028 | 50,000 | Open redirect | WPScan |
43 | simple-membership | CVE-2022-0328 | 50,000 | CSRF member deletion | WPScan |
44 | bnfw | CVE-2022-0345 | 40,000 | E-mail leak | WPScan |
45 | tutor | CVE-2021-25017 | 40,000 | Reflected XSS | WPScan |
46 | advanced-cron-manager | CVE-2021-25084 | 30,000 | Arbitrary cron configuration change | WPScan |
47 | contact-form-7-skins | CVE-2021-25063 | 30,000 | Reflected XSS | WPScan |
48 | easy-paypal-donation | CVE-2021-24989 | 30,000 | CSRF post removal | WPScan |
49 | futurio-extra | CVE-2021-25110 | 30,000 | E-mail leak | WPScan |
50 | lead-form-builder | CVE-2021-24967 | 30,000 | Stored XSS | WPScan |
51 | my-calendar | CVE-2021-24927 | 30,000 | Reflected XSS | WPScan |
52 | notificationx | CVE-2022-0349 | 30,000 | Blind SQL Injection | WPScan |
53 | protect-wp-admin | CVE-2021-24906 | 30,000 | Disabling of plugin security features | WPScan |
54 | site-reviews | CVE-2021-24973 | 30,000 | Stored XSS | WPScan |
55 | ultimate-faqs | CVE-2021-24968 | 30,000 | Possibility to add arbitrary FAQs | WPScan |
56 | video-conferencing-with-zoom-api | CVE-2022-0384 | 30,000 | E-mail leak | WPScan |
57 | wp-user-frontend | CVE-2021-25076 | 30,000 | SQL injection in admin panel leading to reflected XSS | WPScan |
58 | ad-invalid-click-protector | CVE-2022-0190 | 20,000 | SQL injection | WPScan |
59 | asgaros-forum | CVE-2022-0411 | 20,000 | Blind SQL Injection | WPScan |
60 | crazy-bone | CVE-2022-0385 | 20,000 | Stored XSS | WPScan |
61 | event-calendar-wd | CVE-2021-25025 | 20,000 | Possibility to add arbitrary events | WPScan |
62 | float-menu | CVE-2022-0313 | 20,000 | CSRF menu deletion | WPScan |
63 | gmap-embed | CVE-2021-25011 | 20,000 | Arbitrary post removal, plugin settings update | WPScan |
64 | gmap-embed | CVE-2021-25081 | 20,000 | Arbitrary post removal, plugin settings update via CSRF | WPScan |
65 | image-hover-effects-ultimate | CVE-2021-25031 | 20,000 | Reflected XSS | WPScan |
66 | mycred | CVE-2021-25015 | 20,000 | Reflected XSS | WPScan |
67 | mystickyelements | CVE-2022-0148 | 20,000 | Reflected XSS | WPScan |
68 | navz-photo-gallery | CVE-2021-24909 | 20,000 | Reflected XSS | WPScan |
69 | newstatpress | CVE-2022-0206 | 20,000 | Reflected XSS | WPScan |
70 | page-views-count | CVE-2022-0434 | 20,000 | SQL injection | WPScan |
71 | restaurant-reservations | CVE-2021-24965 | 20,000 | Stored XSS | WPScan |
72 | woocommerce-product-addon | CVE-2021-25018 | 20,000 | Stored XSS | WPScan |
73 | wp-accessiblity-helper | CVE-2022-0150 | 20,000 | Reflected XSS | WPScan |
74 | wp-stats-manager | CVE-2021-24750 | 20,000 | SQL injection | WPScan |
75 | wp-stats-manager | CVE-2021-25042 | 20,000 | Stored XSS | WPScan |
76 | wp-stats-manager | CVE-2022-0410 | 20,000 | Blind SQL Injection | WPScan |
77 | wplegalpages | CVE-2021-25106 | 20,000 | Stored XSS | WPScan |
78 | affiliates-manager | CVE-2021-25078 | 10,000 | Stored XSS | WPScan |
79 | business-profile | CVE-2021-25060 | 10,000 | Stored XSS | WPScan |
80 | coming-soon-page | CVE-2022-0164 | 10,000 | Sending any e-mail to all subscribers | WPScan |
81 | coming-soon-page | CVE-2022-0199 | 10,000 | Sending any e-mail to all subscribers via CSRF | WPScan |
82 | duplicate-page-or-post | CVE-2021-25075 | 10,000 | Stored XSS | WPScan |
83 | easy-pricing-tables | CVE-2021-25098 | 10,000 | CSRF post removal | WPScan |
84 | ibtana-visual-editor | CVE-2021-25014 | 10,000 | Stored XSS | WPScan |
85 | ip2location-country-blocker | CVE-2021-25095 | 10,000 | Banning arbitrary countries | WPScan |
86 | ip2location-country-blocker | CVE-2021-25096 | 10,000 | Ban circumvention | WPScan |
87 | ip2location-country-blocker | CVE-2021-25108 | 10,000 | Banning countries via CSRF | WPScan |
88 | link-library | CVE-2021-25091 | 10,000 | Reflected XSS | WPScan |
89 | link-library | CVE-2021-25092 | 10,000 | CSRF settings reset | WPScan |
90 | link-library | CVE-2021-25093 | 10,000 | Arbitrary link removal | WPScan |
91 | modal-window | CVE-2021-25051 | 10,000 | CSRF RCE | WPScan |
92 | page-builder-add | CVE-2021-25067 | 10,000 | Reflected XSS | WPScan |
93 | powerpack-addon-for-beaver-builder | CVE-2022-0176 | 10,000 | Reflected XSS | WPScan |
94 | qubely | CVE-2021-25013 | 10,000 | Arbitrary post removal | WPScan |
95 | rearrange-woocommerce-products | CVE-2021-24928 | 10,000 | SQL injection | WPScan |
96 | registrations-for-the-events-calendar | CVE-2021-24943 | 10,000 | SQL injection | WPScan |
97 | registrations-for-the-events-calendar | CVE-2021-25083 | 10,000 | Reflected XSS | WPScan |
98 | secure-copy-content-protection | CVE-2021-24931 | 10,000 | SQL injection | WPScan |
99 | smart-forms | CVE-2022-0163 | 10,000 | Downloading form data | WPScan |
100 | spider-event-calendar | CVE-2022-0212 | 10,000 | Reflected XSS | WPScan |
101 | ultimate-product-catalogue | CVE-2021-24993 | 10,000 | Possibility to add arbitrary products | WPScan |
102 | whmcs-bridge | CVE-2021-25112 | 10,000 | Reflected XSS | WPScan |
103 | wicked-folders | CVE-2021-24919 | 10,000 | SQL injection | WPScan |
104 | woo-orders-tracking | CVE-2021-25062 | 10,000 | Reflected XSS | WPScan |
105 | woocommerce-exporter | CVE-2022-0149 | 10,000 | Reflected XSS | WPScan |
106 | woocommerce-store-toolkit | CVE-2021-25077 | 10,000 | Reflected XSS | WPScan |
107 | wp-booking-system | CVE-2021-25061 | 10,000 | Reflected XSS | WPScan |
108 | wp-coder | CVE-2021-25053 | 10,000 | CSRF RCE | WPScan |
109 | wp-photo-album-plus | CVE-2021-25115 | 10,000 | Stored XSS | WPScan |
110 | wp125 | CVE-2021-25073 | 10,000 | CSRF ad deletion | WPScan |
111 | events-made-easy | CVE-2021-25030 | 7,000 | SQL injection | WPScan |
112 | likebtn-like-button | CVE-2021-24945 | 7,000 | Sensitive data exposure | WPScan |
113 | responsive-vector-maps | CVE-2021-24947 | 6,000 | Arbitrary file read | WPScan |
114 | button-generation | CVE-2021-25052 | 5,000 | CSRF RCE | WPScan |
并非所有漏洞都是由模糊器直接发现的。例如,在为 CVE- 2021-25095 编写 PoC 时意外发现了CVE-2021-25096。对于其他一些漏洞,工具警报只是漏洞信息的一部分——例如,该工具通知任何用户都可以更新 WordPress 选项——并发现后果(是否会导致例如存储的 XSS)需要手动工作.
值得一提的发现
我不会取笑任何特定的插件作者,但是,我认为一些发现值得分享。
is_admin
WordPressis_admin()
功能,您可能已经猜到了:
确定当前请求是否针对管理界面页面。
(来自https://developer.wordpress.org/reference/functions/is_admin/)
该文档还警告说,它:
不检查用户是否为管理员;用于
current_user_can()
检查角色和能力。
正如您可能已经猜到的那样,它是以下形式的几个漏洞的来源:
if (is_admin()) {
/* dangerous action */
}
REST 路由 URL
让我们考虑以下代码:
register_rest_route((...), '/(...)/(?P<id>[\d]+)', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'callback'),
'permission_callback' => '__return_true',
),
));
/* ... */
function callback($request) {
$id = $request['id'];
}
哪些 ID 值可以传递给处理程序?
正确答案是:所有这些 – 只需使用/?rest_route=/(...)/1&id=hehehe
.
获取用户()

一些插件允许通过提供电子邮件地址的一部分来搜索用户。这允许使用以下步骤泄漏任何用户的电子邮件:
- 对域名的第一个字母进行暴力破解(搜索
@a
、@b
等,并检查用户名何时出现在搜索结果中)。 - 记住第一个字母并用它来猜测第二个字母。假设用户的电子邮件域名以
g
. 然后,您可以暴力破解第二个字母 (@ga
,@gb
, …)。 - 对其余的电子邮件地址重复上述步骤。
正因为如此,我添加了一个检查,当get_users()
被调用时会发出警报。不幸的是,除了发现这种类型的漏洞外,它还导致了许多误报。
跨站脚本保护
请勿执行以下操作:
if (/* potential XSS in $parameter detected */) die('Invalid parameter: ' . $parameter);
一些 XSS 漏洞也是由调试助手引起的,形式如下:
echo "<!--";
var_dump($_POST);
echo "-->";
验证码验证
不要这样做:
if (isset($_POST['captcha'])) {
/* verify captcha */
}
/* do action that should be CAPTCHA-protected */
我已经多次观察到这种模式,无论是验证码还是随机数。
结论
这只是一个概念验证(POC),用于检查自动技术是否是查找 WordPress 插件错误的可行方法。我相信它可以通过例如改进:
- 添加检查以检测其他类型的危险操作,
- 试图减少误报的数量,而不会大量损失真阳性。误报率是该项目的主要障碍之一。
这种技术也可以用于其他插件生态系统。
我发现的许多漏洞很容易通过现代软件工程实践来预防。在许多 WordPress 插件中,HTML 是使用容易出错的echo
语句而不是模板语言构建的。同样,默认情况下,AJAX 端点对所有登录用户或所有未登录用户都可用,而不是要求开发人员提供固定的角色或权限许可列表(以便他们必须明确地将路由标记为可用于所有登录用户)。不幸的是,引入使出错更难的技术并促进其使用是只有 WordPress 团队而不是插件开发人员才能做到的事情。
脚注
- 回想起来,使用一堆正则表达式来检测输出中的崩溃并不是最好的主意。现在我会尝试以不同的方式做到这一点。 ↩
- 回想起来,很明显它并没有涵盖加载 XML 的所有方式。这应该以不同的方式完成。 ↩
- 这种类型的反射型 XSS 要求 cookie 与 POST 请求一起发送,因此由于 SameSite-by-default 行为将更难被利用
转载请注明出处及链接