| 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: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:Comment-Rating Plugin Fixed in Version:2.9.24 Issue Type:SQL Injection (SQLi) Original Code:Found Here DetailsThis week’s vulnerability was a tricky one. The bug patched in this change list affected the Comment-Rating plugin for WordPress (fixed in 2.9.24). Let’s take the bug step by step. First,the application takes a user/attacker supplied value and runs it through an escaping function here (line 9): $k_id = strip_tags($wpdb->escape($_GET['id'])); So,$k_id is now tainted and contains an escaped value provided by the attacker. A few lines later,we see the following code: if($k_id &&$k_action &&$k_path){ //Check to see if the comment id exists and grab the rating $query = “SELECT * FROM `$table_name` WHERE ck_comment_id = $k_id”; $result = mysql_query($query); The code above checks for a specific condition (which is a condition controllable by the attacker) then proceeds to build and execute a SQL query. On line 22 we see $k_id is used to build a dynamic SQL statement. Variables usage within stings are valid in PHP (http://php.net/manual/en/language.types.string.php –see Variable parsing). $k_id is escaped so we should be ok here…right? Actually,in this case escaping isn’t sufficient to prevent SQL injection. Escaping functions typically work by preventing a variable value from breaking out of quotes,unfortunately in this case there are no quotes to break out of. $k_id is designed to be a numeric value not a string,so there is no need to encapsulate the $k_id value in quotes. Although $k_id is designed to be numeric,there was nothing that would prevent an attacker from providing an arbitrary value for $k_id. For example,an attacker could provide a value like this for $k_id: 99999 union select uname,passwd from users As you can see,there are no special characters (double quotes,single quotes,or database escape characters) in the string above that would have been escaped by a database escaping function. When used to build the $query variable,we end up with: $query = “SELECT * FROM `$table_name` WHERE ck_comment_id = 99999 union select uname,passwd from users“; The developers addressed this vulnerability by validating that $k_id is indeed numeric before using the value to build a dynamic SQL statement. Developers Solution<?phprequire_once('../../../wp-config.php');require_once('../../../wp-includes/functions.php');// CSRF attack protection. Check the Referal field to be the same// domain of the script$k_id = strip_tags($wpdb->escape($_GET['id']));$k_action = strip_tags($wpdb->escape($_GET['action']));$k_path = strip_tags($wpdb->escape($_GET['path']));$k_imgIndex = strip_tags($wpdb->escape($_GET['imgIndex']));+// prevent SQL injection+if (!is_numeric($k_id)) die('error|Query error');$table_name = $wpdb->prefix . 'comment_rating';$comment_table_name = $wpdb->prefix . 'comments';if($k_id &&$k_action &&$k_path){ //Check to see if the comment id exists and grab the rating $query = "SELECT * FROM `$table_name` WHERE ck_comment_id = $k_id"; $result = mysql_query($query);if(!$result){die('error|mysql:'.mysql_error());} if(mysql_num_rows($result)){$duplicated = 0;// used as a counter to off set duplicated votes if($row = @mysql_fetch_assoc($result)){if(strstr($row['ck_ips'],getenv("REMOTE_ADDR"))){ // die('error|You have already voted on this item!'); // Just don't count duplicated votes $duplicated = 1; $ck_ips = $row['ck_ips']; } else{ $ck_ips = $row['ck_ips'] . ',' . getenv("REMOTE_ADDR");// IPs are separated by ',' } } $total = $row['ck_rating_up'] - $row['ck_rating_down'];if($k_action == 'add'){ $rating = $row['ck_rating_up'] + 1 - $duplicated; $direction = 'up'; $total = $total + 1 - $duplicated;} elseif($k_action == 'subtract'){ $rating = $row['ck_rating_down'] + 1 - $duplicated; $direction = 'down'; $total = $total - 1 + $duplicated;} else{ die('error|Try again later');//No action given. } if (!$duplicated){ $query = "UPDATE `$table_name` SET ck_rating_$direction = '$rating',ck_ips = '". $ck_ips . "' WHERE ck_comment_id = $k_id"; $result = mysql_query($query); if(!$result) { // die('error|query '.$query); die('error|Query error'); } // Now duplicated votes will not if(!mysql_affected_rows()) { die('error|affected '. $rating); } $karma_modified = 0; if (get_option('ckrating_karma_type') == 'likes' &&$k_action == 'add'){ $karma_modified = 1;$karma = $rating; } if (get_option('ckrating_karma_type') == 'dislikes' &&$k_action == 'subtract'){ $karma_modified = 1;$karma = $rating; } if (get_option('ckrating_karma_type') == 'both'){ $karma_modified = 1;$karma = $total; } if ($karma_modified){ $query = "UPDATE `$comment_table_name` SET comment_karma = '$karma' WHERE comment_ID = $k_id"; $result = mysql_query($query); if(!$result) die('error|Comment Query error'); } } } else{ die('error|Comment doesnt exist');//Comment id not found in db,something wrong ? }} else{ die('error|Fatal:html format error')}// Add the + sign,if ($total >0){$total = "+$total";}//This sends the data back to the js to process and show on the page// The dummy field will separate out any potential garbage that// WP-superCache may attached to the end of the return.echo("done|$k_id|$rating|$k_path|$direction|$total|$k_imgIndex|dummy");?>DetailsAffected Software:FreePBX Fixed in Version:2.9 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DescriptionTo be honest,I was a little confused by this week’s patch. There are several XSS bugs in this code. Originally,the vulnerable code would take a tainted $_REQUEST value (a value from a GET,POST,or cookie) and assign the tainted value to a couple of different PHP variables ($description and $notes in particular). The application then uses of these tainted values on lines 136 and 140,resulting in XSS. The developer addressed these XSS issues by html encoding the $_REQUEST values before assigning them to PHP variables. In the code mentioned above,the developer decided to encode/sanitize at the point of assignment (as opposed to the point of consumption). There are differing perspectives as to whether one should encode/sanitize upon assignment or consumption,but the truth is both methods work. What’s confusing is the code sample contains many symptoms that are exactly like the vulnerable code patched by this security patch. $type,$action,$old_custom_dest,and $custom_dest are all set in exactly the same way the patched assignments were. For some reason,the developer chose to ignore these assignments even though they are only a few lines away. Also,instead of encoding at the point of assignment (like they did for $description and $notes),the developer chose to change styles and encode at the point of consumption for one of the tainted variables (see line 96 and 97). What’s even more confusing is only 4 lines later,we see the developer missed the same tainted variable used in an echo and failed to encode the tainted $custom_dest variable resulting in XSS. Lines 77 – 79 also contain XSS vulnerabilities that were missed in this patch. Developers Solution<?php$tabindex = 0;$display = 'customdests';$type = isset($_REQUEST['type']) ? $_REQUEST['type']:'tool';$action = isset($_REQUEST['action']) ? $_REQUEST['action']:'';if (isset($_REQUEST['delete'])) $action = 'delete';$old_custom_dest = isset($_REQUEST['old_custom_dest']) ? $_REQUEST['old_custom_dest']:'';$custom_dest = isset($_REQUEST['extdisplay']) ? $_REQUEST['extdisplay']:'';-$description = isset($_REQUEST['description']) ? $_REQUEST['description']:'';-$notes = isset($_REQUEST['notes']) ? $_REQUEST['notes']:'';+$description = isset($_REQUEST['description']) ? htmlentities($_REQUEST['description']):'';+$notes = isset($_REQUEST['notes']) ? htmlentities($_REQUEST['notes']):'';switch ($action){case 'add':if (customappsreg_customdests_add($custom_dest,$description,$notes)){needreload();redirect_standard()} else{$custom_dest=''}break;case 'edit':if (customappsreg_customdests_edit($old_custom_dest,$custom_dest,$description,$notes)){needreload();redirect_standard('extdisplay')}break;case 'delete':customappsreg_customdests_delete($custom_dest);needreload();redirect_standard();break}?></div><div class="rnav"><ul><?php echo '<li><a href="config.php?display='.$display.'&type='.$type.'">'._('Add Custom Destination').'</a></li>';foreach (customappsreg_customdests_list() as $row){$descr = $row['description'] != '' ? $row['description']:'('.$row['custom_dest'].')';echo '<li><a href="config.php?display='.$display.'&type='.$type.'&extdisplay='.$row['custom_dest'].'"class="">'.$descr.'</a></li>'}?></ul></div><div class="content"><?phpif ($custom_dest != ''){// load$usage_list = framework_display_destination_usage(customappsreg_customdests_getdest($custom_dest));$row = customappsreg_customdests_get($custom_dest);$description = $row['description'];$notes = $row['notes'];$disp_description = $row['description'] != '' ? $row['description']:'('.$row['custom_dest'].')';echo "<h2>"._("Edit:")."$disp_description"."</h2>"} else{echo "<h2>"._("Add Custom Destination")."</h2>"}$helptext = _("Custom Destinations allows you to register your custom destinations that point to custom dialplans and will also 'publish' these destinations as available destinations to other modules. This is an advanced feature and should only be used by knowledgeable users. If you are getting warnings or errors in the notification panel about CUSTOM destinations that are correct,you should include them here. The 'Unknown Destinations' chooser will allow you to choose and insert any such destinations that the registry is not aware of into the Custom Destination field.");echo $helptext;?><form name="editCustomDest"action="<?php $_SERVER['PHP_SELF'] ?>"method="post"onsubmit="return checkCustomDest(editCustomDest);"><input type="hidden"name="extdisplay"value="<?php echo $custom_dest;?>"><input type="hidden"name="old_custom_dest"value="<?php echo $custom_dest;?>"><input type="hidden"name="action"value="<?php echo ($custom_dest != '' ? 'edit':'add');?>"><table><tr><td colspan="2"><h5><?php echo ($custom_dest ? _("Edit Custom Destination"):_("Add Custom Destination")) ?><hr></h5></td></tr><tr><td><a href="#"class="info"><?php echo _("Custom Destination")?>:<span><?phpecho _("This is the Custom Destination to be published. It should be formatted exactly as you would put it in a goto statement,with context,exten,priority all included. An example might look like:<br />mycustom-app,s,1");if (!empty($usage_list)){echo "<br />"._("READONLY WARNING:Because this destination is being used by other module objects it can not be edited. You must remove those dependencies in order to edit this destination,or create a new destination to use")}?></span></a></td><?phpif (!empty($usage_list)){?>-<td><b><?php echo $custom_dest;?></b></td>+ <td><b><?php echo htmlentities($custom_dest);?></b></td><?php} else{?><td><input size="30"type="text"name="extdisplay"id="extdisplay"value="<?php echo $custom_dest;?>"tabindex="<?php echo ++$tabindex;?>"></td><?php}?></tr><?phpif (empty($usage_list)){?><tr><td><a href=# class="info"><?php echo _("Destination Quick Pick")?><span><?php echo _("Choose un-identified destinations on your system to add to the Custom Destination Registry. This will insert the chosen entry into the Custom Destination box above.")?></span></a></td><td><select onChange="insertDest();"id="insdest"tabindex="<?php echo ++$tabindex;?>"><option value=""><?php echo _("(pick destination)")?></option><?php$results = customappsreg_customdests_getunknown();foreach ($results as $thisdest){echo "<option value='$thisdest'>$thisdest</option>\n"}?></select></td></tr><?php}?><tr><td><a href="#"class="info"><?php echo _("Description")?>:<span><?php echo _("Brief Description that will be published to modules when showing destinations. Example:My Weather App")?></span></a></td><td><input size="30"type="text"name="description"value="<?php echo $description;?>"tabindex="<?php echo ++$tabindex;?>"></td></tr><tr><td valign="top"><a href="#"class="info"><?php echo _("Notes")?>:<span><?php echo _("More detailed notes about this destination to help document it. This field is not used elsewhere.")?></span></a></td><td><textarea name="notes"cols="23"rows="6"tabindex="<?php echo ++$tabindex;?>"><?php echo $notes;?></textarea></td></tr><tr><td colspan="2"><br><input name="Submit"type="submit"value="<?php echo _("Submit Changes")?>"tabindex="<?php echo ++$tabindex;?>"><?php if ($custom_dest != ''){echo ' <input name="delete"type="submit"value="'._("Delete").'">';} ?></td><?phpif ($custom_dest != ''){if (!empty($usage_list)){?><tr><td colspan="2"><a href="#"class="info"><?php echo $usage_list['text']?>:<span><?php echo $usage_list['tooltip']?></span></a></td></tr><?php}}?></tr></table></form>...snip...</script>DetailsAffected Software:BezahlCode-Generator Fixed in Version:1.1 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DescriptionA couple straightforward XSS bugs. $_REQUEST will create an associative array which contains the contents of $_GET,$_POST,and $_COOKIE which are all user/attacker controllable. These variables are then used to create HTML markup. Security bugs are caused by many different reasons. When auditing code for security issues,if you come across issues like the ones shown below its highly likely that the developer simply doesn’t understand the security risk they created. It might be a good idea to review other change lists associated with this developer as they will likely contain similar code symptoms. This type of issue is also indicative of lack of security awareness. The developer here could use some security education about various security issues along with some tips on preventing these types of security issues in the future. Developers Solution<?php if ($data!='') {?><img src="/generator/?generate=<?php echo urlencode($data)?>"/><?php }?></div><br/><form action="/generator/"name="wizard"method="post"class="BezahlCodeForm"><label for="singlepayment"><input type="radio"id="singlepayment"name="gen_type"value="singlepayment"<?php if($_REQUEST['gen_type']=="singlepayment"|| empty($_REQUEST['gen_type'])) echo 'checked="checked"'?>/>Überweisung</label><br /><label for="singlepaymentspende"><input type="radio"id="singlepaymentspende"name="gen_type"value="singlepaymentspende"<?php if($_REQUEST['gen_type']=="singlepaymentspende") echo 'checked="checked"'?>/>Spendenzahlung</label><br /><label for="singledirectdebit"><input type="radio"id="singledirectdebit"name="gen_type"value="singledirectdebit"<?php if($_REQUEST['gen_type']=="singledirectdebit") echo 'checked="checked"'?>/>Lastschrift</label><br />-Name:<br /><input type="text"tooltipText="Format:DTAUS Text"id="gen_name"onblur="checkInput(this,'dtaus')"name="gen_name"maxlength="27"value="<?= isset($_REQUEST['gen_name'])?$_REQUEST['gen_name']:""?>">+Name:<br /><input type="text"tooltipText="Format:DTAUS Text"id="gen_name"onblur="checkInput(this,'dtaus')"name="gen_name"maxlength="27"value="<?= isset($_REQUEST['gen_name'])?htmlspecialchars($_REQUEST['gen_name']):""?>"><br />-Kontonummer:<br /><input type="text"tooltipText="Format:Ganzzahl z.B. 1234"id="gen_account"onblur="checkInput(this,'ganzzahl')"name="gen_account"value="<?= isset($_REQUEST['gen_account'])?$_REQUEST['gen_account']:""?>">+Kontonummer:<br /><input type="text"tooltipText="Format:Ganzzahl z.B. 1234"id="gen_account"onblur="checkInput(this,'ganzzahl')"name="gen_account"value="<?= isset($_REQUEST['gen_account'])?htmlspecialchars($_REQUEST['gen_account']):""?>"><br />-BLZ:<br /><input type="text"tooltipText="Format:Ganzzahl z.B. 1234"id="gen_BNC"onblur="checkInput(this,'ganzzahl')"name="gen_BNC"value="<?= isset($_REQUEST['gen_BNC'])?$_REQUEST['gen_BNC']:""?>">+BLZ:<br /><input type="text"tooltipText="Format:Ganzzahl z.B. 1234"id="gen_BNC"onblur="checkInput(this,'ganzzahl')"name="gen_BNC"value="<?= isset($_REQUEST['gen_BNC'])?htmlspecialchars($_REQUEST['gen_BNC']):""?>"><br />-Betrag in Euro (z.B. 1234,50) <br /><input type="text"tooltipText="Format:Dezimalzahl z.B. 1234,50"onblur="checkInput(this,'dezimalzahl')"id="gen_amount"name="gen_amount"value="<?= isset($_REQUEST['gen_amount'])?$_REQUEST['gen_amount']:""?>">+Betrag in Euro (z.B. 1234,50) <br /><input type="text"tooltipText="Format:Dezimalzahl z.B. 1234,50"onblur="checkInput(this,'dezimalzahl')"id="gen_amount"name="gen_amount"value="<?= isset($_REQUEST['gen_amount'])?htmlspecialchars($_REQUEST['gen_amount']):""?>"><br />-Verwendungszweck:<br /><input type="text"id="gen_reason"tooltipText="Format:DTAUS Text"onblur="checkInput(this,'dtaus')"name="gen_reason"maxlength="54"value="<?= isset($_REQUEST['gen_reason'])?$_REQUEST['gen_reason']:""?>">+Verwendungszweck:<br /><input type="text"id="gen_reason"tooltipText="Format:DTAUS Text"onblur="checkInput(this,'dtaus')"name="gen_reason"maxlength="54"value="<?= isset($_REQUEST['gen_reason'])?htmlspecialchars($_REQUEST['gen_reason']):""?>"><br/><input type="button"value="Erstellen"onclick='javascript:generateImage();'></form><?php if(!(get_option("bezahlcode_showlink") == "hidden")){?><br /><span class="bezahlCodeLink">Weitere Informationen:<a href="http://www.bezahlcode.de"title="BezahlCode - Schnell,einfach und sicher bezahlen"target="_blank">www.bezahlcode.de</a></span><?php } ?></div><script type="text/javascript">var tooltipObj = new DHTMLgoodies_formTooltip();tooltipObj.initFormFieldTooltip();</script>DetailsAffected Software:PunBB Fixed in Version:1.3.2 Issue Type:SMTP Command Injection Original Code:Found Here DescriptionInteresting bug here. In 2008,Stefan Esser reported a bug to the PunBB team which described a SMTP command injection vulnerability. If we look at the code below,we see that PunBB opens a socket connection to a SMTP host and passes various user/attacker controlled values to the SMTP server. Because of this setup,it is possible to craft a SMTP message that tricks the SMTP server into thinking the data provided for the message is completed,and executes any data that follows as SMTP commands. The attacker accomplished this by injecting Carriage Return and Line Feed characters following by a period character on a line by itself (as defined in RFC 821 – SMTP). The PunBB developers addressed this vulnerability by sanitizing CRLFs and period characters. The Web Application Hackers Handbook (by Dafydd Stuttard) describes various forms of SMTP injection in a pretty comprehensive manner. If the PunBB developers used the test cases described by Dafydd in his book would have likely identified this vulnerability before shipping. Here’s a sample from the Web Application Hackers Handbook that talks about SMTP injection (see section 8.2) Developers Solution<?php...snip...function smtp_mail($to,$subject,$message,$headers = ''){global $pun_config;$recipients = explode(',',$to);+// Sanitize the message+$message = str_replace("\r\n.","\r\n..",$message);+$message = (substr($message,0,1) == '.' ? '.'.$message:$message);// Are we using port 25 or a custom port?if (strpos($pun_config['o_smtp_host'],':') !== false)list($smtp_host,$smtp_port) = explode(':',$pun_config['o_smtp_host']);else{$smtp_host = $pun_config['o_smtp_host'];$smtp_port = 25}if (!($socket = fsockopen($smtp_host,$smtp_port,$errno,$errstr,15)))error('Could not connect to smtp host "'.$pun_config['o_smtp_host'].'"('.$errno.') ('.$errstr.')',__FILE__,__LINE__);server_parse($socket,'220');if ($pun_config['o_smtp_user'] != '' &&$pun_config['o_smtp_pass'] != ''){fwrite($socket,'EHLO '.$smtp_host."\r\n");server_parse($socket,'250');fwrite($socket,'AUTH LOGIN'."\r\n");server_parse($socket,'334');fwrite($socket,base64_encode($pun_config['o_smtp_user'])."\r\n");server_parse($socket,'334');fwrite($socket,base64_encode($pun_config['o_smtp_pass'])."\r\n");server_parse($socket,'235')}else{fwrite($socket,'HELO '.$smtp_host."\r\n");server_parse($socket,'250')}fwrite($socket,'MAIL FROM:<'.$pun_config['o_webmaster_email'].'>'."\r\n");server_parse($socket,'250');$to_header = 'To:';@reset($recipients);while (list(,$email) = @each($recipients)){fwrite($socket,'RCPT TO:<'.$email.'>'."\r\n");server_parse($socket,'250');$to_header .= '<'.$email.'>,'}fwrite($socket,'DATA'."\r\n");server_parse($socket,'354');fwrite($socket,'Subject:'.$subject."\r\n".$to_header."\r\n".$headers."\r\n\r\n".$message."\r\n");fwrite($socket,'.'."\r\n");server_parse($socket,'250');fwrite($socket,'QUIT'."\r\n");fclose($socket);return true}DetailsAffected Software:PunBB Fixed in Version:2.1 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DescriptionThis week’s vulnerability was a XSS bug in PunBB. PunBB was taking an un-trusted value directly from the POST parameter ($_POST[‘prune_sticky’]) and echoing the un-trusted value directly into a value attribute for a hidden form input field. You can see the XSS bug in line 98. This echoing of un-trusted input results in XSS. The PunBB developers did something I really like here. Instead of fixing the single instance of XSS and moving on,the PunBB developers went a step further and hardened the use of $_POST[‘prune_sticky’]. Instead of allowing users/attacker to provide arbitrary values for $_POST[’prune_sticky’] they restricted the acceptable values to 1 or 0. You can see this fix in line 11. This is a perfect example of root cause analysis in action. The PunBB developers took a few minutes to understand how the application uses $_POST[‘ prune_sticky’] and adjusted the application behavior to protect against other attacks while being transparent to the user. This patch submitted by the PunBB developers goes a long way in protecting their customers and is a great example of being smart about security fixes. Developers Solution<?php... <snip>...if (isset($_GET['action']) || isset($_POST['prune']) || isset($_POST['prune_comply'])){if (isset($_POST['prune_comply'])){confirm_referrer('admin_prune.php');$prune_from = $_POST['prune_from'];+$prune_sticky = isset($_POST['prune_sticky']) ? '1':'0';$prune_days = intval($_POST['prune_days']);$prune_date = ($prune_days) ? time() - ($prune_days*86400):-1;@set_time_limit(0);if ($prune_from == 'all'){$result = $db->query('SELECT id FROM '.$db->prefix.'forums') or error('Unable to fetch forum list',__FILE__,__LINE__,$db->error());$num_forums = $db->num_rows($result);for ($i = 0;$i <$num_forums;++$i){$fid = $db->result($result,$i);-prune($fid,$_POST['prune_sticky'],$prune_date);+prune($fid,$prune_sticky,$prune_date);update_forum($fid)}}else{$prune_from = intval($prune_from);-prune($prune_from,$_POST['prune_sticky'],$prune_date);+prune($fid,$prune_sticky,$prune_date);update_forum($prune_from)}// Locate any "orphaned redirect topics"and delete them$result = $db->query('SELECT t1.id FROM '.$db->prefix.'topics AS t1 LEFT JOIN '.$db->prefix.'topics AS t2 ON t1.moved_to=t2.id WHERE t2.id IS NULL AND t1.moved_to IS NOT NULL') or error('Unable to fetch redirect topics',__FILE__,__LINE__,$db->error());$num_orphans = $db->num_rows($result);if ($num_orphans){for ($i = 0;$i <$num_orphans;++$i)$orphans[] = $db->result($result,$i);$db->query('DELETE FROM '.$db->prefix.'topics WHERE id IN('.implode(',',$orphans).')') or error('Unable to delete redirect topics',__FILE__,__LINE__,$db->error())}redirect('admin_prune.php','Posts pruned. Redirecting …')}$prune_days = $_POST['req_prune_days'];if (!@preg_match('#^\d+$#',$prune_days))message('Days to prune must be a positive integer.');$prune_date = time() - ($prune_days*86400);$prune_from = $_POST['prune_from'];// Concatenate together the query for counting number or topics to prune$sql = 'SELECT COUNT(id) FROM '.$db->prefix.'topics WHERE last_post<'.$prune_date.' AND moved_to IS NULL';-if ($_POST['prune_sticky'] == '0')+if (!$prune_sticky)$sql .= ' AND sticky=\'0\'';if ($prune_from != 'all'){$prune_from = intval($prune_from);$sql .= ' AND forum_id='.$prune_from;// Fetch the forum name (just for cosmetic reasons)$result = $db->query('SELECT forum_name FROM '.$db->prefix.'forums WHERE id='.$prune_from) or error('Unable to fetch forum name',__FILE__,__LINE__,$db->error());$forum = '"'.pun_htmlspecialchars($db->result($result)).'"'}else$forum = 'all forums';$result = $db->query($sql) or error('Unable to fetch topic prune count',__FILE__,__LINE__,$db->error());$num_topics = $db->result($result);if (!$num_topics)message('There are no topics that are '.$prune_days.' days old. Please decrease the value of "Days old"and try again.');$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Prune';require PUN_ROOT.'header.php';generate_admin_menu('prune');?><div class="blockform"><h2><span>Prune</span></h2><div class="box"><form method="post"action="admin_prune.php?action=foo"><div class="inform"><input type="hidden"name="prune_days"value="<?php echo $prune_days ?>"/>-<input type="hidden"name="prune_sticky"value="<?php echo $_POST['prune_sticky'] ?>"/>+<input type="hidden"name="prune_sticky"value="<?php echo $prune_sticky ?>"/><input type="hidden"name="prune_from"value="<?php echo $prune_from ?>"/><fieldset><legend>Confirm prune posts</legend><div class="infldset"><p>Are you sure that you want to prune all topics older than <?php echo $prune_days ?>days from <?php echo $forum ?>? (<?php echo $num_topics ?>topics)</p><p>WARNING! Pruning posts deletes them permanently.</p></div></fieldset></div><p><input type="submit"name="prune_comply"value="Prune"/><a href="javascript:history.go(-1)">Go back</a></p></form></div></div><div class="clearer"></div></div>... <snip>...DetailsAffected Software:WP-Slimbox 2 Fixed in Version:1.0.1 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DescriptionA bit of a head fake here. There are a lot of variable assignments in this code. Lots of variable assignments results in a lot of tracing during security code audits. As a variable is set with an untrusted value,it becomes tainted. Following that variable until you find exactly where its being used is crucial in understanding whether a security bug exists or not. Any one of those variable assignments could easily result in a major security vulnerability. In this week’s example,the vulnerable line came before the massive set of variable assignments. Once again,we see PHP_SELF being used to create a URL. Instead of trying to encode the value before using it in markup,the developer chose to remove the reference to PHP_SELF. Developers Solution<?php$easingArray = array(swing,easeInQuad,easeOutQuad,easeInOutQuad,easeInCubic,easeOutCubic,easeInOutCubic,easeInQuart,easeOutQuart,easeInOutQuart,easeInQuint,easeOutQuint,easeInOutQuint,easeInSine,easeOutSine,easeInOutSine,easeInExpo,easeOutExpo,easeInOutExpo,easeInCirc,easeOutCirc,easeInOutCirc,easeInElastic,easeOutElastic,easeInOutElastic,easeInBack,easeOutBack,easeInOutBack,easeInBounce,easeOutBounce,easeInOutBounce);$overlayOpacity = array(0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1);$msArray = array(1,100,200,300,400,500,600,700,800,900,1000);$captions = array('a-title','img-alt','img-title','href','None');?><div class="wrap">-<form method="post"action="<?php echo $_SERVER['PHP_SELF']?>?page=slimbox2options"id="options"><?phpecho wp_nonce_field('update-options','wp_slimbox_wpnonce');?><h2><?php _e('WP Slimbox2 Plugin','wp-slimbox2');?></h2>+ <form method="post"action=""id="options"><?php echo wp_nonce_field('update-options','wp_slimbox_wpnonce');?><h2><?php _e('WP Slimbox2 Plugin','wp-slimbox2');?></h2><?phpif(isset($_POST['action']) &&wp_verify_nonce($_POST['wp_slimbox_wpnonce'],'update-options')){$options->update_option(array('autoload' =>$_POST['wp_slimbox_autoload'],'loop' =>$_POST['wp_slimbox_loop'],'overlayOpacity' =>$_POST['wp_slimbox_overlayOpacity'],'overlayColor' =>$_POST['wp_slimbox_overlayColor'],'overlayFadeDuration' =>$_POST['wp_slimbox_overlayFadeDuration'],'resizeDuration' =>$_POST['wp_slimbox_resizeDuration'],'resizeEasing' =>$_POST['wp_slimbox_resizeEasing'],'initialWidth' =>$_POST['wp_slimbox_initialWidth'],'initialHeight' =>$_POST['wp_slimbox_initialHeight'],'imageFadeDuration' =>$_POST['wp_slimbox_imageFadeDuration'],'captionAnimationDuration' =>$_POST['wp_slimbox_captionAnimationDuration'],'caption' =>array($_POST['wp_slimbox_caption1'],$_POST['wp_slimbox_caption2'],$_POST['wp_slimbox_caption3'],$_POST['wp_slimbox_caption4']),'url' =>$_POST['wp_slimbox_url'],'selector' =>$_POST['wp_slimbox_selector'],'counterText' =>$_POST['wp_slimbox_counterText'],'closeKeys' =>$_POST['wp_slimbox_closeKeys'],'previousKeys' =>$_POST['wp_slimbox_previousKeys'],'nextKeys' =>$_POST['wp_slimbox_nextKeys'],'picasaweb' =>$_POST['wp_slimbox_picasaweb'],'flickr' =>$_POST['wp_slimbox_flickr'],'mobile' =>$_POST['wp_slimbox_mobile'],'maintenance' =>$_POST['wp_slimbox_maintenance'],'cache' =>$_POST['wp_slimbox_cache']));echo '<div id="message"class="updated fade"><p><strong>'.__('Settings Saved','wp-slimbox2').'.</strong></p></div>'}$caption = $options->get_option('caption');function selectionGen(&$option,&$array){foreach($array as $key=>$ms){$selected = ($option != $ms)? '':' selected';echo "<option value='$ms'$selected>".(($ms=='1'&&$array[0]!='0')?__('Disabled','wp-slimbox2'):$ms)."</option>\n"}}?><div style="clear:both;padding-top:5px;"></div><h2><?php _e('Settings','wp-slimbox2');?></h2><table class="widefat"cellspacing="0"id="inactive-plugins-table"><thead><tr><th scope="col"colspan="2"><?php _e('Setting','wp-slimbox2');?></th><th scope="col"><?php _e('Description','wp-slimbox2');?></th></tr></thead><tfoot><tr><th scope="col"colspan="3"><?php _e('Use the various options above to control some of the advanced settings of the plugin','wp-slimbox2');?></th></tr></tfoot><tbody class="plugins"><tr class='inactive'><td class='name'><?php _e('Autoload?','wp-slimbox2');?></td><th scope='row' class='check-column'><input type="checkbox"name="wp_slimbox_autoload"<?php if ($options->get_option('autoload') == 'on') echo ' checked="yes"';?>/></th><td class='desc'><p><?php _e('This option allows the user to automatically activate Slimbox on all links pointing to ".jpg",".jpeg",".png",".bmp"or ".gif". All image links will automatically be grouped together in a gallery according to the selector chosen below. If this isn\'t activated you will need to manually add <b><code>rel="lightbox"</code></b>for individual images or <b><code>rel="lightbox-imagesetname"</code></b>for groups on all links you wish to use the Slimbox effect. <b>Default is Disabled.</b>','wp-slimbox2');?></p></td></tr><tr class='inactive'><td class='name'><?php _e('Enable Picasaweb Integration?','wp-slimbox2');?></td><th scope='row' class='check-column'><input type="checkbox"name="wp_slimbox_picasaweb"<?php if ($options->get_option('picasaweb') == 'on') echo ' checked="yes"';?>/></th><td class='desc'><p><?php _e('This option allows the user to automatically add the Slimbox effect to Picasaweb links when provided an appropriate url (this is separate from the autoload script which only functions on direct image links). <b>Default is Disabled.</b>','wp-slimbox2');?></p></td></tr><tr class='inactive'><td class='name'><?php _e('Enable Flickr Integration?','wp-slimbox2');?></td><th scope='row' class='check-column'><input type="checkbox"name="wp_slimbox_flickr"<?php if ($options->get_option('flickr') == 'on') echo ' checked="yes"';?>/></th><td class='desc'><p><?php _e('This option allows the user to automatically add the Slimbox effect to Flickr links when provided an appropriate url (this is separate from the autoload script which only functions on direct image links). <b>Default is Disabled.</b>','wp-slimbox2');?></p></td></tr><tr class='inactive'><td class='name'><?php _e('Loop?','wp-slimbox2');?></td><th scope='row' class='check-column'><input type="checkbox"name="wp_slimbox_loop"<?php if ($options->get_option('loop') == 'on') echo ' checked="yes"';?>/></th><td class='desc'><p><?php _e('This option allows the user to navigate between the first and last images of a Slimbox gallery group when there is more than one image to display. <b>Default is Disabled.</b>','wp-slimbox2');?></p></td></tr><tr class='inactive'><td class='name'><?php _e('Overlay Opacity','wp-slimbox2');?></td><th scope='row' class='check-column'><select name="wp_slimbox_overlayOpacity"><?php selectionGen($options->get_option('overlayOpacity'),$overlayOpacity);?></select></th><td class='desc'><p><?php _e('This option allows the user to adjust the opacity of the background overlay. 1 is completely opaque,0 is completely transparent. <b>Default is 0.8.</b>','wp-slimbox2');?></p></td></tr><tr class='inactive'><td class='name'><?php _e('Overlay Color','wp-slimbox2');?></td><th scope='row' class='check-column'><input type="text"id="wp_slimbox_overlayColor"name="wp_slimbox_overlayColor"value="<?php echo $options->get_option('overlayColor');?>"size="7"maxlength="7"/><div id="picker"></div></th><td class='desc'><p><?php _e('This option allows the user to set the color of the overlay by selecting your hue from the circle and color gradient from the square. Alternatively you may manually enter a valid HTML color code. The color of the entry field will change to reflect your selected color. <b>Default is #000000.</b>','wp-slimbox2');?></p></td></tr><tr class='inactive'><td class='name'><?php _e('Overlay Fade Duration','wp-slimbox2');?></td><th scope='row' class='check-column'><select name="wp_slimbox_overlayFadeDuration"><?php selectionGen($options->get_option('overlayFadeDuration'),$msArray);?></select></th><td class='desc'><p><?php _e('This option allows the user to adjust the duration of the overlay fade-in and fade-out animations,in milliseconds. <b>Default is 400.</b>','wp-slimbox2');?></p></td></tr><tr class='inactive'><td class='name'><?php _e('Resize Duration','wp-slimbox2');?></td><th scope='row' class='check-column'><select name="wp_slimbox_resizeDuration"><?php selectionGen($options->get_option('resizeDuration'),$msArray);?></select></th><td class='desc'><p><?php _e('This option allows the user to adjust the duration of the resize animation for width and height,in milliseconds. <b>Default is 400.</b>','wp-slimbox2');?></p></td></tr>DetailsAffected Software:Subscribe to Comments Plugin Fixed in Version:2.1 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DescriptionA familiar symptom here with the same ole result. In the vulnerable code we see a call to $_SERVER['REQUEST_URI']. For some reason,many developers assume REQUEST_URI cannot be tainted and used for XSS. REQUEST_URI will not only include the path to current php file,it will also include any querystring parameters in the URI as well. Here’s a few examples of what REQUEST_URI will return: http://spotthevuln.com/blah/ results in –>/ http://spotthevuln.com/blah//index.php results in –>/blah/index.php http://spotthevuln.com/blah/index.php?qs=value results in –>/blah/index.php?qs=value http://spotthevuln.com/blah/index.php/qs1/qs2 results in –>/blah/index.php/qs1/qs2
As you can see an attacker can easily taint the REQUEST_URI value,using it in XSS attacks. The developers addressed this vulnerability by encoding calls to REQUEST_URI. Developers Solution<?phpfunction show_subscription_checkbox ($id='0'){global $sg_subscribe;sg_subscribe_start();if ( $sg_subscribe->checkbox_shown ) return $id;if ( !$email = $sg_subscribe->current_viewer_subscription_status() ):?><?php ?><?php ?><?php ?><p <?php if ($sg_subscribe->clear_both) echo 'style="clear:both;"';?>class="subscribe-to-comments"> <input type="checkbox"name="subscribe"id="subscribe"value="subscribe"style="width:auto;"<?php if ($sg_subscribe->default_subscribed) echo 'checked="checked"';?>/> <label for="subscribe"><?php echo $sg_subscribe->not_subscribed_text;?></label></p><?php ?><?php elseif ( $email == 'admin' &¤t_user_can('manage_options') ):?><?php ?><?php ?><?php ?><p <?php if ($sg_subscribe->clear_both) echo 'style="clear:both;"';?>class="subscribe-to-comments"><?php echo str_replace('[manager_link]',$sg_subscribe->manage_link($email,true,false),$sg_subscribe->author_text);?></p><?php else:?><?php ?><?php ?><?php ?><p <?php if ($sg_subscribe->clear_both) echo 'style="clear:both;"';?>class="subscribe-to-comments"><?php echo str_replace('[manager_link]',$sg_subscribe->manage_link($email,true,false),$sg_subscribe->subscribed_text);?></p><?php ?><?php endif;$sg_subscribe->checkbox_shown = true;return $id}function show_manual_subscription_form (){global $id,$sg_subscribe,$user_email;sg_subscribe_start();$sg_subscribe->show_errors('solo_subscribe','<div class="solo-subscribe-errors">','</div>',__('<strong>Error:</strong>','subscribe-to-comments'),'<br />');if ( !$sg_subscribe->current_viewer_subscription_status() ):get_currentuserinfo();?><?php ?><?php ?><?php ?>-<form action="http://<?php echo $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ?>"method="post">+<form action="http://<?php echo $_SERVER['HTTP_HOST'] . wp_specialchars($_SERVER['REQUEST_URI']);?>"method="post"><input type="hidden"name="solo-comment-subscribe"value="solo-comment-subscribe"/><input type="hidden"name="postid"value="<?php echo $id;?>"/>-<input type="hidden"name="ref"value="<?php echo 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];?>"/>+<input type="hidden"name="ref"value="<?php echo urlencode('http://' . $_SERVER['HTTP_HOST'] . wp_specialchars($_SERVER['REQUEST_URI']));?>"/><p class="solo-subscribe-to-comments"><?php _e('Subscribe without commenting','subscribe-to-comments');?><br /><label for="solo-subscribe-email"><?php _e('E-Mail:','subscribe-to-comments');?><input type="text"name="email"id="solo-subscribe-email"size="22"value="<?php echo $user_email;?>"/></label><input type="submit"name="submit"value="<?php _e('Subscribe','subscribe-to-comments');?>"/></p></form><?php ?>DetailsAffected Software:Boinc Fixed in Version:N/A Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DescriptionThe hint pretty much gave this one away. This week’s bug was an XSS exposure in Boinc. Boinc is an open source project which uses idle time on a computer to perform various scientific tasks. According to the website,its “safe,secure,and easy”. Boinc doesn’t seem to have version numbers and is updated on a constant basis. This bug was checked into the Boinc source about four weeks ago. The bug can be found in the else statement in the pm_form() function. The else statement takes a tainted value from the POST request body and uses it to populate a variable. The variable assignment is here: $writeto = post_str(“to”,true); $subject = post_str(“subject”,true); $content = post_str(“content”,true);
The hint lets us know that post_str takes values from the POST request body. Even if a hint wasn’t provided,you could have guessed that values coming from post_str() were tainted by looking at the first two lines of code outside of the if/else statement: $content = htmlspecialchars($content); $subject = htmlspecialchars($subject);
The two lines above show that the author was careful to encode the $subject and $content variables before using them in markup. Although the $writeto variable was assigned in a similar manner and even in the same code block,it doesn’t undergo any encoding. $writeto is then used in the markup in the code provided below,resulting in XSS: “<input type=\”text\”name=\”to\”value=\”$writeto\”size=\”60\”>”
Some other interesting items. This page is using the .inc extension for includes. Hopefully,the correct extension mappings are done to avoid source code disclosure of includes. While the application logic is open source,I’m sure there are configuration settings like database connection strings which could be exposed. Also,instead of using htmlspecialchars() to encode $writeto,the developers chose to use a function named sanitize_tags(). I hope sanitize tags defends against attribute injection which doesn’t require any HTML tags! Developers Solution<?phprequire_once("boinc_db.inc");require_once("sanitize_html.inc");require_once("bbcode_html.inc");function pm_header(){ echo "<div>\n"; echo " <a href=\"pm.php?action=inbox\">".tra("Inbox")."</a>\n"; echo " | <a href=\"pm.php?action=new\">".tra("Write")."</a>\n"; echo "</div>\n"}function pm_form($error = null){ global $bbcode_html,$bbcode_js; global $g_logged_in_user; page_head(tra("Send private message"),'','','',$bbcode_js); if (post_str("preview",true) == tra("Preview")){ $options = new output_options; echo "<div id=\"preview\">\n"; echo "<div class=\"header\">".tra("Preview")."</div>\n"; echo output_transform(post_str("content",true),$options); echo "</div>\n"; } $replyto = get_int("replyto",true); $userid = get_int("userid",true); $subject = null; $content = null; if ($replyto){ $message = BoincPrivateMessage::lookup_id($replyto); if (!$message || $message->userid != $g_logged_in_user->id){ error_page("no such message"); } $content = "[quote]".$message->content."[/quote]\n"; $userid = $message->senderid; $user = BoincUser::lookup_id($userid); if ($user != null){ $writeto = $userid."(".$user->name.")"; } $subject = $message->subject; if (substr($subject,0,3) != "re:"){ $subject = "re:".$subject; } } elseif ($userid){ $user = BoincUser::lookup_id($userid); if ($user){ $writeto = $userid."(".$user->name.")"; } } else{- $writeto = post_str("to",true);+$writeto = sanitize_tags(post_str("to",true)); $subject = post_str("subject",true); $content = post_str("content",true); } $content = htmlspecialchars($content); $subject = htmlspecialchars($subject); if ($error != null){ echo "<div class=\"error\">".$error."</div>\n"; } echo "<form action=\"pm.php\"method=\"post\"name=\"post\"onsubmit=\"return checkForm(this)\">\n"; echo "<input type=\"hidden\"name=\"action\"value=\"send\">\n"; echo form_tokens($g_logged_in_user->authenticator); start_table(); row2(tra("To")."<br /><span class=\"smalltext\">".tra("User IDs or unique usernames,separated with commas")."</span>", "<input type=\"text\"name=\"to\"value=\"$writeto\"size=\"60\">" ); row2(tra("Subject"),"<input type=\"text\"name=\"subject\"value=\"$subject\"size=\"60\">"); row2(tra("Message")."<span class=\"smalltext\">".html_info()."</span>", $bbcode_html."<textarea name=\"content\"rows=\"18\"cols=\"80\">$content</textarea>" ); echo "<tr><td></td><td><input type=\"submit\"name=\"preview\"value=\"".tra("Preview")."\"><input type=\"submit\"value=\"".tra("Send message")."\"></td></tr>\n"; end_table(); page_tail(); exit()}function send_pm_notification_email( $logged_in_user,$to_user,$subject,$content){ $message = "You have received a new private message at ".PROJECT.".From:$logged_in_user->name (ID $logged_in_user->id)Subject:$subject$content--------------------------To delete or respond to this message,visit:".URL_BASE."pm.phpTo change email preferences,visit:".URL_BASE."edit_forum_preferences_form.phpDo not reply to this message."; send_email($to_user,"[".PROJECT."] ".tra("- private message"),$message)}?> |