5 years ago, I published a blog post covering one of the most widespread and potentially damaging Cryptojacking attacks seen on the Web. Despite the extensive coverage in global media at the time, and the realisation of just how bad things could have been, it seems we really didn't learn our lesson.

The Government Cryptojacking Attack

Back in 2018, a friend of mine alerted me to a warning he got when visiting a Government website here in the UK. His Anti-Virus program was telling him that a Cryptocurrency miner was running on the page, and with just a few seconds of investigation, I was able to confirm that was indeed the case. Cryptojacking is the process of criminals using the hardware of others to mine Cryptocurrency for them, and immediately I knew this was a Cryptojacking attack. You can indeed mine Cryptocurrency using JavaScript and if you can get your malicious JavaScript onto a website, all visitors to that website will mine Cryptocurrency for you! It's the perfect Cryptojacking attack with no overheads, you just place your JavaScript on the site, sit back, and watch the money roll in.

You can read the full blog post I published back in 2018 that goes into all of the details much more than I will here. In this blog post, I want to focus on what we took away from that attack and what changes we've seen in the industry since.

The JavaScript Supply Chain

The attack was so widespread and impacted so many government websites because it was a 3rd-party compromise in a JavaScript dependency, not a vulnerability in each of the 5,000+ sites affected. All of the sites had one thing in common, the following script tag:

<script src="//www.browsealoud.com/plus/scripts/ba.js" type="text/javascript"></script>

It looks simple enough, and it's the same kind of script tag you can see countless times on almost any page if you view the source. We all load assets from 3rd-party locations but JavaScript is particularly dangerous, and it was the file referenced in the src attribute above that was modified by the attackers. Once that file is modified, let's say, to include a Cryptocurrency Miner, the browsers of all visitors who visit any page with that script tag will dutifully download the JavaScript file and begin mining Cryptocurrency to send to the attackers, simply because the browser doesn't know any better! It's a valid script tag, the browser sent a request, it got some JavaScript back, so run it!

This approach is so unbelievably dangerous, but,  most of the time it works out just fine and we get the JavaScript we wanted. The problem is though, when that file is modified, you're going to get the JavaScript that the attackers give you. The best way to think of this script tag is as a "blank cheque" for JavaScript:

You would never go around handing out blank cheques to anyone because, frankly, it's a terrible idea! Yet, for some reason, we don't seem to have the same level of concern when writing out blank cheques for JavaScript...

We Got Lucky

Not only did we get lucky, we got lucky in more ways than one.

Ian, who got the Antivirus warning, found the attack ~3 hours after it had started! Talk about a rapid detection, but, it could have been there for months prior. Not only that, but had he not got the warning, or had the attackers taken any basic precautions to avoid detection, the attack could have lurked for days, weeks or even months longer too. Here's the script file archived at Sun, 11 Feb 2018 05:22:27 and it's clean, then the next archive was Sun, 11 Feb 2018 11:26:33 and the file has been infected.

The first person that Ian tipped off about this was me. He knew to raise it with someone that works in the area of web security and I was able to quickly identify the source of the attack. Given the nature of the attack and that it needed to be stopped quickly, I went public and started reaching out to all of the appropriate organisations to try and get a rapid response, which started less than 48 hours later after the NCSC here in the UK reached out to me.

The luckiest thing about this, though, was that the attackers seemed to lack any imagination at all. Just pause for a second and think about your answer to the following question:

If I gave you the ability to inject any, arbitrary JavaScript that you wanted into 5,000+ sites, including hundreds of Government sites, what would you do?

Honestly, I can't believe that all the attackers decided to do was mine some Monero, but I also think that's part of the problem with regards to the lack of response. Had this been some cataclysmic event, and the attackers had done any one of a thousand things that would be highly visual and damaging, there would have been much more impact. I discussed the possibilities widely in the press at the time, and the striking thing was that you could do almost anything you can think of, as long as you can copy/paste the code from Stack Overflow!!

In an interview I did for a BBC TV show here in the UK, there were several demonstrations of things you could do with hostile JavaScript. I used Fiddler to intercept and replace the JavaScript payload from the 3rd-party, giving me the same access the attackers had, but most of the things I showed simply couldn't be put on TV. Imagine official government sites loading full-screen pornography, a 'Breaking News' banner that claimed the Prime Minister had been assassinated or any other terrible thing that you could do with really significant impact. In the end, we showed a keylogger that would scrape data right out of the page, and given the kind of sites the keylogger would have been on, that was still a really damaging prospect, but I don't feel this adequately conveyed what could have been done and how bad this could have been.

Original BBC Episode link

This Is A Solved Problem

As I discussed back in my original blog post covering this incident, we already have a pair of technologies that were designed to help with exactly these kinds of attacks. Both Subresource Integrity, which I first covered in 2015, and Content Security Policy, which I first covered in 2014, could have stopped this attack, but neither were in use.

You can read my blog posts on both of those security mechanisms for great detail, but I can summarise them quite easily here for you.

SRI is an integrity attribute added to a JavaScript tag so that the browser knows if the JavaScript has been tampered with when it downloads it. It looks like this:

<script src="//www.browsealoud.com/plus/scripts/ba.js" integrity="sha256-Abhisa/nS9WMne/YX+dqiFINl+JiE15MCWvASJvVtIk=" crossorigin="anonymous"></script>

