Coupon Creation Vulnerability Patched In WooCommerce Smart Coupons

Description: Unauthenticated Coupon Creation
Affected Plugin: WooCommerce Smart Coupons
Affected Plugin Slug: woocommerce-smart-coupons
Affected Versions: <= 4.6.0
CVSS Score: 5.3 (Medium)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Patched Version: 4.6.5

Late last month a patch was released for WooCommerce Smart Coupons, a commercial WooCommerce plugin that helps store managers handle coupons and gift certificates. In vulnerable versions of the plugin, unauthenticated attackers could send themselves gift certificates of any value, which could be redeemed for products sold on the victim’s storefront.

This vulnerability was originally identified by Aaron Averbuch and his team at Bloomscape, who privately contacted us after disclosing the issue to the plugin’s developers. A patch was released the following day in WooCommerce Smart Coupons version 4.6.5. To protect our users, we released a firewall rule to block attempts to exploit this flaw. Wordfence Premium users already have access to this rule, and sites still on the free version will receive the rule March 25, 2020, thirty days after it was released.

We urge all WooCommerce Smart Coupons users to update to the latest available version as soon as possible to mitigate the risk of fraudulent gift certificates. Typical WordPress users update commercial plugins less reliably than those in the WordPress repository, and that trend continues with this plugin. At the time of this writing, nearly nine out of ten sites using WooCommerce Smart Coupons are still running a vulnerable version of the plugin.

In today’s post, we examine the vulnerability and discuss how to identify if your site has been affected.

Vulnerability In Detail

One of the features of WooCommerce Smart Coupons allows store managers to create gift certificates which can be emailed to customers. The interface for this feature is only available to user roles with the manage_woocommerce capability, which is available by default on the administrator and shop_manager roles.

Screenshot of the Send Store Credit interface

Screenshot of the Send Store Credit interface.

This functionality was made vulnerable by the way WooCommerce Smart Coupons handled inputs from that form. While the dashboard page for this feature was restricted to privileged users, the plugin was listening for submissions on every page in wp-admin.

