Path Relative Style-sheet Injection


Overview

Web applications often link common code to avoid having multiple copies of the same source within a site. This is a best practice that allows a developer to correct a defect or add an upgrade into a single file and have that new code propogate through out the entire application. Stylesheets, JavaScript and other "includes" are often linked using "link" tags and "script" tags respectively. In the case of a link tag, the "href" attribute specifies the path of the include file. For script tags the "src" attribute does the same.

Links can be "relative" or "absolute". Absolute links specify the full path to the resource file. An example would be

<a href="/mutillidae/styles/global.css" target="_blank"> /mutillidae/styles/global.css </a>

Relative links specify the path from the current page. The path for this page is /mutillidae. A reference to the same stylesheet could be done with

<a href="styles/global.css" target="_blank"> styles/global.css </a>

Hover your mouse over the relative link above and look in your browsers status bar to see how the browser will resolve this relative link. The path of the parent page that is including the resource is the base URL. The browser will automatically append the base URL page with the link specified in the "href" attribute resulting in a "real" path of

/mutillidae/styles/global.css

The browser will make a request to the web server for the stylesheet using this path. You may want to observe this behavior using Burp-Suite or via the Developer --> Network tool in Firefox.

If the paths to include files are relative and the user can control the base URL then it may be possible to trick the browser into constructing the path to the included file incorrectly.

Example

The page in Mutillidae that implements path relative stylesheet injection (in addition to several other vulnerabilities) is styling.php. The page is framed by styling-frame.php. Assuming the default installation, the direct URL to the styling.php page is http://localhost/mutillidae/styling.php . The styling.php page contains a path relative link to the global styles page global-styles.css located in the "styles" directory. The link element is written similar to

<link rel="stylesheet" type="text/css" href="./styles/global-styles.css" />

When the browser loads URL

http://localhost/mutillidae/styling.php

it will see the relative link to

./styles/global-styles.css

. To load global styles the browser determines the base URL from the parent page to be

http://localhost/mutillidae/

then appends the relative link for the

global-styles.css

page. The resulting URL for the stylesheet will be

http://localhost/mutillidae/styles/global-styles.css

The user may add additional directories beyond the end of the file name. This can cause significant confusion for the browser and may result in different behavior between the browser and the web server. One such URL may be

http://localhost/mutillidae/styling.php/foo/bar

The browser may calculate the base URL to be

http://localhost/mutillidae/styling.php/foo

When this base URL is used to determine the URL for the global-styles.css stylesheet, the resulting file path will be

http://localhost/mutillidae/styling.php/foo/styles/global-styles.css

The browser will send a request to the web server to fetch the file /mutillidae/styling.php/foo/styles/global-styles.css . The file does not exist but it turns out this may not matter. Web servers tend to determine file paths at least partially based on the file extention. The file extention in this case is ".php". The Apache or IIS web server hosting Mutillidae will probably consider the file path to be

http://localhost/mutillidae/styling.php

The web server will respond to the request for the stylesheet with a second copy of page styling.php. Page styling.php is an HTML document. HTML documents that are well-formed will send an HTTP response header of "Content-Type: text/html" declaring the content to be HTML. However, the browser (from its point of view) attempted to fetch a stylesheet (CSS document). How the browser handles this situation will determine the outcome of this "Relative Path Overwrite" (Credit: Gareth Heyes).

If the browser interprets the HTML document strictly, processing will stop since the document returned by the web server does not have the required Content-Type of "text/css". Browsers may relax strictness if running in compatibility mode or processing files with older document types (i.e. "transitional"). View the source of the styling.php page in Mutillidae to see a document type set to Transitional. The document type is declared at the top of the HTML document. Note: See the Burp-Suite blog for a discusion on "quirks mode".

In cases where the browser parses the HTML document, any CSS contained in the HTML document may be executed. Any CSS contained in the HTML document is not likely to be malicious of course; however, some web application pages allow user input. If a malicious CSS is injected into the HTML document and that HTML document is fetched by a browser attempting to load CSS, the injected CSS may be executed by the browser.

Discovery Methodology

Discovering pages with this vulnerability can be difficult because of the number of variables that influence whether a page is vulnerable. The application framework and web server need to interpret the URL based on page name while the browser simultaneously interprets the URL based on the full path. The browser also has to be willing to parse and execute CSS found inside of non-css documents. Also a would-be attacker will need some mechanism by which they can inject malicious CSS into that non-css document. To set the browser into compatibility mode, it may be neccesay to frame the victim page in order to set compatibility mode within the framing page.

One possible approach is to identify pages which contain relative links to stylesheets and/or JavaScript include files. When found check if the page sets the Content-Type HTTP response header correctly. If the response header is present, it may still be possible to place the browser into compatibility mode by framing the page. check if the page allows itself to be framed.

Exploitation

To exploit the site, several conditions need to be met. The browser should be encouraged to enter compatibility mode. It may help to frame the target page to make this easier. Note that Mutillidae has already provided a framed page to help with this step.

The browser should be capible of downgrading into compatibility mode so that HTML pages will be parsed by the CSS interpreter desipte the fact that the content type of the page is HTML. Internet Explorer up through version 11 is confirmed to work in this mode.

Assuming the prerequisites are met, the page needs to be injected with a cascading stylesheet (CSS) command. If the page is possible to inject, the injection opportunity will vary. In the case of Mutillidae, the styling.php page will reflect the address of the framing page. If the malicious CSS can be incorporated into the URL itself, the CSS will be reflected giving the browser a chance to interpret the CSS.

http://172.16.0.130/mutillidae/index.php?page=styling-frame.php&page-to-frame=styling.php/foo/bar/%0A{}*{color:red;}///

In the preceding URL, the first portion (black) is the common home page all pages in Mutillidae share. The "page" parameter tells index.php which page the user would like to view. So far, this is normal operation.

The next parameter "page-to-frame" (blue) determines what page styling-frame.php will frame. Note that the page being framed, styling.php, also accepts a "page-title" parameter. This parameter is not mandatory for this attack but is useful for other types of cross-site scripting.

The additional text at the end (red) is the attack. Injection attacks can be broken down into their three components: prefix, payload and suffix.

/foo/bar/%0A{}*{color:red;}///

The prefix in this case is two parts. The path /foo/bar/ triggers the PRSSI vulnerability by having the browser try to fetch a CSS document that includes the page name in the path. The web server does not parse paths like browsers and will recognize the page name then ignore the rest of the path. The rest of the prefix opens a "selector" in CSS terms. The selector in this example is asterisk. Selectors choose to which element to apply the style. The asterisk matches any element making the payload more likely to be applied (execute). The portion in red is the payload. This payload turns text red. The third portion of the attack is the suffix which properly closes out the prefix to form a syntactically correct statement.

Example

The following link is confirmed to reproduce the vulnerability in a fully patched Internet Explorer 11 (Compatibility mode) running on Windows 7

http://172.16.0.130/mutillidae/index.php?page=styling-frame.php&page-to-frame=styling.php/foo/bar/%0A{}*{color:red;}///

References

Relative Path Overwrite by Gareth Heyes
PortSwigger Web Security Blog

Cross Site Scripting Defenses

To defend against Cross-Site Scripting, encode all output per context. Just because the application sanitized/validated/filtered the input when the user sent the input doesnt mean the application is safe. The database could be altered by a rouge insider, a database attack such as ASPROX, or a mallicious programmer. Developers should not have access to production database data; ever. Developers should not be able to copy their own code into production; ever. That is what change control is for.

Videos


Warning: Could not reach YouTube via network connection. Failed to embed video.

Click here to watch Introduction to Path Relative Style Sheet Injection