AppSec Blog

Spot the Vuln - Light - Cross Site Scripting

Details

Affected Software: FreeNAS

Fixed in Version: 0.69.3

Issue Type: Cross Site Scripting (XSS)

Original Code: Found Here

Description

The code sample for this week contained a couple XSS vulnerabilities. Although not essential for exploitation, its also interesting to note that this response is within an SVG image. You can see this by examining the header() api specifying the content-type: header("Content-type: image/svg+xml");

The first issue is pretty easy to follow, so we'll begin there. On line 11, $ifname is assigned a tainted value from $_GET["ifname"]. After the variable assignment, the authors use the tainted variable to build HTML markup on line 66.

The second issue requires a little bit of tracing. First, the $ifnum variable is assigned a tainted value from $_GET["ifnum"] on line 10. $ifnum is then used to build the $fetch_link variable on line 18. If $fetch_link is ever used to build HTML markup, it will result in XSS.

The third issue also requires a bit of tracing as well. Once again, we start with the assignment of a tainted variable to $ifnum on line 10. $ifnum is then used to build an error message on line 37 ($error_text). $error_text is then used to build HTML markup on line 72 resulting in XSS.

The developers addressed this issue by using htmlspecialchars() during the inital variable assignments. This takes care of all three of the XSS issues described above.

Developers Solution