add_action( 'admin_init', array( $this, 'woocommerce_coupon_admin_init' ) );
public function woocommerce_coupon_admin_init() {

	$get_import = ( isset( $_GET['import'] ) ) ? wc_clean( wp_unslash( $_GET['import'] ) ) : ''; // phpcs:ignore
	$get_page   = ( isset( $_GET['page'] ) ) ? wc_clean( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore
	$get_action = ( isset( $_GET['action'] ) ) ? wc_clean( wp_unslash( $_GET['action'] ) ) : ''; // phpcs:ignore

	$post_smart_coupon_email   = ( isset( $_POST['smart_coupon_email'] ) ) ? wc_clean( wp_unslash( $_POST['smart_coupon_email'] ) ) : ''; // phpcs:ignore
	$post_smart_coupon_amount  = ( isset( $_POST['smart_coupon_amount'] ) ) ? wc_clean( wp_unslash( $_POST['smart_coupon_amount'] ) ) : 0; // phpcs:ignore
	$post_smart_coupon_message = ( isset( $_POST['smart_coupon_message'] ) ) ? wp_kses_post( wp_unslash( $_POST['smart_coupon_message'] ) ) : ''; // phpcs:ignore

	if ( 'wc-sc-coupons' === $get_import || 'wc-smart-coupons' === $get_page ) {
		ob_start();
	}

	if ( defined( 'WP_LOAD_IMPORTERS' ) ) {
		register_importer( 'wc-sc-coupons', __( 'WooCommerce Coupons (CSV)', 'woocommerce-smart-coupons' ), __( 'Import <strong>coupons</strong> to your store via a csv file.', 'woocommerce-smart-coupons' ), array( $this, 'coupon_importer' ) );
	}

	if ( 'sent_gift_certificate' === $get_action && 'wc-smart-coupons' === $get_page ) {
		$email   = $post_smart_coupon_email;
		$amount  = $post_smart_coupon_amount;
		$message = $post_smart_coupon_message;
		$this->send_gift_certificate( $email, $amount, $message );
	}
}

The snippets above, taken from class-wc-sc-admin-pages.php, show how this input is handled. The plugin registers the woocommerce_coupon_admin_init() function to WordPress’s admin_init hook. This function performs checks to determine whether to start output buffering or register a CSV importer, but then checks if it should send a gift certificate.

It makes this decision based on two $_GET parameters: action=sent_gift_certificate and page=wc-smart-coupons. These parameters are common in the WordPress dashboard, but accessing them directly is insecure in this case. There’s no validation that a user has access to the wc-smart-coupons page.

As we’ve reported in several cases recently, such as the vulnerabilities in Email Subscribers & Newsletters and last week’s zero-day campaign, the admin_init hook is accessible to any of a site’s visitors. Unauthenticated users can send requests to /wp-admin/admin-post.php, which will satisfy requirements for is_admin() as well as firing every function hooked to admin_init.  This, of course, includes woocommerce_coupon_admin_init().

By crafting a request with all of the necessary parameters, attackers could generate and send themselves valid gift certificates for a victim’s WooCommerce store. This vulnerability has been patched as of WooCommerce Smart Coupons 4.6.5.

Remediation Can Be Tricky

Internally, these gift certificates are considered coupons, just like a typical percentage-off coupon you’d distribute for a promotion. They behave differently, with a value that can be spent instead of a reusable discount, but are treated the same within the WooCommerce interface.

Screenshot of a list of generated coupons.

Screenshot of a list of generated coupons.

Unfortunately, this means it’s not possible for the WooCommerce Smart Coupons to invalidate any fraudulent store credit that was created through this vulnerability. If a vulnerable site was exploited and store credit generated, it would still be valid and redeemable after the site owner updated the plugin. Each coupon would need to be deleted by an administrator or shop manager to prevent their use.

For stores that don’t make use of these gift certificates, remediation is as simple as deleting every coupon with the type Store Credit / Gift Certificate. However, for sites that send store credit frequently, it might not be immediately clear which coupons are legitimate and which were created fraudulently.

If you believe store credit was created by a malicious user, there are two ways you can help identify which coupons are fraudulent.

Comparing Coupon Creation Times With Access Logs

This method requires access to your site’s access logs. If you do not know how to access these, contact your hosting provider for assistance.

While this vulnerability allows coupons to be generated on unauthenticated /wp-admin endpoints, legitimate usage only sends requests to one location: /wp-admin/admin.php. This endpoint is inaccessible to unauthenticated users, so any coupons generated by a request to that file are legitimate.

On the other hand, coupons generated by requests to other locations, like /wp-admin/admin-post.php or /wp-admin/admin-ajax.php, are probably fraudulent.

For example, the following string in an access log would suggest an attempt to exploit this vulnerability:

"POST /wp-admin/admin-post.php?page=wc-smart-coupons&action=sent_gift_certificate HTTP/1.1"

The next one is a legitimate entry:

"POST /wp-admin/admin.php?page=wc-smart-coupons&action=sent_gift_certificate HTTP/1.1"

By comparing the timestamps of these log entries to the publish times of suspicious coupons, you can determine which to keep and which to delete.

Checking WordPress Post Metadata For Suspicious Emails

This method requires access to your site’s database. If you do not know how to access this, contact your hosting provider for assistance.

While the WooCommerce Smart Coupons interface doesn’t immediately reveal where each coupon was sent, this data is still stored in the WordPress database.

Search your site’s wp_postmeta table for suspicious customer_email entries with a query like the following. (Note: Your site’s database prefix may be different, but we’ll use the default wp_ in our examples.)

mysql> select * from wp_postmeta where meta_key = 'customer_email';
+---------+---------+----------------+--------------------------------------------+
| meta_id | post_id | meta_key       | meta_value                                 |
+---------+---------+----------------+--------------------------------------------+
|     168 |      54 | customer_email | a:1:{i:0;s:24:"shopshopshop@example.com";} |
|     188 |      55 | customer_email | a:1:{i:0;s:23:"hacker@evil.example.com";}  |
|     266 |      57 | customer_email | a:1:{i:0;s:22:"shopperman@example.com";}   |
|     285 |      59 | customer_email | a:1:{i:0;s:21:"luvs2shop@example.com";}    |
+---------+---------+----------------+--------------------------------------------+
4 rows in set (0.00 sec)

In the example set above, we see four coupons with different customer_email values. One particular email stands out: hacker@evil.example.com. The post_id for this coupon is 55, so let’s see which coupon code that corresponds to:

mysql> select post_title from wp_posts where ID = 55;
+---------------+
| post_title    |
+---------------+
| qvi93te4veedu |
+---------------+
1 row in set (0.00 sec)

Now we see the offending coupon code: qvi93te4veedu. With this we can delete the coupon, or investigate further to identify any orders that store credit may have been used on.

Not all malicious users have easily identifiable email addresses, but you can also compare these emails to other resources such as your mailing list and previous orders to identify suspicious outliers.

Timeline

  • February 20, 2020 – Vulnerability disclosed by Aaron Averbuch and his team at Bloomscape.
  • February 21, 2020 – WooCommerce Smart Coupons version 4.6.5 released to patch vulnerability.
  • February 24, 2020 – Firewall rule released to prevent exploitation against sites with Wordfence Premium.
  • March 25, 2020 – Firewall rule available to Wordfence free users.

Conclusion

Vulnerabilities such as this one, where features are intended for privileged users but are inadvertently left open to attack, are unfortunately common. If you are developing WordPress plugins and themes, be sure to validate user capabilities directly for any privileged activity. Hooking code into admin_init, or attempting to secure functionality with is_admin() checks, is dangerous and ineffective without performing these capabilities checks. For more information on how to check user capabilities, visit the WordPress.org codex entry for current_user_can().

At this time, we have not detected any malicious activity targeting WooCommerce Smart Coupons. With that said, it’s very important to update to the latest version of the plugin as soon as possible.

Wordfence Premium users are already protected from possible attacks. Sites on the free version will receive the rule on the date specified in the timeline above.

We will monitor our network for any changes in activity around this vulnerability, and will provide details as they emerge.

Thanks again to Aaron Averbuch and his team at Bloomscape for their discovery and disclosure of this issue. Additional thanks to QA Lead Matt Rusnak for his assistance in vulnerability analysis.

 

Did you enjoy this post? Share it!

Comments

No Comments