一种半自动发现WordPress插件漏洞的技术

一种半自动发现WordPress插件漏洞的技术

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(回显包含“或<的已知有效载荷),
    • 等等。

这种方法可以转移到其他 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插件安装数量漏洞类型链接
1updraftplusCVE-2021-250223,000,000Reflected XSSWPScan
2code-snippetsCVE-2021-25008500,000Reflected XSSWPScan
3woocommerce-pdf-invoices-packing-slipsCVE-2021-24991300,000Reflected XSSWPScan
4ad-inserterCVE-2022-0288200,000Reflected XSSWPScan
5complianz-gdprCVE-2022-0193200,000Reflected XSSWPScan
6custom-facebook-feedCVE-2021-25065200,000Reflected XSSWPScan
7loginpressCVE-2022-0347200,000Reflected XSSWPScan
8use-any-fontCVE-2021-24977200,000Arbitrary CSS append + stored XSSWPScan
9white-label-cmsCVE-2022-0422200,000Reflected XSSWPScan
10wp-cerberCVE-2022-0429200,000Stored XSSWPScan
11capability-manager-enhancedCVE-2021-25032100,000Arbitrary settings updateWPScan
12chatyCVE-2021-25016100,000Reflected XSSWPScan
13cmp-coming-soon-maintenanceCVE-2022-0188100,000Possibility to add arbitrary CSSWPScan
14download-managerCVE-2021-24969100,000Stored XSSWPScan
15download-managerCVE-2021-25069100,000Reflected XSSWPScan
16email-subscribersCVE-2022-0439100,000Blind SQL InjectionWPScan
17modern-events-calendar-liteCVE-2021-24925100,000Reflected XSSWPScan
18modern-events-calendar-liteCVE-2021-24946100,000Blind SQL injectionWPScan
19modern-events-calendar-liteCVE-2021-25046100,000Stored XSSWPScan
20paid-memberships-proCVE-2021-25114100,000Blind SQL InjectionWPScan
21ti-woocommerce-wishlistCVE-2022-0412100,000Blind SQL InjectionWPScan
22webp-converter-for-mediaCVE-2021-25074100,000Open redirectWPScan
23woocommerce-products-filterCVE-2021-25085100,000Reflected XSSWPScan
24wpvivid-backuprestoreCVE-2021-24994100,000Stored XSSWPScan
25social-networks-auto-poster-facebook-twitter-gCVE-2021-2497590,000Stored XSSWPScan
26social-networks-auto-poster-facebook-twitter-gCVE-2021-2507290,000CSRF post removalWPScan
27themify-portfolio-postCVE-2022-020080,000Reflected XSS (logged-in POST 3)WPScan
28woo-product-feed-proCVE-2021-2497480,000Stored XSSWPScan
29woo-product-feed-proCVE-2022-042680,000Reflected XSS (logged-in POST 3)WPScan
30bookingCVE-2021-2504060,000Reflected XSSWPScan
31mappress-google-maps-for-wordpressCVE-2022-020860,000Reflected XSSWPScan
32permalink-managerCVE-2022-020160,000Reflected XSSWPScan
33powerpack-lite-for-elementorCVE-2021-2502760,000Reflected XSSWPScan
34real-cookie-bannerCVE-2022-044560,000CSRF settings reset and deleting all GDPR consentsWPScan
35wd-instagram-feedCVE-2021-2504760,000Reflected XSSWPScan
36woocommerce-currency-switcherCVE-2021-2504360,000Reflected XSSWPScan
37woocommerce-currency-switcherCVE-2022-023460,000Reflected XSSWPScan
38wp-responsive-menuCVE-2021-2497160,000Stored XSSWPScan
39wp-rss-aggregatorCVE-2021-2498860,000Stored XSSWPScan
40wp-rss-aggregatorCVE-2022-018960,000Reflected XSS (logged-in POST 3)WPScan
41ditty-news-tickerCVE-2022-053350,000Reflected XSSWPScan
42event-ticketsCVE-2021-2502850,000Open redirectWPScan
43simple-membershipCVE-2022-032850,000CSRF member deletionWPScan
44bnfwCVE-2022-034540,000E-mail leakWPScan
45tutorCVE-2021-2501740,000Reflected XSSWPScan
46advanced-cron-managerCVE-2021-2508430,000Arbitrary cron configuration changeWPScan
47contact-form-7-skinsCVE-2021-2506330,000Reflected XSSWPScan
48easy-paypal-donationCVE-2021-2498930,000CSRF post removalWPScan
49futurio-extraCVE-2021-2511030,000E-mail leakWPScan
50lead-form-builderCVE-2021-2496730,000Stored XSSWPScan
51my-calendarCVE-2021-2492730,000Reflected XSSWPScan
52notificationxCVE-2022-034930,000Blind SQL InjectionWPScan
53protect-wp-adminCVE-2021-2490630,000Disabling of plugin security featuresWPScan
54site-reviewsCVE-2021-2497330,000Stored XSSWPScan
55ultimate-faqsCVE-2021-2496830,000Possibility to add arbitrary FAQsWPScan
56video-conferencing-with-zoom-apiCVE-2022-038430,000E-mail leakWPScan
57wp-user-frontendCVE-2021-2507630,000SQL injection in admin panel leading to reflected XSSWPScan
58ad-invalid-click-protectorCVE-2022-019020,000SQL injectionWPScan
59asgaros-forumCVE-2022-041120,000Blind SQL InjectionWPScan
60crazy-boneCVE-2022-038520,000Stored XSSWPScan
61event-calendar-wdCVE-2021-2502520,000Possibility to add arbitrary eventsWPScan
62float-menuCVE-2022-031320,000CSRF menu deletionWPScan
63gmap-embedCVE-2021-2501120,000Arbitrary post removal, plugin settings updateWPScan
64gmap-embedCVE-2021-2508120,000Arbitrary post removal, plugin settings update via CSRFWPScan
65image-hover-effects-ultimateCVE-2021-2503120,000Reflected XSSWPScan
66mycredCVE-2021-2501520,000Reflected XSSWPScan
67mystickyelementsCVE-2022-014820,000Reflected XSSWPScan
68navz-photo-galleryCVE-2021-2490920,000Reflected XSSWPScan
69newstatpressCVE-2022-020620,000Reflected XSSWPScan
70page-views-countCVE-2022-043420,000SQL injectionWPScan
71restaurant-reservationsCVE-2021-2496520,000Stored XSSWPScan
72woocommerce-product-addonCVE-2021-2501820,000Stored XSSWPScan
73wp-accessiblity-helperCVE-2022-015020,000Reflected XSSWPScan
74wp-stats-managerCVE-2021-2475020,000SQL injectionWPScan
75wp-stats-managerCVE-2021-2504220,000Stored XSSWPScan
76wp-stats-managerCVE-2022-041020,000Blind SQL InjectionWPScan
77wplegalpagesCVE-2021-2510620,000Stored XSSWPScan
78affiliates-managerCVE-2021-2507810,000Stored XSSWPScan
79business-profileCVE-2021-2506010,000Stored XSSWPScan
80coming-soon-pageCVE-2022-016410,000Sending any e-mail to all subscribersWPScan
81coming-soon-pageCVE-2022-019910,000Sending any e-mail to all subscribers via CSRFWPScan
82duplicate-page-or-postCVE-2021-2507510,000Stored XSSWPScan
83easy-pricing-tablesCVE-2021-2509810,000CSRF post removalWPScan
84ibtana-visual-editorCVE-2021-2501410,000Stored XSSWPScan
85ip2location-country-blockerCVE-2021-2509510,000Banning arbitrary countriesWPScan
86ip2location-country-blockerCVE-2021-2509610,000Ban circumventionWPScan
87ip2location-country-blockerCVE-2021-2510810,000Banning countries via CSRFWPScan
88link-libraryCVE-2021-2509110,000Reflected XSSWPScan
89link-libraryCVE-2021-2509210,000CSRF settings resetWPScan
90link-libraryCVE-2021-2509310,000Arbitrary link removalWPScan
91modal-windowCVE-2021-2505110,000CSRF RCEWPScan
92page-builder-addCVE-2021-2506710,000Reflected XSSWPScan
93powerpack-addon-for-beaver-builderCVE-2022-017610,000Reflected XSSWPScan
94qubelyCVE-2021-2501310,000Arbitrary post removalWPScan
95rearrange-woocommerce-productsCVE-2021-2492810,000SQL injectionWPScan
96registrations-for-the-events-calendarCVE-2021-2494310,000SQL injectionWPScan
97registrations-for-the-events-calendarCVE-2021-2508310,000Reflected XSSWPScan
98secure-copy-content-protectionCVE-2021-2493110,000SQL injectionWPScan
99smart-formsCVE-2022-016310,000Downloading form dataWPScan
100spider-event-calendarCVE-2022-021210,000Reflected XSSWPScan
101ultimate-product-catalogueCVE-2021-2499310,000Possibility to add arbitrary productsWPScan
102whmcs-bridgeCVE-2021-2511210,000Reflected XSSWPScan
103wicked-foldersCVE-2021-2491910,000SQL injectionWPScan
104woo-orders-trackingCVE-2021-2506210,000Reflected XSSWPScan
105woocommerce-exporterCVE-2022-014910,000Reflected XSSWPScan
106woocommerce-store-toolkitCVE-2021-2507710,000Reflected XSSWPScan
107wp-booking-systemCVE-2021-2506110,000Reflected XSSWPScan
108wp-coderCVE-2021-2505310,000CSRF RCEWPScan
109wp-photo-album-plusCVE-2021-2511510,000Stored XSSWPScan
110wp125CVE-2021-2507310,000CSRF ad deletionWPScan
111events-made-easyCVE-2021-250307,000SQL injectionWPScan
112likebtn-like-buttonCVE-2021-249457,000Sensitive data exposureWPScan
113responsive-vector-mapsCVE-2021-249476,000Arbitrary file readWPScan
114button-generationCVE-2021-250525,000CSRF RCEWPScan

并非所有漏洞都是由模糊器直接发现的。例如,在为 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.

获取用户()

一种半自动发现WordPress插件漏洞的技术

一些插件允许通过提供电子邮件地址的一部分来搜索用户。这允许使用以下步骤泄漏任何用户的电子邮件:

  • 对域名的第一个字母进行暴力破解(搜索@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 团队而不是插件开发人员才能做到的事情。

脚注

  1. 回想起来,使用一堆正则表达式来检测输出中的崩溃并不是最好的主意。现在我会尝试以不同的方式做到这一点。 
  2. 回想起来,很明显它并没有涵盖加载 XML 的所有方式。这应该以不同的方式完成。 
  3. 这种类型的反射型 XSS 要求 cookie 与 POST 请求一起发送,因此由于 SameSite-by-default 行为将更难被利用

from

转载请注明出处及链接

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用 * 标注