By adding that integrity attribute, the browser would download the modified/infected file and the integrity check would fail because the hash of the JavaScript won't match the hash specified in the integrity attribute.

CSP is a mechanism that allows you to control where the page can load content from, content like JavaScript, and control where the page can send data to, like the rewards from Cryptojacking! You would define a CSP like this as a HTTP response header:

CSP: script-src 'self' browsealoud.com; connect-src 'self' browsealoud.com

That CSP would restrict JavaScript to being loaded from your own site or browselaoud.com and apply the same restriction for outbound connections from the page, only to yourself and browsealoud.com. This CSP would do either or both of 1) stopping the coinhive.com JS from loading and 2) stopping the stolen Cryptocurrency from being sent to the attackers.

Where Are We Today?

Whilst the use of SRI and CSP both continue to grow, it's not growing anywhere near fast enough for my liking! It's true that there are some considerations when using SRI and/or CSP, but it doesn't require a lot of effort to get the basics in place, and the basics can offer you a whole heap of protection. Since Cryptojacking reached its peak in 2018, and has since fallen from the top spot, attackers have now switched to using keyloggers and dataloggers in the page instead, just like I showed in that BBC TV episode above. The most common thing attackers are targeting right now is payment pages so they can steal Payment Card Data. Known as 'Magecart', these attacks all rely on the exact same problem; attackers found a way to get JavaScript into your page, and compromising your 3rd-party dependencies still remains the most common way to do that! Once the JavaScript is in the page, it can read and skim a copy of full card details including PAN, expiry, CVV, address, etc...

There have of course been various studies into this, many companies (including my own) now offer features and products to help you with this problem, but it was a particular whitepaper that was brought to my attention by another friend of mine and really spurred the creation of this blog post.

The paper, The More Things Change, the More They Stay the Same: Integrity of Modern JavaScript, looks at the ways in which a given piece of JavaScript changes over time and one of the mechanisms to detect such changes, Subresource Integrity. In the aftermath of the Government Cryptojacking attack, one thing that was really obvious was that SRI would have prevented the attack from ever happening and it's great to see that many of the Government sites are now using SRI, but sadly, they're not doing it right... To explain the problem, I'll just quote from the paper directly, highlight mine:

We found that both domains include a ba.js script in the HTML of some pages that (1) first asks the URL browsealoud.com/.../sri.json for the SRI digest of a particular version of the browsealoud.js script, before (2) programmatically injecting the  element with the digest. This is an incorrect usage of SRI that does not provide any security guarantee, even if the initial ba.js script were to be requested using SRI (it did not use SRI), because a compromised provider would be able to change the script content and the digest accordingly.

So the original ba.js file that was infected a few years back is now simply acting as a bootstrap to pull in the required dependencies from the 3rd-party and it's getting the integrity attributes from... the 3rd-party... All the attacker has to do is infect the ba.js file just like they did before and, while they're there, update the sri.json file to change the hash, assuming of course that the hash isn't generated dynamically...

You can see this approach in the file (https://www.browsealoud.com/plus/scripts/ba.js) and looking through the archives, it seems that the vendor changed to this method in mid-2020. One original point of resistance from the vendor during the initial response to the attack was against offering versioned paths, which are required for SRI to work because the file has to be static to be integrity checked, it can't be dynamic. Having a versioned path meant the vendor would have to do feature deprecations and support older version, rather than the existing approach which was effectively "latest.js" and the library just 'updates' any time when the vendor changes the file and they have no legacy support considerations. My guess would be that this approach gets them to a point where they can dynamically update the library on all of their customer sites without the customer having to update the version in the path for the JS file. The problem is, that was exactly the problem in the first place! Think about it: If the vendor can patch the JS you're loading into your site, then so can an attacker! At least now I suppose they can say "we're using SRI"... 🤷‍♂️

Getting Started Is Easy

If you have script tags on your site that are loading static JavaScript, you should absolutely go and add SRI to those tags! Many providers that give you script tags to include in your site and now providing them with the SRI integrity attribute already added, but many aren't. You can generate a new script tag with SRI using our SRI Hash Generator to replace any that don't have SRI, just paste the URL from the src attribute of your script tag and we'll generate the new script tag for you to replace the old one.

For CSP, it's a little harder than copy/paste to get started, but it's really not much harder. We have a dedicated Content Security Policy page that gives you details, but the CSP Wizard is really the place to start. By using a CSP Report-Only header that sends reports for everything, but doesn't block anything, we can quickly audit all of the dependencies you have across your entire site.

Content-Security-Policy-Report-Only: default-src 'none'; form-action 'none'; frame-ancestors 'none'; report-uri https://demo.report-uri.com/r/d/csp/wizard

Once we've generated the list of dependencies that you have, we need you to tell us which ones are supposed to be there and which ones aren't. From that, we can generally build your entire policy for you! Even if you never decide to go to enforce mode, we can still monitor for new dependencies being added to your site, or any other changes, and alert you if they look suspicious. A CSP in Report-Only mode is still a very powerful monitoring solution and it shouldn't be overlooked.

If you want any more information specific to Cryptojacking or Magecart, check out those dedicated product pages or, you can look at our Case Studies for other real-world examples of where these kinds of attacks have happened and caused serious problems for the organisations involved. If you have any questions, feel free to drop them down below or you can email/DM me via the usual channels!