Introduction
Cross-site scripting (XSS) is one of the three most exploited security vulnerability on the web.
A XSS vulnerability enables attackers to inject client-side script into a Web page viewed by other users.
Although it's a client-side attack it can be critical and lead to a full compromise.
Unfortunately XSS vulnerabilities are often misunderstood and overlooked.
Along the years pentesters have developed stealth tricks to evade XSS filters.
This cheat sheet is focused on providing guidance against these filters.
PHP XSS filters evasion
PHP is probably the most popular server-side scripting language designed for online web development.
By default PHP doesn't escape HTML tags from user controlled input.
If the developer of a web application doesn't properly sanitize user controlled input, it can lead to a vulnerability.
str_replace, preg_replace
Some developers are using the str_replace
or preg_replace
functions to remove <script>
tags.
This is bad practice because other HTML tags such as <img>
or <svg>
can execute JavaScript without user interaction.
The trick to evade a replace filter is to understand how it works and to take advantage of its weakness.
The code below takes the author parameter, remove all occurrences of script
no matter what the case is and print the result.
<?php
echo 'Author: ' . preg_replace('/script/i', '', $_GET['author']);
/*
Example output for …?author=Alice
Author: Alice
*/
?>
An attacker can easily leverage this vulnerable code by splitting the tag.
The output for …?author=<scrSCRIPTipt>alert('XSS')</scrSCRIPTipt>
is Author: <script>alert('XSS')</script>
and the script will execute.
htmlentities
Using htmlentities
is a far better choice, but in some situations it can still lead to a vulnerability.
The code below takes the user parameter, removes all occurrences of script and prints the result.
<?php
echo "Profile picture <img alt='Profile' src='/profiles/".htmlentities($_GET["user"]).".jpg' />";
/*
Example output for …?user=Bob
Profile picture <img alt='Profile' src='/profiles/Bob.jpg' />
*/
?>
By default the htmlentities
function doesn't convert single quotes to HTML character entities.
Then we can use the onerror
property of the img tag to execute JavaScript.
The request to …?user=x' onerror='alert("XSS")
will set the src
of the img
tag to x.
Because the picture doesn't exists the onerror
event is triggered and the attacker code will execute.
Data URIs
The data URI scheme is a (Uniform Resource Identifier) scheme that provides a way to include data in-line in web pages as if they were external resources.
Data URI syntax
The syntax of data URIs was defined RFC 2397, published in August 1998.data:[<media type>][;charset=<character set>][;base64],<data>
HTML example
An HTML fragment embedding a picture of Wiremask.
<img src="data:image/bmp;base64,Qk1+AAAAAAAAAD4AAAAoAAAAPAAAAAgAAAABAAEAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wDOduQTZPIbkM52zPIm99swxHbM8iYHynCUNhzypmcYcJW2zDCHbjjwsbbs8ccO+nCxtuzxx477MDmWDDHnnhuQ" alt="wiremask" />
Exploitation
Data URIs can be used with just a few HTML tags.
<a>
<iframe>
<img>
<object>
The code below takes the video parameter, converts all special characters to HTML entities with the htmlspecialchars
function and prints the result.
<?php
echo 'Video: <object width="800" height="600" data="'.htmlspecialchars($_GET['video']).'"></object>';
/*
Example output for ?video=Wizzy.swf
Video: <object width="800" height="600" data="Wizzy.swf"></object>
*/
?>
An attacker can encode the payload <script>alert("XSS")</script>
to Base64 and create an URL …?video=data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik8L3NjcmlwdD4=
.
The media type of the Data URI is set to text/html which means that the object will decode the Base64 encoded payload and execute its content.
UTF-7 encoding
There is another way to exploit XSS vulnerabilities through htmlentities
and htmlspecialchars
.
If the page encoding is UTF-7 or if the attacker is able to control the page encoding, then the following UTF-7 encoded payload +ADw-script+AD4-alert('XSS')+ADsAPA-/script+AD4-
will execute.