<?php ... snip ... require("guiconfig.inc"); header("Content-type: image/svg+xml"); /********** HTTP GET Based Conf ***********/ +$ifnum=@htmlspecialchars($_GET["ifnum"]); // BSD / SNMP interface name / number +$ifname=@htmlspecialchars($_GET["ifname"]) ? htmlspecialchars($_GET["ifname"]) : "Interface $ifnum"; //Interface name that will be showed on top right of graph -$ifnum=@$_GET["ifnum"]; // BSD / SNMP interface name / number -$ifname=@$_GET["ifname"]?$_GET["ifname"]:"Interface $ifnum"; //Interface name that will be showed on top right of graph /********* Other conf *******/ $scale_type="follow"; //Autoscale default setup : "up" = only increase scale; "follow" = increase and decrease scale according to current graphed datas $nb_plot=120; //NB plot in graph $time_interval=1; //Refresh time Interval $unit="bits"; //Initial unit type: "bits" or "bytes" $fetch_link = "stats.php?if=$ifnum"; //SVG attributes $attribs['bg']='fill="#EEEEEE" stroke="none" stroke-width="0" opacity="1"'; $attribs['axis']='fill="black" stroke="black"'; $attribs['in']='fill="#00CC00" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"'; $attribs['out']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"'; $attribs['graph_in']='fill="none" stroke="#00CC00" stroke-opacity="0.8"'; $attribs['graph_out']='fill="none" stroke="#FF0000" stroke-opacity="0.8"'; $attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"'; $attribs['graphname']='fill="#435370" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"'; $attribs['grid_txt']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="6"'; $attribs['grid']='stroke="gray" stroke-opacity="0.5"'; $attribs['switch_unit']='fill="#435370" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"'; $attribs['switch_scale']='fill="#435370" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"'; $attribs['error']='fill="red" font-family="Arial" font-size="4"'; $attribs['collect_initial']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"'; //Error text if we cannot fetch data : depends on which method is used $error_text = gettext("Cannot get data about interface") . " $ifnum"; $height=100; //SVG internal height : do not modify $width=200; //SVG internal width : do not modify $encoding = system_get_language_codeset(); /********* Graph DATA **************/ header("Last-Modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT"); header("Expires: " . gmdate( "D, j M Y H:i:s", time() ) . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 header("Cache-Control: post-check=0, pre-check=0", FALSE); header("Pragma: no-cache"); // HTTP/1.0 header("Content-type: image/svg+xml"); echo "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>\n"; ?> <svg width="100%" height="100%" viewBox="0 0 <?=$width?> <?=$height?>" preserveAspectRatio="none" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init(evt)"> <g id="graph"> <rect id="bg" x1="0" y1="0" width="100%" height="100%" <?=$attribs['bg']?>/> <line id="axis_x" x1="0" y1="0" x2="0" y2="100%" <?=$attribs['axis']?>/> <line id="axis_y" x1="0" y1="100%" x2="100%" y2="100%" <?=$attribs['axis']?>/> <path id="graph_out" d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_out']?>/> <path id="graph_in" d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_in']?>/> <path id="grid" d="M0 <?=$height/4*1?> L <?=$width?> <?=$height/4*1?> M0 <?=$height/4*2?> L <?=$width?> <?=$height/4*2?> M0 <?=$height/4*3?> L <?=$width?> <?=$height/4*3?>" <?=$attribs['grid']?>/> <text id="grid_txt1" x="<?=$width?>" y="<?=$height/4*1?>" <?=$attribs['grid_txt']?> text-anchor="end">75%</text> <text id="grid_txt2" x="<?=$width?>" y="<?=$height/4*2?>" <?=$attribs['grid_txt']?> text-anchor="end">50%</text> <text id="grid_txt3" x="<?=$width?>" y="<?=$height/4*3?>" <?=$attribs['grid_txt']?> text-anchor="end">25%</text> <text id="graph_in_lbl" x="5" y="8" <?=$attribs['in']?>><?=gettext("In");?> <tspan id="graph_in_txt" <?=$attribs['in']?>> </tspan></text> <text id="graph_out_lbl" x="5" y="16" <?=$attribs['out']?>><?=gettext("Out");?> <tspan id="graph_out_txt" <?=$attribs['out']?>> </tspan></text> <text id="ifname" x="<?=$width?>" y="8" <?=$attribs['graphname']?> text-anchor="end"><?=$ifname?></text> <text id="switch_unit" x="<?=$width*0.55?>" y="5" <?=$attribs['switch_unit']?>><?=sprintf(gettext("Switch to %s/s"), ("bits" === $unit) ? "bytes" : "bits");?></text> <text id="switch_scale" x="<?=$width*0.55?>" y="11" <?=$attribs['switch_scale']?>><?=gettext("AutoScale");?> (<?=("up" === $scale_type) ? gettext("Up") : gettext("Follow");?>)</text> <text id="datetime" x="<?=$width*0.55?>" y="17" <?=$attribs['legend']?>> </text> <text id="graphlast" x="<?=$width*0.55?>" y="23" <?=$attribs['legend']?>><?=gettext("Graph shows last");?> <?=$time_interval*$nb_plot?> <?=gettext("seconds");?></text> <polygon id="axis_arrow_x" <?=$attribs['axis']?> points="<?=($width) . "," . ($height)?> <?=($width-2) . "," . ($height-2)?> <?=($width-2) . "," . $height?>"/> <text id="error" x="<?=$width*0.5?>" y="<?=$height*0.4?>" visibility="hidden" <?=$attribs['error']?> text-anchor="middle"><?=$error_text?></text> <text id="collect_initial" x="<?=$width*0.5?>" y="<?=$height*0.4?>" visibility="hidden" <?=$attribs['collect_initial']?> text-anchor="middle"><?=gettext("Collecting initial data, please wait...");?></text> </g> <script type="text/ecmascript"> <![CDATA[ /** * getURL is a proprietary Adobe function, but it's simplicity has made it very * popular. If getURL is undefined we spin our own by wrapping XMLHttpRequest. */ if (typeof getURL == 'undefined') { getURL = function(url, callback) { if (!url) throw 'No URL for getURL'; try { if (typeof callback.operationComplete == 'function') callback = callback.operationComplete; } catch (e) {} if (typeof callback != 'function') throw 'No callback function for getURL'; var http_request = null; if (typeof XMLHttpRequest != 'undefined') { http_request = new XMLHttpRequest(); } else if (typeof ActiveXObject != 'undefined') { try { http_request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { http_request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } if (!http_request) throw 'Both getURL and XMLHttpRequest are undefined'; http_request.onreadystatechange = function() { if (http_request.readyState == 4) { callback( { success : true, content : http_request.responseText, contentType : http_request.getResponseHeader("Content-Type") } ); } } http_request.open('GET', url, true); http_request.send(null); } }

Post a Comment






Captcha


* Indicates a required field.