The Code Behind Magecart Skimming Scripts

When a website is compromised to steal credit card information, a link to a malicious JavaScript file is normally inserted into the website’s code. This file then loads what is called the skimmer, the code responsible for skimming personal and financial details from customers. The code behind Magecart-style attacks can be very simple, only 22 lines were required to breach credit card details from 380,000 British Airway customers:

RapidSpike - The code behind Magecart attack on British Airways.
The infamous code added to the BA website.

Although the files are executed as JavaScript by the browser, files can be dynamically generated server-side to help manipulate the content to avoid detection.

During R&D for our Magecart Attack Detection system, our tests alerted us to some suspicious activity on an e-commerce site that had been in the news for a previous attack. Very briefly, instead of JavaScript code loading in the file, there was a misconfiguration on the malicious server used to host the skimmer, and the raw server-side script used to generate the JavaScript skimmer was exposed. As it was on a Magento platform it was PHP code that was displayed. We were able to take a copy before the hacking group successfully updated the server moments later.

Below are some snippets of code that have been used in high-profile attacks.

Booby Traps

The following block of code is aimed at security researches or anyone trying to directly load the file. The criminals do not want anyone inspecting the skimmer or looking at the skimming code, so will permanently block access to the contents if the script has not been loaded by the compromised website:

if(isset($_SERVER['HTTP_REFERER'])){
    $host = parse_url($_SERVER['HTTP_REFERER']);
    if(md5(simple_ltrim($host['host'], 'www.'))==$host_check){
        echo $js;
    }else{
        file_put_contents($ban_dir.$ip, $_SERVER['HTTP_REFERER']);
        echo 'jQuery.noConflict()';
    }
}else{
    file_put_contents($ban_dir.$ip, $_SERVER['HTTP_REFERER']);
    echo 'jQuery.noConflict()';
}

Files loaded by a website have a referer header. Here’s a JavaScript file for Google Tag Manager loading on the Harrods website:

RapidSpike - JavaScript file for Google Tag Manager

If the file is loaded directly in the browser rather than by the website, there will not be a referer header. Using $_SERVER['HTTP_REFERER'] will return the referer in the server-side script. If it is not set or it is different from the website the hacker intended to infect, the IP address of the viewer is saved to a ban list and the content of the file is simply jQuery.noConflict(), making it look like an innocent file. After an IP is on the ban list, there is no way to load the file, even if it has the correct referer header, due to this bit of code:

if(file_exists($ban_dir.$ip)){
    echo 'jQuery.noConflict()';
    exit;
}

Now when the file is loaded we see this innocent script:

RapidSpike - File loaded script.
Looks innocent enough…

Although not present in the code we intercepted, there are several other tricks a hacker could use to avoid detection, all straightforward to do server-side:

  • Geolocate – based on the IP, the location of the customer could be determined and the skimmer could only load based on country. For example, only serve the skimming code to people in France. Any security researcher or tool running outside of France would not see any malicious code unless they used a VPN. Testing every script on a website from every country would not be feasible!
  • Browser – I doubt many people in the security sector use Internet Explorer, so targeting just people on IE could help stay unnoticed.
  • Device Type – on a desktop or laptop it’s very easy to use built-in browser tools to inspect network traffic, view file source, etc. It’s a lot more difficult to do the same on a mobile device. You would have to use special software to proxy data to view what’s loaded. So only displaying the skimmer on mobile devices would make it much harder to see the skimmer.
  • Operating System – similar to browser detection, there was one incident that was said to hide the skimming code to anyone on a Linux-based machine, as they would be more likely to be someone in the technology or security industry.

Backdoors

As well as booby traps to keep people out, we also spotted backdoors to let people in and easily view captured data. This is simply activated by a series of query strings added to the URL of the skimmer. For example, loading the file using https://example.com/skimmer.js?banned_ips=1 would trigger the following and list all the banned IPs collected in the booby trap above:

if(isset($_GET['banned_ips'])){
     $dirs = scandir($ban_dir);
     foreach($dirs as $dir){
         if(!in_array($dir, ['.', '..', 'index.html'])){
             $banlist[$dir] = file_get_contents($ban_dir.$dir);
         }
     }
     echo json_encode($banlist);
     exit;
 }

Several backdoors were exposing more sensitive information, but all used query strings or POST variables. I won’t detail those here, you’ll have to use your imagination instead! This further demonstrates that not all hacks need direct access to a malicious or compromised server and sensitive data such as stolen credit cards, administration passwords, etc. can easily be retrieved or shared.

Worried about being attacked? Detect web-skimming, formjacking and supply chain attacks. Easily protect against unauthorised changes to your critical JavaScript files with RapidSpike Client-Side Security: Attack Detection.