| DetailsAffected Software:Corpse C&C Fixed in Version:? Issue Type:XSS Original Code:Found Here DetailsFairly straightforward XSS bug here. This week’s bug can be found in the index.php file for the Corpse C&C. Specifically,the index file located at Corpse/info/socks/index.php. Buried deep within the print statement starting on line 30 are two unsanitized,unescaped variables ($states and $countrys). Both $states and $countrys are taken directly from $_POST parameters and assigned to php variables. Those php variables are then used to build HTML markup. Buried within a large print statement,a little difficult to spot,but this bug is classic XSS. Vulnerable Code1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| <?phpinclude_once('geoipcity.inc');include_once('../mysqllog.php');$countrys = $_POST['countrys']; $states = $_POST['states']; if ($countrys == "") { $countrys = "all";}if ($states == "") { $states = "all";}$date = date("m-d");list($month, $day) = explode('-', $date);print "<STYLE><!-- a:link{color:#404040;text-decoration:none} a:visited{color:#909090;text-decoration:none} a:active{color:#000000;text-decoration:none} a:hover{color:#000000;text-decoration:none} input{BACKGROUND-COLOR:#66CF96;BORDER-BOTTOM:#ffffff 1px solid;BORDER-LEFT:#ffffff 1px solid;BORDER-RIGHT:#ffffff 1px solid;BORDER-TOP:#ffffff 1px solid;COLOR:#000000;FONT-FAMILY:Tahoma,sans-serif;FONT-SIZE:12px} --></STYLE> <BODY bgcolor=#DDDDDD text=#505050 marginwidth=0><table align=center border=1><TD><form action=index.php method=post><B>Select by country</B><TD><select name=countrys><option value=all>All countries";$j = 1;while ($GEOIP_COUNTRY_CODES[$j] != "") { print "<option value=$GEOIP_COUNTRY_CODES[$j]>$GEOIP_COUNTRY_NAMES[$j]\r\n"; $j++;}print "</SELECT><TD><BR><INPUT type=submit value=submit></FORM><TR><TD> <FORM action=index.php method=post><B>Select by state</B><TD><select name=states><option value=all>all<option value=AK>AK<option value=AL>AL<option value=AR>AR<option value=AS>AS<option value=AZ>AZ<option value=CA>CA<option value=CO>CO <option value=CT>CT<option value=DC>DC<option value=DE>DE<option value=FL>FL<option value=GA>GA<option value=HI>HI<option value=IA>IA<option value=ID>ID<option value=IL>IL<option value=IN>IN <option value=KS>KS<option value=KY>KY<option value=LA>LA<option value=MA>MA<option value=MD>MD<option value=ME>ME<option value=MI>MI<option value=MN>MN<option value=MO>MO<option value=MP>MP <option value=MS>MS<option value=MT>MT<option value=NC>NC<option value=ND>ND<option value=NE>NE<option value=NH>NH<option value=NJ>NJ<option value=NM>NM<option value=NV>NU<option value=NY>NY <option value=OH>OH<option value=OK>OK<option value=OR>OR<option value=PA>PA<option value=PR>PR<option value=RI>RI<option value=SC>SC<option value=SD>SD<option value=TN>TN<option value=TX>TX <option value=UT>UT<option value=VA>VA<option value=VI>VI<option value=VT>VT<option value=WA>WA<option value=WI>WI<option value=WV>WV<option value=WY>WY</select> <TD><BR><input type=submit value=submit></form></table><B><CENTER><BR>Current country selected:$countrys<BR>Current state selected:$states</CENTER></B><BR> <table width=100% cellspacing=0><tr><td><table width=100% bgcolor=#FFFFFF cellspacing=1><tr><td align=center bgcolor=#66CF96><b>List</b></td></tr></table></td></tr> <tr><td><table width=100% bgcolor=#FFFFFF cellspacing=1><tr><td align=center bgcolor=#66CF96>IP</td><td align=center bgcolor=#66CF96>UPDATE</td><td align=center bgcolor=#66CF96>ID</td> <td align=center bgcolor=#66CF96>COUNTRY</td> <td align=center bgcolor=#66CF96>CITY</td> <td align=center bgcolor=#66CF96>STATE</td> <td align=center bgcolor=#66CF96>UPTIME</td></tr>"; $stime = mktime();$stime = $stime - 86400;$link = mysql_connect($mysql_host, $mysql_login, $mysql_pass) or die("Could not connect:" . mysql_error());mysql_select_db($mysql_db, $link) or die("Could not select:" . mysql_error());$query = 'SELECT * FROM `socks` WHERE `update` >' . $stime . ' ORDER BY `update` DESC';$result = mysql_query($query, $link) or die("Could not execute:" . mysql_error());$tot = 0;while ($row = mysql_fetch_assoc($result)) { $prms[0] = $row['ip']; $prms[1] = $row['hport']; $prms[2] = $row['sport']; $prms[3] = $row['update']; $prms[4] = $row['uptime']; $prms[5] = $row['uid']; $prms[6] = $row['used']; if ($prms[0] != "") { printent ($prms,$tot,$countrys,$states); $tot++; }}mysql_close($link);print "</table><table width=100% bgcolor=#FFFFFF cellspacing=1><tr><td align=right bgcolor=#66CF96>Total:<b>$tot</b></tr></td></table></table></table></tr></td></TABLE></BODY></HTML>";function printent ($prms,$tot,$countrys,$states){ if(!($tot%2)) { $bcolor="#D6D6D6"; } else { $bcolor="#98E8E1"; } $tid = $prms[5]; $tid = chop($tid); $gi = geoip_open ("../GeoIPCity.dat",GEOIP_STANDARD ); $record = geoip_record_by_addr ($gi,$prms[0]); geoip_close ($gi); if (($countrys == "all") & ($states == "all")) { echo "<tr>\r\n"; echo "<td align=left bgcolor=$bcolor onClick=\"window.open('check.php?ip=$prms[0]&port=$prms[2]&hport=$prms[1]','child','scrollbars=no,width=250,height=100');\" onmouseover=\"this.style.background='#000D2A';\" onmouseout=\"this.style.background='$bcolor';\"><font face='Fixedsys' color=#707070><INPUT type=button value=\"Copy IP\" onclick=window.clipboardData.setData(\"Text\",\"$prms[0]\")>$prms[0]</font></td>\r\n"; echo "<td align=center bgcolor=$bcolor><font face='Fixedsys' color=#707070>" . date("H:i:s d.m.y", $prms[3]) ."</font></td>\r\n";//socks echo "<td align=center bgcolor=$bcolor><font face='Fixedsys' color=#707070><INPUT type=button value=\"Copy ID\" onclick=window.clipboardData.setData(\"Text\",\"$tid\")> $tid</font></td>\r\n";//socks // Show flag if ($record->country_code == "") { $record->country_code = "-"; $record->country_name = ""; } $c_code = strtolower($record->country_code); $flag = "<IMG src=../flags/$c_code.gif> $record->country_name.<BR>"; echo "<td align=left bgcolor=$bcolor><font face='Fixedsys' color=#707070>$flag</font></td>\r\n"; |
DetailsAffected Software:Zeus C&C Fixed in Version:? Issue Type:XSS and XSRF Original Code:Found Here DetailsThis week’s bugs affected Zeus C&C 1.1.0.0. The file we’re looking at is mod.bcmds.php. The first thing that popped out at me was the named constant “QUERY_STRING” that’s being used in various places in code. Although we don’t get to see exactly where QUERY_STRING is being defined in the code snippet as a general rule of thumb,values from the query string cannot be trusted. In this case,QUERY_STRING is defined in a different file (in.php) in the following line: 1
| define('QUERY_STRING', QUERY_STRING_BLANK .$module); |
QUERY_STRING_BLANK is defined in the following way (also in in.php): 1
| define('QUERY_STRING_BLANK', $_SERVER['PHP_SELF'].'?m='); |
Veteran Spot the Vuln readers will immediately realize that $_SERVER[‘PHP_SELF’] cannot be trusted and can contain attacker supplied data. An old,but good write-up on PHP_SELF XSS can be found here.
Knowing this,we’re free to XSS the Zeus C&C and hijack the bots… as long as we can get the Zeus botmaster to visit a page we own (a reasonable request) AND we can figure out the domain name the botmaster is using for their C&C (fairly difficult). Botmasters can take advantage of browser same origin policy defenses and use a host file to create a unique domain for their C&Cs… minimizing the impact of reflected XSS exploits against their C&Cs. I’m wondering if this is the first public security advice for the botmaster community…
I’ve highlighted the lines that insecurely use the QUERYSTRING constant to build HTML markup,resulting in XSS. I couldn’t find a mod.bcmds.php file after Zeus 1.1.0.0,so I’m considering this specific XSS issue fixed.
There is a second,more subtle issue in this code… one that still affects the latest Zeus C&C builds. The C&C developer seemingly went through great lengths to defend against SQL injection. A quick perusal through the code shows a smattering of addslashes() and is_numeric() in attempts to validate input before passing it to backend databases. What’s missing however… are nonce/token checks (XSRF defenses). The following code snippet is a perfect example: 1 2 3 4 5 6
| else if(isset($_GET['del'])&&is_numeric ($_GET['del'])&&$pedt){ mysql_query('DELETE FROM '.TABLE_BCMDS .' WHERE id='.$_GET['del'].' LIMIT 1'); header('Location:'.QUERY_STRING ); die(); } |
In the snippet above,we see that the C&C code grabs a value directly from the querystring,validates that it is_numeric(),and then passes the value to a DELETE statement. No where does the code attempt to validate that the request wasn’t generated via XSRF. If an attacker can discover the location of the C&C and lure the botmaster to an attacker controlled page,they can setup an XSRF attack to delete the entire TABLE_BCMDS. Looking through the latest,most current Zeus C&C code,XSRF defenses still have not been put into place… come on guys,even WordPress has XSRF defenses! http://codex.wordpress.org/Function_Reference/wp_verify_nonce Vulnerable Code1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| <?php if(!defined('__INDEX__'))die();$pedt=PRIV &PRIV_BOTS_CMDS_EDIT ;if((isset($_GET['new'])&&$pedt)||(isset($_GET['edit'])&&is_numeric ($_GET['edit']))){ if(!@include_once('fmt.php'))die('fmt.php not founded!'); $name=isset($_POST['name'])? $_POST['name']:time(); $stat=isset($_POST['stat'])? ($_POST['stat']? 1:0):0; $limit=(isset($_POST['limit'])&&is_numeric ($_POST['limit']))? $_POST['limit']:0; $cnts=isset($_POST['cnts'])? $_POST['cnts']:''; $cids=isset($_POST['cids'])? $_POST['cids']:''; $bns=isset($_POST['bns'])? $_POST['bns']:''; $cmds=isset($_POST['cmds'])? $_POST['cmds']:''; if($_SERVER['REQUEST_METHOD']=='POST'&&strlen ($name)>0&&$pedt) { $cmdsb=EncodeBuffer (str_replace("\r\n","\n",trim($cmds))); $data='name=\''.addslashes($name).'\',stat='.$stat.',lim='.$limit.',c=\''.addslashes(SepFmt ($cnts)).'\',comps=\''.addslashes(SepFmt ($cids)).'\',bns=\''.addslashes(SepFmt ($bns)).'\',cmds=\''.addslashes($cmdsb).'\''; if(isset($_GET['new']))mysql_query('INSERT INTO '.TABLE_BCMDS .' SET '.$data.',id2='.time()); else mysql_query('UPDATE '.TABLE_BCMDS .' SET '.$data.' WHERE id=\''.$_GET['edit'].'\' LIMIT 1'); header('Location:'.QUERY_STRING ); } else { if(!$pedt&&isset ($_GET['new']))unset($_GET['new']); HTMLBegin (isset($_GET['new'])?LNG_MBCMDS_NEWCMD :($pedt?LNG_MBCMDS_EDITCMD :LNG_MBCMDS_VIEWCMD )); if(isset($_GET['new']))print CmdForm ('new',LNG_MBCMDS_NEWCMD ,LNG_MBCMDS_ADD ,$name,$stat,$limit,$cnts,$cids,$bns,$cmds); else { $r=mysql_query('SELECT * FROM '.TABLE_BCMDS .' WHERE id=\''.$_GET['edit'].'\' LIMIT 1'); if($r&&mysql_affected_rows ()==1&&($m=mysql_fetch_assoc($r)))print CmdForm ('edit='.$_GET['edit'],$pedt?LNG_MBCMDS_EDITCMD :LNG_MBCMDS_VIEWCMD ,$pedt?LNG_MBCMDS_EDIT :'',$m['name'],$m['stat'],$m['lim'],SepFmtB ($m['c']),SepFmtB ($m['comps']),SepFmtB ($m['bns']),DecodeBuffer ($m['cmds'])); else print '<font class="error">'.LNG_MBCMDS_ERROR_1 .'</font>'; } HTMLEnd (); } die();}else if(isset($_GET['del'])&&is_numeric ($_GET['del'])&&$pedt){ mysql_query('DELETE FROM '.TABLE_BCMDS .' WHERE id='.$_GET['del'].' LIMIT 1'); header('Location:'.QUERY_STRING ); die(); }else if(isset($_GET['res'])&&is_numeric ($_GET['res'])&&$pedt){ mysql_query('UPDATE '.TABLE_BCMDS .' SET exc=\'0\',rcomps=\'\',exct=\'0\' WHERE id='.$_GET['res'].' LIMIT 1'); header('Location:'.QUERY_STRING ); die();}HTMLBegin(LNG_MBCMDS,$pedt?'function DelCmd(uid,q){if(confirm(q))window.location=\''.QUERY_STRING.'&del=\'+uid};function ResCmd(uid,q){if(confirm(q))window.location=\''.QUERY_STRING.'&res=\'+uid}':''); $r=mysql_query('SELECT * FROM '.TABLE_BCMDS ); $total=mysql_affected_rows();print '<table class="tbl1"><tr><td class="td1"colspan="'.($pedt? 9:10).'">'.LNG_MBCMDS_R_CMDS .' ('.$total.')</td>';if($pedt)print '<td class="td1"align="center"><input type="submit"value="'.LNG_MBCMDS_NEWCMD.'"class="ism"style="width:100%"onClick="window.location=\''.QUERY_STRING.'&new\';"></td>'; print '</tr><tr><td class="td1">'.LNG_MBCMDS_R_ID .'</td><td class="td1">'.LNG_MBCMDS_R_NAME .'</td><td class="td1">'.LNG_MBCMDS_R_STAT .'</td><td class="td1">'.LNG_MBCMDS_R_LIMIT .'</td><td class="td1">'.LNG_MBCMDS_R_REQ .'</td><td class="td1">'.LNG_MBCMDS_R_EXEC .'</td><td class="td1">'.LNG_MBCMDS_R_CNTS .'</td><td class="td1">'.LNG_MBCMDS_R_CIDS .'</td><td class="td1">'.LNG_MBCMDS_R_BNS .'</td><td class="td1"> </td></tr>';if($total>0){ $j=0; while(($m=mysql_fetch_assoc($r))) { $a=(($j++)%2==0? 1:2); print '<tr valign="top"><td align="right"class="tdx'.$a.'">'.$m['id2'].'</td>'. '<td class="tdx'.$a.'">'.htmlentities($m['name']).'</td>'. '<td class="tdx'.$a.'">'.($m['stat']?LNG_MBCMDS_STAT_ON :LNG_MBCMDS_STAT_OFF ).'</td>'. '<td align="right"class="tdx'.$a.'">'.$m['lim'].'</td>'. '<td align="right"class="tdx'.$a.'">'.$m['exc'].'</td>'. '<td align="right"class="tdx'.$a.'">'.$m['exct'].'</td>'. '<td class="tdx'.$a.'">'.($m['c']==''? '-':str_replace(',','<br>',htmlentities(SepFmtB ($m['c'])))).'</td>'. '<td class="tdx'.$a.'">'.($m['comps']==''? '-':str_replace(',','<br>',htmlentities(SepFmtB ($m['comps'])))).'</td>'. '<td class="tdx'.$a.'">'.($m['bns']==''? '-':str_replace(',','<br>',htmlentities(SepFmtB ($m['bns'])))).'</td>'. '<td class="tdx'.$a.'"align="center"><input class="ism"style="width:90%"type="submit"value="'.($pedt?LNG_MBCMDS_R_EDIT :LNG_MBCMDS_R_VIEW ).'"onClick="window.location=\''.QUERY_STRING .'&edit='.$m['id'].'\';return false;">'; if($pedt)print '<br><input class="ism"style="width:90%"type="submit"value="'.LNG_MBCMDS_R_RES_OK .'"onClick="javascript:ResCmd(\''.$m['id'].'\',\''.addslashes(sprintf(LNG_MBCMDS_R_RES ,$m['name'])).'\');return false;"><br><input class="ism"style="width:90%"type="submit"value="'.LNG_MBCMDS_R_DEL_OK .'"onClick="javascript:DelCmd(\''.$m['id'].'\',\''.addslashes(sprintf(LNG_MBCMDS_R_DEL ,$m['name'])).'\');return false;">'; print '</td></tr>'; }}else print '<tr><td align="center"colspan="10"class="tdx1"><i>'.LNG_MBCMDS_R_NONE .'</i></td></tr>';print '</table>';HTMLEnd ();function CmdForm ($cmd,$title,$action,$name,$stat,$limit,$cnts,$cids,$bns,$cmds){ $en=$action==''? 0:1; $stat=$stat? 1:0; $ro=$en? '':'readonly '; $str=$en?'<form method="POST"action="'.QUERY_STRING.'&'.$cmd.'">':''; $str.='<table class="tbl1"width="350"><tr><td class="td1"colspan="2">'.$title.'</td></tr>'. '<tr><td>'.LNG_MBCMDS_NAME .'</td><td width="100%"><input '.$ro.'type="text"name="name"value="'.htmlentities($name).'"style="width:100%"></td></tr>'. '<tr><td colspan="2"><table class="tbl1"><tr><td>'.LNG_MBCMDS_STAT .'</td><td width="100%"><select '.($en? '':'disabled ').'name="stat"style="width:100%">'. '<option value="1"'.($stat==1? ' selected':'').'>'.LNG_MBCMDS_STAT_ON .'</option>'. '<option value="0"'.($stat==0? ' selected':'').'>'.LNG_MBCMDS_STAT_OFF .'</option>'. '</select></td></tr>'. '<tr><td>'.LNG_MBCMDS_LIMIT .'</td><td width="100%"><input '.$ro.'type="text"name="limit"value="'.$limit.'"style="width:100%"></td></tr>'. '<tr><td>'.LNG_MBCMDS_CNTS .'</td><td width="100%"><input '.$ro.'type="text"name="cnts"value="'.$cnts.'"style="width:100%"></td></tr>'. '<tr><td>'.LNG_MBCMDS_CIDS .'</td><td width="100%"><input '.$ro.'type="text"name="cids"value="'.$cids.'"style="width:100%"></td></tr>'. '<tr><td>'.LNG_MBCMDS_BNS .'</td><td width="100%"><input '.$ro.'type="text"name="bns"value="'.$bns.'"style="width:100%"></td></tr>'. '<tr><td valign="top">'.LNG_MBCMDS_CMDS .'</td><td><textarea wrap="off"'.$ro.'name="cmds"style="width:100%;height:100">'.htmlentities($cmds).'</textarea></td></tr>'. '</table></tr></td><tr><td colspan="2"align="right">'; if($en)$str.='<input type="submit"class="ism"value="'.$action.'"style="width:100"> '; $str.='<input type="submit"class="ism"value="'.LNG_MBCMDS_BACK.'"style="width:100"onClick="window.location.href=\''.QUERY_STRING.'\';return false;"></td></tr>'; if($en)$str.='</form>'; return $str.'</table>';}function SepFmt ($str){if(strlen($str)>1){$str=str_replace(',','|',trim($str));if ($str[0]!='|')$str='|'.$str;if ($str[strlen($str)-1]!='|')$str.='|';}return $str;}function SepFmtB ($str){if(strlen($str)>1){$str=str_replace('|',',',trim($str));if ($str[0]==',')$str=substr($str,1);$l=strlen($str);if ($str[$l-1]==',')$str=substr($str,0,$l-1);}return $str;}?> |
DetailsAffected Software:WordPress Core Fixed in Version:2.8 Issue Type:Cross Site Scripting Original Code:Found Here DetailsThis week’s bug was subtle. The patch submitted by the developer addresses an XSS bug. Looking at the diff,we see that $title and $selection come from the query string. These values are fixed up before being assigned to a variable. The developers changed the way $title is assigned in the diff. It’s difficult to see why $title needs to be changed,so we’ll ignore that change for now. $selection gives some hints towards XSS. $selection is assigned from the query string value $_GET[‘s’] which is sent through the trim() and aposfix() functions. Immediately following the $selection variable assignment we see the $selection being manipulated with some HTML tags. This is a good indication that $selection will eventually be used to build HTML markup. I usually recommend developers encode/sanitize values as close to the point of consumption as possible,but this case is different. $selection contains HTML tags (the <p>and </p>tags),so encoding the whole value at the point of consumption will also encode those tags. The <p>tags are probably designed to be rendered by the browser. Due to the mixing of HTML tags and regular data,the developer will have to encode the user controlled values during variable assignment. This is exactly what the WordPress developers did in the patch. Developers Solution<?phprequire_once('admin.php');header('Content-Type:' . get_option('html_type') . ';charset=' . get_option('blog_charset'));if ( ! current_user_can('edit_posts') )wp_die( __( 'Cheatin’uh?' ) );function aposfix($text){$translation_table[chr(34)] = '"';$translation_table[chr(38)] = '&';$translation_table[chr(39)] = ''';return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/","&",strtr($text,$translation_table))}function press_it(){// define some basic variables$quick['post_status'] = 'draft';// set as draft first$quick['post_category'] = isset($_REQUEST['post_category']) ? $_REQUEST['post_category']:null;$quick['tax_input'] = isset($_REQUEST['tax_input']) ? $_REQUEST['tax_input']:'';$quick['post_title'] = isset($_REQUEST['title']) ? $_REQUEST['title']:'';$quick['post_content'] = '';// insert the post with nothing in it,to get an ID$post_ID = wp_insert_post($quick,true);$content = isset($_REQUEST['content']) ? $_REQUEST['content']:'';$upload = false;if( !empty($_REQUEST['photo_src']) &¤t_user_can('upload_files') )foreach( (array) $_REQUEST['photo_src'] as $key =>$image)// see if files exist in content - we don't want to upload non-used selected files.if( strpos($_REQUEST['content'],$image) !== false ){$desc = isset($_REQUEST['photo_description'][$key]) ? $_REQUEST['photo_description'][$key]:'';$upload = media_sideload_image($image,$post_ID,$desc);// Replace the POSTED content <img>with correct uploaded ones. Regex contains fix for Magic Quotesif( !is_wp_error($upload) ) $content = preg_replace('/<img ([^>]*)src=\\\?(\"|\')'.preg_quote($image,'/').'\\\?(\2)([^>\/]*)\$http_status_codes=array( 100 =>'Continue', 101 =>'Switching Protocols', 102 =>'Processing', 200 =>'OK', 201 =>'Created', 202 =>'Accepted', 203 =>'Non-Authoritative Information', 204 =>'No Content', 205 =>'Reset Content', 206 =>'Partial Content', 207 =>'Multi-Status', 300 =>'Multiple Choices', 301 =>'Moved Permanently', 302 =>'Found', 303 =>'See Other', 304 =>'Not Modified', 305 =>'Use Proxy', 306 =>'unused', 307 =>'Temporary Redirect', 400 =>'Bad Request', 401 =>'Authorization Required', 402 =>'Payment Required', 403 =>'Forbidden', 404 =>'Not Found', 405 =>'Method Not Allowed', 406 =>'Not Acceptable', 407 =>'Proxy Authentication Required', 408 =>'Request Time-out', 409 =>'Conflict', 410 =>'Gone', 411 =>'Length Required', 412 =>'Precondition Failed', 413 =>'Request Entity Too Large', 414 =>'Request-URI Too Large', 415 =>'Unsupported Media Type', 416 =>'Requested Range Not Satisfiable', 417 =>'Expectation Failed', 418 =>'unused', 419 =>'unused', 420 =>'unused', 421 =>'unused', 422 =>'Unprocessable Entity', 423 =>'Locked', 424 =>'Failed Dependency', 425 =>'No code', 426 =>'Upgrade Required', 500 =>'Internal Server Error', 501 =>'Method Not Implemented', 502 =>'Bad Gateway', 503 =>'Service Temporarily Unavailable', 504 =>'Gateway Time-out', 505 =>'HTTP Version Not Supported', 506 =>'Variant Also Negotiates', 507 =>'Insufficient Storage', 508 =>'unused', 509 =>'unused', 510 =>'Not Extended',);$err_status_codes = array('100'=>array('Continue',''),'101'=>array('Switching Protocols',''),'102'=>array('Processing',''),'200'=>array('OK',''),'201'=>array('Created',''),'202'=>array('Accepted',''),'203'=>array('Non-Authoritative Information',''),'204'=>array('No Content',''),'205'=>array('Reset Content',''),'206'=>array('Partial Content',''),'207'=>array('Multi-Status',''),'300'=>array('Multiple Choices',''),'301'=>array('Moved Permanently','The document has moved <a href="THEREQUESTURI">here</a>.'),'302'=>array('Found','The document has moved <a href="THEREQUESTURI">here</a>.'),'303'=>array('See Other','The answer to your request is located <a href="THEREQUESTURI">here</a>.'),'304'=>array('Not Modified',''),'305'=>array('Use Proxy','This resource is only accessible through the proxy THEREQUESTURIYou will need to configure your client to use that proxy.'),'307'=>array('Temporary Redirect','The document has moved <a href="THEREQUESTURI">here</a>.'),'400' =>array('Bad Request','Your browser sent a request that this server could not understand.'),'401' =>array('Authorization Required','This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g.,bad password),or your browser doesn\'t understand how to supply the credentials required.'),'402' =>array('Payment Required','INTERROR'),'403' =>array('Forbidden','You don\'t have permission to access THEREQUESTURI on this server.'),'404' =>array('Not Found','We couldn\'t find <acronym title="THEREQUESTURI">that uri</acronym>on our server,though it\'s most certainly not your fault.'),'405' =>array('Method Not Allowed','The requested method THEREQMETH is not allowed for the URL THEREQUESTURI.'),'406' =>array('Not Acceptable','An appropriate representation of the requested resource THEREQUESTURI could not be found on this server.'),'407' =>array('Proxy Authentication Required','This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g.,bad password),or your browser doesn\'t understand how to supply the credentials required.'),'408' =>array('Request Time-out','Server timeout waiting for the HTTP request from the client.'),'409' =>array('Conflict','INTERROR'),'410' =>array('Gone','The requested resourceTHEREQUESTURIis no longer available on this server and there is no forwarding address. Please remove all references to this resource.'),'411' =>array('Length Required','A request of the requested method GET requires a valid Content-length.'),'412' =>array('Precondition Failed','The precondition on the request for the URL THEREQUESTURI evaluated to false.'),'413' =>array('Request Entity Too Large','The requested resource THEREQUESTURI does not allow request data with GET requests,or the amount of data provided in the request exceeds the capacity limit.'),'414' =>array('Request-URI Too Large','The requested URL\'s length exceeds the capacity limit for this server.'),'415' =>array('Unsupported Media Type','The supplied request data is not in a format acceptable for processing by this resource.'),'416' =>array('Requested Range Not Satisfiable',''),'417' =>array('Expectation Failed','The expectation given in the Expect request-header field could not be met by this server. The client sent <code>Expect:</code>'),'422' =>array('Unprocessable Entity','The server understands the media type of the request entity,but was unable to process the contained instructions.'),'423' =>array('Locked','The requested resource is currently locked. The lock must be released or proper identification given before the method can be applied.'),'424' =>array('Failed Dependency','The method could not be performed on the resource because the requested action depended on another action and that other action failed.'),'425' =>array('No code','INTERROR'),'426' =>array('Upgrade Required','The requested resource can only be retrieved using SSL. The server is willing to upgrade the current connection to SSL,but your client doesn\'t support it. Either upgrade your client,or try requesting the page using https://'),'500' =>array('Internal Server Error','INTERROR'),'501' =>array('Method Not Implemented','GET to THEREQUESTURI not supported.'),'502' =>array('Bad Gateway','The proxy server received an invalid response from an upstream server.'),'503' =>array('Service Temporarily Unavailable','The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.'),'504' =>array('Gateway Time-out','The proxy server did not receive a timely response from the upstream server.'),'505' =>array('HTTP Version Not Supported','INTERROR'),'506' =>array('Variant Also Negotiates','A variant for the requested resource <code>THEREQUESTURI</code>is itself a negotiable resource. This indicates a configuration error.'),'507' =>array('Insufficient Storage','The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request. There is insufficient free space left in your storage allocation.'),'510' =>array('Not Extended','A mandatory extension policy in the request is not accepted by the server for this resource.'));if (isset($_SERVER['REDIRECT_STATUS'])) $err_code = $_SERVER['REDIRECT_STATUS'];$err_req_meth = $_SERVER['REQUEST_METHOD'];$err_req = htmlentities(strip_tags($_SERVER['REQUEST_URI']));$err_phrase = $err_status_codes[$err_code][0];$err_body = str_replace( array('INTERROR','THEREQUESTURI','THEREQMETH'),array('The server encountered an internal error or misconfiguration and was unable to complete your request.',$err_req,$err_req_meth),$err_status_codes[$err_code][1]);@header("HTTP/1.1 $err_code $err_phrase",1);@header("Status:$err_code $err_phrase",1);if ( $err_code=='400'||$err_code=='403'||$err_code=='405'||$err_code[0]=='5'){@header("Connection:close",1);if ($err_code == '405') @header('Allow:GET,HEAD,POST,OPTIONS,TRACE');echo "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html>\n<head>\n<title>{$err_code}{$err_phrase}</title>\n<h1>{$err_phrase}</h1>\n<p>{$err_body}<br>\n</p>\n</body></html>"} else echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xml:lang="en"lang="en"><head><title>'.$err_code.' '.$err_phrase.'</title><meta http-equiv="content-type"content="text/html;charset=UTF-8"/></head><body><h1>'.$err_code.' '.$err_phrase.'</h1><hr /><p>'.$err_body.'<br /></p>-<pre>-'.print_r($_SERVER,1).'-</pre></body></html>';?>DetailsAffected Software:WordPress Core Fixed in Version:2.2-alpha Issue Type:Cross Site Scripting Original Code:Found Here DetailsA couple of bugs affecting WordPress core here. On line 73,we see that $_SERVER['REQUEST_URI'] is passed to add_query_arg(). From the provided code sample,it’s difficult to see that this results in XSS. The developers addressed this by encoding the return value from add_query_arg(). The second issue starts at wp_get_referer(). This function checks $_REQUEST['_wp_http_referer'] and/or $_SERVER['HTTP_REFERER'] for possible values. This makes is so the attacker has several options for tainting wp_get_referer(). Passing a tainted GET or POST parameter will do the trick. Simply redirecting to the vulnerable WordPress installation from a tainted URL will also taint the value returned from wp_get_referer(). Later,in wp_nonce_ays(),the tainted wp_get_referer() value is passed to the $adminurl variable. $adminurl is then used to build HTML markup in a couple of different places. The WP developers addressed this issue by passing wp_get_referer() before assinging that value to $adminurl. Seems like an effective fix? Well,url values are always a bit tricky. These values have to be encoded before being used to build HTML markup. URLs also have to be validated if they are being passed to a SRC,HREF,or other HTML attribute which causes a browser navigation or request. In this example,the tainted $adminurl is used to populate an A HREF value. The value is encoded,however that encoding doesn’t stop an attacker from passing a javascript:payload url… Developers Solution<?php...snip...function wp_original_referer_field(){echo '<input type="hidden"name="_wp_original_http_referer"value="' . attribute_escape(stripslashes($_SERVER['REQUEST_URI'])) . '"/>'}function wp_get_referer(){foreach ( array($_REQUEST['_wp_http_referer'],$_SERVER['HTTP_REFERER']) as $ref )if ( !empty($ref) )return $ref;return false}function wp_get_original_referer(){if ( !empty($_REQUEST['_wp_original_http_referer']) )return $_REQUEST['_wp_original_http_referer'];return false}function wp_mkdir_p($target){// from php.net/mkdir user contributed notesif (file_exists($target)){if (! @ is_dir($target))return false;elsereturn true}// Attempting to create the directory may clutter up our display.if (@ mkdir($target)){$stat = @ stat(dirname($target));$dir_perms = $stat['mode'] &0007777;// Get the permission bits.@ chmod($target,$dir_perms);return true} else{if ( is_dir(dirname($target)) )return false}// If the above failed,attempt to create the parent node,then try again.if (wp_mkdir_p(dirname($target)))return wp_mkdir_p($target);return false}...snip...function wp_nonce_ays($action){global $pagenow,$menu,$submenu,$parent_file,$submenu_file;$adminurl = get_option('siteurl') . '/wp-admin';if ( wp_get_referer() )-$adminurl = wp_get_referer();+$adminurl = attribute_escape(wp_get_referer());$title = __('WordPress Confirmation');// Remove extra layer of slashes.$_POST = stripslashes_deep($_POST );if ( $_POST ){$q = http_build_query($_POST);$q = explode( ini_get('arg_separator.output'),$q);$html .= "\t<form method='post' action='$pagenow'>\n";foreach ( (array) $q as $a ){$v = substr(strstr($a,'='),1);$k = substr($a,0,-(strlen($v)+1));$html .= "\t\t<input type='hidden' name='". attribute_escape(urldecode($k)) . "' value='". attribute_escape(urldecode($v)) . "' />\n"}$html .= "\t\t<input type='hidden' name='_wpnonce' value='". wp_create_nonce($action) . "' />\n";$html .= "\t\t<div id='message' class='confirm fade'>\n\t\t<p>". wp_specialchars(wp_explain_nonce($action)) . "</p>\n\t\t<p><a href='$adminurl'>". __('No') . "</a><input type='submit' value='". __('Yes') . "' /></p>\n\t\t</div>\n\t</form>\n"} else{-$html .= "\t<div id='message' class='confirm fade'>\n\t<p>". wp_specialchars(wp_explain_nonce($action)) . "</p>\n\t<p><a href='$adminurl'>". __('No') . "</a><a href='". add_query_arg( '_wpnonce',wp_create_nonce($action),$_SERVER['REQUEST_URI'] ) . "'>". __('Yes') . "</a></p>\n\t</div>\n";+ $html .= "\t<div id='message' class='confirm fade'>\n\t<p>". wp_specialchars(wp_explain_nonce($action)) . "</p>\n\t<p><a href='$adminurl'>". __('No') . "</a><a href='". attribute_escape(add_query_arg( '_wpnonce',wp_create_nonce($action),$_SERVER['REQUEST_URI'] )) . "'>". __('Yes') . "</a></p>\n\t</div>\n"}$html .= "</body>\n</html>";wp_die($html,$title)}function wp_die($message,$title = ''){global $wp_locale;header('Content-Type:text/html;charset=utf-8');if ( empty($title) )$title = __('WordPress ›Error');if ( strstr($_SERVER['PHP_SELF'],'wp-admin') )$admin_dir = '';else$admin_dir = 'wp-admin/';?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"<?php if ( function_exists('language_attributes') ) language_attributes();?>><head><title><?php echo $title ?></title><meta http-equiv="Content-Type"content="text/html;charset=utf-8"/><link rel="stylesheet"href="<?php echo $admin_dir;?>install.css"type="text/css"/><?php if ( ('rtl' == $wp_locale->text_direction) ):?><link rel="stylesheet"href="<?php echo $admin_dir;?>install-rtl.css"type="text/css"/><?php endif;?></head><body><h1 id="logo"><img alt="WordPress"src="<?php echo $admin_dir;?>images/wordpress-logo.png"/></h1><p><?php echo $message;?></p></body></html>...snip...DetailsAffected Software:Cubed Fixed in Version:1.0 RC2 Issue Type:Cross Site Scripting Original Code:Found Here DetailsThis week’s patch is a good one. The code sample was basically a library that only contained functions. While there isn’t a blatant vulnerability in the library,there is a startling function called “PrepDataForScript”. Looking at PrepDataForScript,it’s obvious this function is meant to provide some sanitization. Unfortunately,the routine isn’t very robust. When you see things like the code snippet below,you know the developer is headed in the wrong direction: $strData = str_replace(“","</script>",$strData); Fortunately,the Cubed developers were smart enough to realize that this function is dangerous and will probably lead to a false sense of security. Instead of trying to fix it up,they just removed the function entirely. Developers Solution<?php...snip...function QcodoHandleError($__exc_errno,$__exc_errstr,$__exc_errfile,$__exc_errline,$blnExit = true){// If a command is called with "@",then we should returnif (error_reporting() == 0)return;if (class_exists('QApplicationBase'))QApplicationBase::$ErrorFlag = true;global $__exc_strType;if (isset($__exc_strType))return;$__exc_strType = "Error";$__exc_strMessage = $__exc_errstr;switch ($__exc_errno){case E_ERROR:$__exc_strObjectType = "E_ERROR";break;case E_WARNING:$__exc_strObjectType = "E_WARNING";break;case E_PARSE:$__exc_strObjectType = "E_PARSE";break;case E_NOTICE:$__exc_strObjectType = "E_NOTICE";break;case E_STRICT:$__exc_strObjectType = "E_STRICT";break;case E_CORE_ERROR:$__exc_strObjectType = "E_CORE_ERROR";break;case E_CORE_WARNING:$__exc_strObjectType = "E_CORE_WARNING";break;case E_COMPILE_ERROR:$__exc_strObjectType = "E_COMPILE_ERROR";break;case E_COMPILE_WARNING:$__exc_strObjectType = "E_COMPILE_WARNING";break;case E_USER_ERROR:$__exc_strObjectType = "E_USER_ERROR";break;case E_USER_WARNING:$__exc_strObjectType = "E_USER_WARNING";break;case E_USER_NOTICE:$__exc_strObjectType = "E_USER_NOTICE";break;default:$__exc_strObjectType = "Unknown";break}$__exc_strFilename = $__exc_errfile;$__exc_intLineNumber = $__exc_errline;$__exc_strStackTrace = "";$__exc_objBacktrace = debug_backtrace();for ($__exc_intIndex = 0;$__exc_intIndex <count($__exc_objBacktrace);$__exc_intIndex++){$__exc_objItem = $__exc_objBacktrace[$__exc_intIndex];$__exc_strKeyFile = (array_key_exists("file",$__exc_objItem)) ? $__exc_objItem["file"]:"";$__exc_strKeyLine = (array_key_exists("line",$__exc_objItem)) ? $__exc_objItem["line"]:"";$__exc_strKeyClass = (array_key_exists("class",$__exc_objItem)) ? $__exc_objItem["class"]:"";$__exc_strKeyType = (array_key_exists("type",$__exc_objItem)) ? $__exc_objItem["type"]:"";$__exc_strKeyFunction = (array_key_exists("function",$__exc_objItem)) ? $__exc_objItem["function"]:"";$__exc_strStackTrace .= sprintf("#%s %s(%s):%s%s%s()\n",$__exc_intIndex,$__exc_strKeyFile,$__exc_strKeyLine,$__exc_strKeyClass,$__exc_strKeyType,$__exc_strKeyFunction)}if (ob_get_length()){$__exc_strRenderedPage = ob_get_contents();ob_clean()}// Call to display the Error Page (as defined in configuration.inc.php)require(__DOCROOT__ . ERROR_PAGE_PATH);if($blnExit)exit}-function PrepDataForScript($strData){-$strData = str_replace("\\","\\\\",$strData);-$strData = str_replace("\n","\\n",$strData);-$strData = str_replace("\r","\\r",$strData);-$strData = str_replace("\"",""",$strData);-$strData = str_replace("</script>","</script>",$strData);-$strData = str_replace("</Script>","</script>",$strData);-$strData = str_replace("</SCRIPT>","</script>",$strData);-return $strData;-}?>DetailsAffected Software:StatPressCN Fixed in Version:1.9.1 Issue Type:SQL Injection Original Code:Found Here DetailsThis patch was full of interesting tidbits. First,the change log for this patch is as follows: **1.9.1** + fix a flaw allowing a remote cross-site scripting attack
Keep the change list description in mind as we go over the patch submitted by the developers. The submitted patch is pretty simple. There is an additional qualifier set for an if statement that checks to see if $_GET["where$i"] is contained within array $f. It’s difficult to determine whether this is true… but it doesn’t really matter. The second change is an addslashes to $_GET["what$i"] before using the tainted query string parameter to build a dynamic SQL statement. This is to prevent an obvious SQL injection bug in the LIKE operator of the SQL statement. What’s surprising is the developer missed the $_GET["where$i"] query string parameter used to build the SQL statement on the same line. This bug is equally devastating and results in SQL injection against the application. So despite the change log description,this patch is to address a SQL injection bug,NOT an XSS. Looking through the rest of the code,we see XSS (lines 7-9 and 17) and SQL injection bugs (lines 57,65,77) littered throughout the code base. These bugs still exist in the latest version,are not patched,and put users at risk. If you have this plug-in installed,your server and users are at significant risk! Developers Solution </table> <br> <table> <tr><td><table><tr><td><input type=checkbox name=oderbycount value=checked <?php print $_GET['oderbycount'] ?>><?php _e('sort by count if grouped','statpresscn');?></td></tr><tr><td><input type=checkbox name=spider value=checked <?php print $_GET['spider'] ?>><?php _e('include spiders/crawlers/bot','statpresscn');?></td></tr><tr><td><input type=checkbox name=feed value=checked <?php print $_GET['feed'] ?>><?php _e('include feed','statpresscn');?></td></tr></table></td><td width=15></td><td><table><tr> <td><?php _e('Limit results to','statpresscn');?> <select name=limitquery><?php if($_GET['limitquery'] >0){print "<option>".$_GET['limitquery']."</option>"} ?><option>200</option><option>150</option><option>50</option></select> </td></tr><tr><td> </td></tr><tr> <td align=right><input type=submit value=<?php _e('Search','statpresscn');?>name=searchsubmit></td></tr></table></td> </tr> </table><!-- It's strange that the page value should be spc-search,and not others. --> <input type=hidden name=page value='spc-search'><input type=hidden name=statpress_action value=search> </form><br> <?php if(isset($_GET['searchsubmit'])){ # query builder $qry=""; # FIELDS $fields=""; for($i=1;$i<=5;$i++){- if($_GET["where$i"] != ''){+if($_GET["where$i"] != '' &&array_key_exists($_GET["where$i"],$f)){//??where?????? $fields.=$_GET["where$i"].",";} } $fields=rtrim($fields,","); # WHERE $where="WHERE 1=1"; if($_GET['spider'] != 'checked'){$where.="AND spider=''";} if($_GET['feed'] != 'checked'){$where.="AND feed=''";} for($i=1;$i<=5;$i++){if(($_GET["what$i"] != '') &&($_GET["where$i"] != '')){- $where.="AND ".$_GET["where$i"]."LIKE '%".$_GET["what$i"]."%'";+$where.="AND ".$_GET["where$i"]."LIKE '%".addslashes($_GET["what$i"])."%'";//addslashes?????? } } # ORDER BY $orderby=""; for($i=1;$i<=5;$i++){if(($_GET["sortby$i"] == 'checked') &&($_GET["where$i"] != '')){$orderby.=$_GET["where$i"].',';} } # GROUP BY $groupby=""; for($i=1;$i<=5;$i++){if(($_GET["groupby$i"] == 'checked') &&($_GET["where$i"] != '')){$groupby.=$_GET["where$i"].',';} } if($groupby != ''){$grouparray = explode(",",rtrim($groupby,','));$groupby="GROUP BY ".rtrim($groupby,',');$fields.=",count(*) as totale";if($_GET['oderbycount'] == 'checked'){$orderby="totale DESC,".$orderby;} } if($orderby != ''){$orderby="ORDER BY ".rtrim($orderby,',');} $limit="LIMIT ".$_GET['limitquery']; # Results print "<h2>".__('Results','statpresscn')."</h2>"; $sql="SELECT $fields FROM $table_name $where $groupby $orderby $limit;"; //print "$sql<br>"; print "<table class='widefat'><thead><tr>"; for($i=1;$i<=5;$i++){if($_GET["where$i"] != ''){print "<th scope='col'>";if((count($grouparray)>0)&&in_array($_GET["where$i"],$grouparray)){print "<font color=red>";} print ucfirst($f[$_GET["where$i"]]);if((count($grouparray)>0)&&in_array($_GET["where$i"],$grouparray)){print "</font>";} print "</th>";} } if($groupby != ''){print "<th scope='col'><font color=red>".__('Count','statpresscn')."</font></th>";} print "</tr></thead><tbody id='the-list'>"; $qry=$wpdb->get_results($sql,ARRAY_N); $cloumnscount = count($wpdb->get_col_info("name")); foreach ($qry as $rk){print "<tr>";for($i=1;$i<=$cloumnscount;$i++){print "<td>";if($_GET["where$i"] == 'urlrequested'){print "<a href=".heart5_config_url($rk[$i-1])."target=_heart5>";print iri_StatPress_Decode($rk[$i-1]);print "</a>";} else{print $rk[$i-1];}// print $rk[$i-1];print "</td>";} print "</tr>"; } print "</table>"; print "<br /><br /><font size=1 color=gray>sql:$sql</font>"; }?></div>DetailsAffected Software:Lazyest-Gallery Fixed in Version:0.9 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DetailsFor most security issues,I give the developer the benefit of the doubt. It’s tough to keep track of all the corner cases and security nuances. For this diff however,there is no excuse. First,let’s cover what the patch fixes. On line 18,the developer was taking a tainted value passed via query string parameter and using that value to build HTML markup. This is XSS in its most classic form. Also,on line 58 the same tainted input is used to build the SRC attribute for an image tag,also resulting in XSS. The developer chose to encode both of these tainted values before using them in the HTML output. Now,let’s talk about the problems with this patch. First,the tainted value used to build the SRC attribute for an image tag needs additional validation. SRC attributes are tricky as they usually cause the browser to issue a request. Escaping the tainted SRC value only prevents the attacker from breaking out of the attribute and injecting their own HTML. Escaping doesn’t prevent the attacker from passing a well formed URI like javascript:javascript-payload-here. I can let the developer slide on this one… chalk it up as a lesson on corner cases. Now,if you look at the patched line,you’ll see that the ALT attribute for the same image tag also contains a XSS vulnerability. Yes,the developer missed a XSS vulnerability that is less than 5 characters away from a fixed XSS vulnerability. This also shows that the developer never tested the patch. The tainted query string parameter is the same for all the vulnerable sections. If the developer tried to test this patch,they would have discovered they were still exposed… Developers Solution<?php// Don't remove this lines:require_once('../../../wp-blog-header.php');global $lg_gallery;?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type"content="<?php bloginfo('html_type');?>;charset=<?php bloginfo('charset');?>"/><meta name="generator"content="WordPress <?php bloginfo('version');?>"/>-<title><?php echo $_GET['image'] ?></title>+<title><?php echo esc_html($_GET['image']) ?></title><style type="text/css">body{text-align:center;margin:0;padding:0}img{border:none}</style><script type="text/javascript">function WinWidth(){if (window.innerWidth!=window.undefined) return window.innerWidth;if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth;if (document.body) return document.body.clientWidth;return window.undefined}function WinHeight(){if (window.innerHeight!=window.undefined) return window.innerHeight;if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight;if (document.body) return document.body.clientHeight;return window.undefined}function FitPic(){iWidth=WinWidth();iHeight=WinHeight();iWidth = document.images[0].width - iWidth;iHeight = document.images[0].height - iHeight;window.resizeBy((iWidth),(iHeight))self.focus()} </script></head><body onload="FitPic()"><a href="javascript:self.close()"title="<?php _e('Click to close',$lg_text_domain);?>">-<img src="<?php echo str_replace("","%20",$lg_gallery->address.$_GET['folder'].$_GET['image']);?>"alt="<?php echo $_GET['image'];?>"/>+<img src="<?php echo str_replace("","%20",$lg_gallery->address.esc_attr($_GET['folder']).esc_attr($_GET['image']));?>"alt="<?php echo $_GET['image'];?>"/></a></body></html><?php?>DetailsAffected Software:WPhone Plug-in Fixed in Version:1.5.2 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DetailsThis bug is a straightforward XSS bug. Once again,we see the familiar $_SERVER['PHP_SELF'] variable being echoed back to the user without any encoding. The fix is simple,remove the value for the ACTION form attribute completely. This removes the need for any type of sanitization and ensures the form is POSTed to the URL that is hosting the form. On a side note,many developers reduce the testing/defenses implemented in web pages designed for mobile clients. For some reason,it’s tempting to assume web pages designed for mobile applications have less exposure. Less exposure is obviously not the case;web pages designed for mobile clients have just as much exposure as web pages designed for normal web browsers. Please ensure your security diligence and security test cases cover your mobile attack surface. Just because the devices are smaller,that doesn’t make your attack surface is smaller too! Developers Solution<?php# Visit this file in your browser to simulate a mobile device's screensize via an <iframe>$devices = array('iphone_p' =>array('type' =>'iPhone:portrait (320x480)','width' =>320,'height' =>480),'iphone_l' =>array('type' =>'iPhone:landscape (480x320)','width' =>480,'height' =>320),'moto' =>array('type' =>'Motorola phone/browser (RAZR,v551,etc)','width' =>176,'height' =>220),'n80' =>array('type' =>'Nokia N80 (N60WebKit)','width' =>352,'height' =>416));if ( (int) $_REQUEST['w'] &&(int) $_REQUEST['h'] ){$choice = array('type' =>"Custom size ({$_REQUEST['w']}x{$_REQUEST['h']})",'width' =>$_REQUEST['w'],'height' =>$_REQUEST['h'])}elseif ( $devices[$_REQUEST['d']] )$choice = $devices[$_REQUEST['d']];else $choice = $devices['iphone_p'];?><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type"content="text/html;charset=UTF-8"><title>WPhone iFramer test tool:<?php echo $choice['type'];?></title></head><body>-<form action="<?php echo $_SERVER['PHP_SELF'];?>"method="get">+ <form action=""method="get"><label for="h">CHOOSE</label><select name="d"id="d"><option></option><?phpforeach ( $devices as $this_d_key =>$this_d ){$selected = ( $_REQUEST['d'] == $this_d_key ) ? 'selected':'';echo '<option value="' . $this_d_key . '"' . $selected . '>' . $this_d['type'] . '</option>' . "\n\t\t\t"}echo "\n";?></select><br />OR INPUT<label for="w">Width</label><input type="text"name="w"id="w"value=""size="5"/>x<label for="h">Height</label><input type="text"name="h"id="h"value=""size="5"/><br /><input type="submit"name="submit"value="view"/></form><h2><?php echo $choice['type'];?></h2><iframe src="../../../wp-login.php"width="<?php echo $choice['width'];?>"height="<?php echo $choice['height'];?>">your browser does not support iframes.</iframe></body></html> | |