| DetailsAffected Software:DojoX Fixed in Version:1.4.1 Issue Type:Cross Site Scripting (XSS) Original Code:Found Here DescriptionThis week’s bug was an easy one with a straightforward fix. The vulnerable code sample is basically a single switch statement. Most of the cases don’t do anything interesting (from a security standpoint) however,the default case at the end of the switch statement leads to a vulnerable condition. If all of the case statements fail,the application throws a useful error message echoing back a value directly from the query string. The DojoX developers addressed the vulnerability by html encoding the value before echoing it back to the user. Simple bug,simple fix. I hope all the readers have a good weekend and a Happy Halloween! Developers Solution<?php// this file is just a bouncer for ContentPane.html testerror_reporting(E_ALL ^ E_NOTICE);if(isset($_GET['mode'])){switch($_GET['mode']){case 'htmlPaths':echo "<img src='../images/testImage.gif' id='imgTest'/><div id='inlineStyleTest' style='width:188px;height:125px;background-image:url(../images/testImage.gif)'></div><style>@import 'getResponse.php?mode=importCss';</style><link type='text/css' rel='stylesheet' href='getResponse.php?mode=linkCss'><div id='importCssTest'></div><div id='linkCssTest'></div><div id='importMediaTest'></div><div id='linkMediaTest'></div><!-- these may download but not render --><style media='print'>@import 'getResponse.php?mode=importMediaPrint';</style><link media='print' type='text/css' rel='stylesheet' href='getResponse.php?mode=linkMediaPrint'>";break;case 'importCss':header('Content-type:text/css;charset=utf-8');echo "#importMediaTest{margin:4px;border:1px dashed red;width:200px;height:200px}#importCssTest{margin:4px;border:1px solid blue;width:100px;height:100px}";break;case 'linkCss':header('Content-type:text/css;charset=utf-8');echo "#linkMediaTest{margin:4px;border:2px dashed red;width:200px;height:200px}#linkCssTest{margin:4px;border:2px dashed red;width:100px;height:100px}";break;case 'importMediaPrint':// may download but not renderheader('Content-type:text/css;charset=utf-8');echo "#importMediaTest{margin:10px;border:5px dashed gray;width:100px;height:100px}";break;case 'linkMediaPrint':// may download but not renderheader('Content-type:text/css;charset=utf-8');echo "#linkMediaTest{margin:10px;border:5px dashed gray;width:100px;height:100px}";break;case 'remoteJsTrue':header('Content-type:text/javascript;charset=utf-8');echo "unTypedVarInDocScope = true;";break;case 'remoteJsFalse':header('Content-type:text/javascript;charset=utf-8');echo "unTypedVarInDocScope = false;";break;case 'entityChars':header('Content-type:text/css;charset=utf-8');if($_GET['entityEscaped'] == null){print("var div = document.createElement(\"div\");document.body.appendChild(div);div.innerHTML = \"<div id=\\\"should_not_be_here2\\\"></div>\";window.__remotePaneLoaded2 = true;")}else{print("window.__remotePaneLoaded2 = true;")}break;default:-echo "unkown mode{$_GET['mode']}";+echo "unkown mode{htmlentities($_GET['mode'])}"}}?>DetailsAffected Software:WordPress Fixed in Version:2.1 Issue Type:HTTP Header Injection Original Code:Found Here DescriptionThis week’s bug was a Set-Cookie/HTTP Header injection bug in WordPress Core. Looking at the code,we see that the WordPress Developers assign several variables directly from the $_POST body. These assignments are listed below: $comment_author = trim($_POST['author']); $comment_author_email = trim($_POST['email']); $comment_author_url = trim($_POST['url']); $comment_content = trim($_POST['comment']);
Each of these variables should now be considered tainted and should be sanitized/encoded before using their values in any operations. It seems that the WordPress developers were aware that the values assigned to the variables listed above could not be trusted and proceeded to escape the values before using them in database related operations. Some examples of the sanitization can are provided below: $comment_author = $wpdb->escape($user_identity); $comment_author_email = $wpdb->escape($user_email); $comment_author_url = $wpdb->escape($user_url);
Unfortunately,the developers utilized the incorrect sanitizing routines for the tainted values in the setcookie API. The developers used stripslashes() to sanitize the user controlled value before passing it to the setcookie() API. Although stripslashes can help prevent other types of vulnerabilities,it was not intended to defend against HTTP HEADER injection or cookie poisoning. By injecting a series of CRLF (%0d%0a) characters,an attacker could use this bug to inject arbitrary headers into the HTTP response and in some cases use this header injection bug for XSS. The WordPress developers addressed this issue by passing the attacker controlled value to the clean_url() function before allowing it in the setcookie. The full source for clean_url() can be found here,however the more interesting sanitizing routines are provided below: $url = preg_replace(‘|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i’,”,$url); $strip = array(‘%0d’,‘%0a’,‘%0D’,‘%0A’); $url = _deep_replace($strip,$url); $url = str_replace(‘;//’,‘://’,$url);
Developers Solution<?phprequire( dirname(__FILE__) . '/wp-config.php' );nocache_headers();$comment_post_ID = (int) $_POST['comment_post_ID'];$status = $wpdb->get_row("SELECT post_status,comment_status FROM $wpdb->posts WHERE ID = '$comment_post_ID'");if ( empty($status->comment_status) ){do_action('comment_id_not_found',$comment_post_ID);exit} elseif ( 'closed' == $status->comment_status ){do_action('comment_closed',$comment_post_ID);die( __('Sorry,comments are closed for this item.') )} elseif ( 'draft' == $status->post_status ){do_action('comment_on_draft',$comment_post_ID);exit}$comment_author = trim($_POST['author']);$comment_author_email = trim($_POST['email']);$comment_author_url = trim($_POST['url']);$comment_content = trim($_POST['comment']);// If the user is logged inget_currentuserinfo();if ( $user_ID ):$comment_author = $wpdb->escape($user_identity);$comment_author_email = $wpdb->escape($user_email);$comment_author_url = $wpdb->escape($user_url);else:if ( get_option('comment_registration') )die( __('Sorry,you must be logged in to post a comment.') );endif;$comment_type = '';if ( get_settings('require_name_email') &&!$user_ID ){if ( 6 >strlen($comment_author_email) || '' == $comment_author )die( __('Error:please fill the required fields (name,email).') );elseif ( !is_email($comment_author_email))die( __('Error:please enter a valid email address.') )}if ( '' == $comment_content )die( __('Error:please type a comment.') );$commentdata = compact('comment_post_ID','comment_author','comment_author_email','comment_author_url','comment_content','comment_type','user_ID');wp_new_comment( $commentdata );if ( !$user_ID ):setcookie('comment_author_' . COOKIEHASH,stripslashes($comment_author),time() + 30000000,COOKIEPATH,COOKIE_DOMAIN);setcookie('comment_author_email_' . COOKIEHASH,stripslashes($comment_author_email),time() + 30000000,COOKIEPATH,COOKIE_DOMAIN);-setcookie('comment_author_url_' . COOKIEHASH,stripslashes($comment_author_url),time() + 30000000,COOKIEPATH,COOKIE_DOMAIN);+setcookie('comment_author_url_' . COOKIEHASH,stripslashes(clean_url($comment_author_url)),time() + 30000000,COOKIEPATH,COOKIE_DOMAIN);endif;$location = ( empty( $_POST['redirect_to'] ) ) ? get_permalink( $comment_post_ID ):$_POST['redirect_to'];wp_redirect( $location );?>
DetailsAffected Software:OpenFire Fixed in Version:3.7.0b Issue Type:XSS Original Code: Found Here DescriptionThis week’s bug was an XSS vulnerability caused by the improper escaping of an HTML attribute. It’s obvious that the developers attempted to protect their software from XSS vulnerabilities. They even wrote their own XSS sanitizing method (escapeHTMLTags). The escapeHTMLTags() method is simple,strip out <and >characters and return the string. Unfortunately,this simple pattern isn’t sufficient in defending against all XSS vulnerabilities. There is a bit of tracing that is required to understand this bug,so let’s start the tracing. The bug begins with the following variable assignment: String username = ParamUtils.getParameter(request,“username”);
The username value is assigned directly from the HTTP request. Later,the username variable is escaped using the custom escapeHTMLTags() function. The escaping occurs in the following line: username = org.jivesoftware.util.StringUtils.escapeHTMLTags(username);
Later in the code,the escaped username value is used in the markup as part of an HTML attribute. The vulnerable line is presented below: <input size=”15″maxlength=”50″value=”<%= (username != null ? username:“”) %>”>
The line above checks to see if the username variable has been assigned a value. If the username variable contains a value,it is displayed in the markup as the value attribute for an input field. While sanitizing the <and >characters would prevent an attacker closing the input field and starting a new html tag,it doesn’t prevent an attacker from closing off the attribute value and injecting a new HTML attribute for the input field. Some consider injection into a input field to be unexploitable (or limited to certain browsers),check out Gareth Heyes blog post about exploiting text fields with new HTML5 events http://www.thespanner.co.uk/2009/12/06/html5-new-xss-vectors/ Developers Solution public static String escapeHTMLTags(String in){ if (in == null){ return null; } char ch; int i = 0; int last = 0; char[] input = in.toCharArray(); int len = input.length; StringBuilder out = new StringBuilder((int)(len * 1.3)); for (;i <len;i++){ ch = input[i]; if (ch >'>'){ } else if (ch == '<'){if (i >last){out.append(input,last,i - last);} last = i + 1;out.append(LT_ENCODE); } else if (ch == '>'){if (i >last){out.append(input,last,i - last);} last = i + 1;out.append(GT_ENCODE); } else if (ch == '\n'){if (i >last){out.append(input,last,i - last);} last = i + 1;out.append("<br>"); } } if (last == 0){ return in; } if (i >last){ out.append(input,last,i - last); } return out.toString(); }... <snip>...<% // get parameters String username = ParamUtils.getParameter(request,"username"); String password = ParamUtils.getParameter(request,"password"); String url = ParamUtils.getParameter(request,"url"); url = org.jivesoftware.util.StringUtils.escapeHTMLTags(url); // SSO between cluster nodes String secret = ParamUtils.getParameter(request,"secret"); String nodeID = ParamUtils.getParameter(request,"nodeID"); String nonce = ParamUtils.getParameter(request,"nonce"); // The user auth token: AuthToken authToken = null; // Check the request/response for a login token Map<String,String>errors = new HashMap<String,String>(); if (ParamUtils.getBooleanParameter(request,"login")){ String loginUsername = username; if (loginUsername != null){ loginUsername = JID.escapeNode(loginUsername); } try{ if (secret != null &&nodeID != null){if (StringUtils.hash(AdminConsolePlugin.secret).equals(secret) &&ClusterManager.isClusterMember(Base64.decode(nodeID,Base64.URL_SAFE))){authToken = new AuthToken(loginUsername);} else if ("clearspace".equals(nodeID) &&ClearspaceManager.isEnabled()){ClearspaceManager csmanager = ClearspaceManager.getInstance();String sharedSecret = csmanager.getSharedSecret();if (nonce == null || sharedSecret == null || !csmanager.isValidNonce(nonce) || !StringUtils.hash(loginUsername + ":"+ sharedSecret + ":"+ nonce).equals(secret)){throw new UnauthorizedException("SSO failed. Invalid secret was provided");} authToken = new AuthToken(loginUsername);} else{throw new UnauthorizedException("SSO failed. Invalid secret or node ID was provided");} } else{// Check that a username was provided before trying to verify credentials if (loginUsername != null){if (LoginLimitManager.getInstance().hasHitConnectionLimit(loginUsername,request.getRemoteAddr())){throw new UnauthorizedException("User '"+ loginUsername +"' or address '"+ request.getRemoteAddr() + "' has his login attempt limit.");} if (!AdminManager.getInstance().isUserAdmin(loginUsername,true)){throw new UnauthorizedException("User '"+ loginUsername + "' not allowed to login.");} authToken = AuthFactory.authenticate(loginUsername,password);} else{errors.put("unauthorized",LocaleUtils.getLocalizedString("login.failed.unauthorized"));} }... <snip>... // Escape HTML tags in username to prevent cross-site scripting attacks. This // is necessary because we display the username in the page below. username = org.jivesoftware.util.StringUtils.escapeHTMLTags(username);%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title><%= AdminConsole.getAppName() %><fmt:message key="login.title"/></title><script language="JavaScript"type="text/javascript"><!--// break out of framesif (self.parent.frames.length != 0){self.parent.location=document.location} function updateFields(el){ if (el.checked){document.loginForm.username.disabled = true;document.loginForm.password.disabled = true; } else{document.loginForm.username.disabled = false;document.loginForm.password.disabled = false;document.loginForm.username.focus(); } }//--></script> <link rel="stylesheet"href="style/global.css"type="text/css"> <link rel="stylesheet"href="style/login.css"type="text/css"></head><body><form action="login.jsp"name="loginForm"method="post"><% if (url != null){try{%> <input type="hidden"name="url"value="<%= url %>"><% } catch (Exception e){Log.error(e);} } %><input type="hidden"name="login"value="true"><div align="center"> <!-- BEGIN login box --> <div id="jive-loginBox"> <div align="center"id="jive-loginTable"> <span id="jive-login-header"style="background:transparent url(images/login_logo.gif) no-repeat left;padding:29px 0 10px 205px;"> <fmt:message key="admin.console"/> </span> <div style="text-align:center;width:380px;"> <table cellpadding="0"cellspacing="0"border="0"align="center"><tr><td align="right"class="loginFormTable"><table cellpadding="2"cellspacing="0"border="0"><noscript> <tr> <td colspan="3"> <table cellpadding="0"cellspacing="0"border="0"> <tr valign="top"> <td><img src="images/error-16x16.gif"width="16"height="16"border="0"alt=""vspace="2"></td> <td><div class="jive-error-text"style="padding-left:5px;color:#cc0000;"><fmt:message key="login.error"/></div></td> </tr> </table> </td> </tr></noscript><% if (errors.size() >0){%> <tr> <td colspan="3"> <table cellpadding="0"cellspacing="0"border="0"> <% for (String error:errors.values()){%> <tr valign="top"> <td><img src="images/error-16x16.gif"width="16"height="16"border="0"alt=""vspace="2"></td> <td><div class="jive-error-text"style="padding-left:5px;color:#cc0000;"><%= error%></div></td> </tr> <% } %> </table> </td> </tr><% } %><tr>+ <td><input type="text"name="username"size="15"maxlength="50"id="u01"value="<%= (username != null ? StringUtils.removeXSSCharacters(username):"") %>"></td>- <td><input type="text"name="username"size="15"maxlength="50"id="u01"value="<%= (username != null ? username:"") %>"></td> <td><input type="password"name="password"size="15"maxlength="50"id="p01"></td> <td align="center"><input type="submit"value=" <fmt:message key="login.login"/> "></td></tr><tr valign="top"> <td class="jive-login-label"><label for="u01"><fmt:message key="login.username"/></label></td> <td class="jive-login-label"><label for="p01"><fmt:message key="login.password"/></label></td> <td> </td></tr></table></td></tr><tr><td align="right"><div align="right"id="jive-loginVersion"><%= AdminConsole.getAppName() %>,<fmt:message key="login.version"/>:<%= AdminConsole.getVersionString() %></div></td></tr> </table> </div> </div> </div> <!-- END login box --></div></form><script language="JavaScript"type="text/javascript"><!-- if (document.loginForm.username.value == ''){ document.loginForm.username.focus(); } else{ document.loginForm.password.focus(); }//--></script></body></html>DetailsAffected Software:Dojox Fixed in Version:1.4.1 Issue Type:XSS Original Code: Found Here DescriptionThe code sample presented this week have a few XSS vulnerabilities. The first XSS bug is caused when $_GET[‘messId’] doesn’t match any of the switch cases. The default behavior is to throw a friendly error message indicating the messId is unknown along with the value passed via the querystring. Unfortunately,the error message can also contain attacker controlled HTML/SCRIPT resulting in XSS. The two other XSS bugs fixed by the developers in this patch are classic XSS. Both issues take user/attacker controlled variables and display the variables in markup without sanitization/encoding. Although the XSS bugs are fairly straight forward,what I find interesting in this example is why this page is here in the first place. The code don’t seem to provide any useful functionality (other than to provide a place for attackers to abuse XSS). If you were a security engineer assigned to audit this page,it might be a good idea to ask WHY this page exists in the first place. It turns out that this page is indeed a test/debugging page that is included with dojox,offering no functionality intended for production users. Think long and hard before exposing test and debug functionality in your production environment. Check production systems for example/testing/debugging functionality and disable/remove this functionality if possible. Code developed for testing and debugging rarely undergoes the scrutiny of production code and will like contain security issues. Developers Solution1 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
| <?php // this just bounces a message as a response,and optionally emulates network latency.
// default delay is 0 sec,to change: // getResponse.php?delay=[Int milliseconds]
// to change the message returned // getResponse.php?mess=whatever%20string%20you%20want.
// to select a predefined message // getResponse.php?messId=0
error_reporting(E_ALL ^ E_NOTICE);
$delay = 1;// 1 micro second to avoid zero division in messId 2 if(isset($_GET['delay']) &&is_numeric($_GET['delay'])){ $delay = (intval($_GET['delay']) * 1000); }
if(isset($_GET['messId']) &&is_numeric($_GET['messId'])){ switch($_GET['messId']){ case 0: echo "<h3>WARNING This should NEVER be seen,delayed by 2 sec!</h3>"; $delay = 2; break; case 1: echo "<div dojotype='dijit.TestWidget'>Testing attr('href',...)</div>"; break; case 2: echo "<div dojotype='dijit.TestWidget'>Delayed attr('href',...) test</div> <div dojotype='dijit.TestWidget'>Delayed by ". ($delay/1000000) . "sec.</div>"; break; case 3: echo "IT WAS the best of times,it was the worst of times,it was the age of wisdom,it was the age of foolishness,it was the epoch of belief,it was the epoch of incredulity,it was the season of Light,it was the season of Darkness,it was the spring of hope,it was the winter of despair,we had everything before us,we had nothing before us,we were all going direct to Heaven,we were all going direct the other way -- in short,the period was so far like the present period,that some of its noisiest authorities insisted on its being received,for good or for evil,in the superlative degree of comparison only"; break; case 4: echo "There were a king with a large jaw and a queen with a plain face,on the throne of England;there were a king with a large jaw and a queen with a fair face,on the throne of France. In both countries it was clearer than crystal to the lords of the State preserves of loaves and fishes,that things in general were settled for ever."; break; case 5: echo "It was the year of Our Lord one thousand seven hundred and seventy- five. Spiritual revelations were conceded to England at that favoured period,as at this. Mrs. Southcott had recently attained her five-and- twentieth blessed birthday,of whom a prophetic private in the Life Guards had heralded the sublime appearance by announcing that arrangements were made for the swallowing up of London and Westminster. Even the Cock-lane ghost had been laid only a round dozen of years,after rapping out its messages,as the spirits of this very year last past (supernaturally deficient in originality) rapped out theirs. Mere messages in the earthly order of events had lately come to the English Crown and People,from a congress of British subjects in America:"; break; default: -echo "unknown messId:{$_GET['messId']}"; +echo "unknown messId:". htmlentities($_GET['messId']); } }
if(isset($_GET['bounceGetStr']) && $_GET['bounceGetStr']){ -echo "<div id='bouncedGetStr'>{$_SERVER["QUERY_STRING"]}</div>"; +echo "<div id='bouncedGetStr'>".htmlentities($_SERVER["QUERY_STRING"])."</div>"; }
if(isset($_GET['message']) &&$_GET['message']){ -echo $_GET['message']; +echo htmlentities($_GET['message']); }
usleep($delay);
?> |
DetailsAffected Software:WordPress (core) Fixed in Version:1.2 Issue Type:XSS Original Code: Found Here DescriptionLooking at this code made me smile,its about 6 years old. There’s a lot going on here and quite a few issues. The first thing that jumped out at me was the use of $HTTP_POST_FILES. $HTTP_POST_FILES means were working with user controlled files. There are tons of things that can go wrong when dealing with user/attacker controlled files (a list too long to go into here). Lets hope the WordPress devs are on their A-game here. Looking at the patch submitted by the WordPress developers,we see that they changed references to $HTTP_POST_FILES to the superglobal $_FILES. Within the $_FILES array there are a couple indexes that are commonly used. These indexes are: [name] [type] [tmp_name] [error] [size]
Name,type,and size are all controlled by the user/attacker,so the WordPress developers should be wary when dealing with these values. Surprisingly (or unsurprisingly,depending on your point of view),this patch doesn’t contain seem to contain any robust validation of data associated with the uploaded file data. Instead,the defenses put in place here seem to be centered around replacing a poor validation/sanitization routine with a more robust encoding routine which prevents a XSS vulnerability. The replaced sanitization routine and the XSS bug are presented in the following lines: -$imgdesc = str_replace(‘”‘,‘&quot;’,$_POST['imgdesc']); +$imgdesc = htmlentities2($imgdesc); class=”uploadform”value=”<?php echo $imgdesc;?>”/>
What’s surprising is although the WordPress developers prevented this single XSS vulnerability,there is a large number of XSS vulnerabilities in this file. The most obvious symptom is “<?php echo $_REQUEST[] ?>. Additionally,the loose validation of the user uploaded file is concerning,especially with the number of problems that can be encountered when dealing with user controlled files. Maybe the varsity team was on vacation when this patch went in. Developers Solution1 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
| <?php //Makes sure they choose a file
//print_r($HTTP_POST_FILES); //die();
- $imgalt = (isset($_POST['imgalt'])) ? $_POST['imgalt']:$imgalt; - - $img1_name = (strlen($imgalt)) ? $_POST['imgalt']:$HTTP_POST_FILES['img1']['name']; - $img1_type = (strlen($imgalt)) ? $_POST['img1_type']:$HTTP_POST_FILES['img1']['type']; - $imgdesc = str_replace('"','&quot;',$_POST['imgdesc']); +$imgalt = basename( (isset($_POST['imgalt'])) ? $_POST['imgalt']:'' ); + +$img1_name = (strlen($imgalt)) ? $imgalt:basename( $_FILES['img1']['name'] ); +$img1_type = (strlen($imgalt)) ? $_POST['img1_type']:$_FILES['img1']['type']; +$imgdesc = htmlentities2($imgdesc);
$imgtype = explode(".",$img1_name); $imgtype = strtolower($imgtype[count($imgtype)-1]);
if (in_array($imgtype,$allowed_types) == false) { die(sprintf(__('File %1$s of type %2$s is not allowed.') ,$img1_name,$imgtype)); }
if (strlen($imgalt)) { $pathtofile = get_settings('fileupload_realpath')."/".$imgalt; -$img1 = $_POST['img1']; +$img1 = $_POST['img1']['tmp_name']; } else { $pathtofile = get_settings('fileupload_realpath')."/".$img1_name; -$img1 = $HTTP_POST_FILES['img1']['tmp_name']; +$img1 = $_FILES['img1']['tmp_name']; }
// makes sure not to upload duplicates,rename duplicates $i = 1; $pathtofile2 = $pathtofile; $tmppathtofile = $pathtofile2; $img2_name = $img1_name;
while (file_exists($pathtofile2)) { $pos = strpos($tmppathtofile,'.'.trim($imgtype)); $pathtofile_start = substr($tmppathtofile,0,$pos); $pathtofile2 = $pathtofile_start.'_'.zeroise($i++,2).'.'.trim($imgtype); $img2_name = explode('/',$pathtofile2); $img2_name = $img2_name[count($img2_name)-1]; }
if (file_exists($pathtofile) &&!strlen($imgalt)) { $i = explode(' ',get_settings('fileupload_allowedtypes')); $i = implode(',',array_slice($i,1,count($i)-2)); $moved = move_uploaded_file($img1,$pathtofile2); // if move_uploaded_file() fails,try copy() if (!$moved) { $moved = copy($img1,$pathtofile2); } if (!$moved) { die(sprintf(__("Couldn't upload your file to %s."),$pathtofile2)); } else { chmod($pathtofile2,0666); @unlink($img1); }
//
// duplicate-renaming function contributed by Gary Lawrence Murphy ?> <p><strong><?php __('Duplicate File?') ?></strong></p> <p><b><em><?php printf(__("The filename '%s' already exists!"),$img1_name);?></em></b></p> <p><?php printf(__("Filename '%1\$s' moved to '%2\$s'"),$img1,"$pathtofile2 - $img2_name") ?></p> <p><?php _e('Confirm or rename:') ?></p> <form action="upload.php"method="post"enctype="multipart/form-data"> <input type="hidden"name="MAX_FILE_SIZE"value="<?php echo get_settings('fileupload_maxk') *1024 ?>"/> <input type="hidden"name="img1_type"value="<?php echo $img1_type;?>"/> <input type="hidden"name="img1_name"value="<?php echo $img2_name;?>"/> <input type="hidden"name="img1_size"value="<?php echo $img1_size;?>"/> <input type="hidden"name="img1"value="<?php echo $pathtofile2;?>"/> <input type="hidden"name="thumbsize"value="<?php echo $_REQUEST['thumbsize'];?>"/> <input type="hidden"name="imgthumbsizecustom"value="<?php echo $_REQUEST['imgthumbsizecustom'];?>"/> <?php _e('Alternate name:') ?><br /><input type="text"name="imgalt"size="30"value="<?php echo $img2_name;?>"/><br /> <br /> <?php _e('Description:') ?><br /><input type="text"name="imgdesc"size="30"value="<?php echo $imgdesc;?>"/> <br /> <input type="submit"name="submit"value="<?php _e('Rename') ?>"/> </form> </div> |
DetailsAffected Software:The Hacker’s Diet (WordPress Plugin) Fixed in Version:0.9.7b Issue Type:SQL Injection Original Code: Found Here DescriptionThis week’s vulnerability was a SQL injection vulnerability affecting the Hacker’s Diet WordPress plugin. In the vulnerable version,the plugin assigns several variables using values obtained directly from the querystring. The variable assignments are shown below: $weeks = $_GET["weeks"]; $start_date = $_GET["start_date"]; $end_date = $_GET["end_date"]; $goal = $_GET["goal"]; $user_id = $_GET["user"]; $maint_mode = $_GET["maint_mode"];
No sanitization or validation is done before assigning the values. Once the assignments are made,the attacker controlled values are then passed to a dynamic SQL string here resulting in SQL Injection: $query = “select date,weight,trend from “.$table_prefix.”hackdiet_weightlog where wp_id = $user_id and date >\”".date(“Y-m-d”,strtotime(“$weeks weeks ago”)).”\”order by date asc”; $query = “select date,weight,trend from “.$table_prefix.”hackdiet_weightlog where wp_id = $user_id and date >= \”$start_date\”and date <= \”$end_date\”order by date asc”;
The plugin authors patched this vulnerability by validating that the $_GET[“user”] and $_GET[“weeks”] parameters contains only numeric characters. An interesting exercise would be to trace through the code and find where the following variables are being used: $start_date = $_GET["start_date"]; $end_date = $_GET["end_date"]; $goal = $_GET["goal"]; $maint_mode = $_GET["maint_mode"];
Developers Solution1 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
| <?php include (dirname(__FILE__)."/jpgraph/jpgraph.php"); include (dirname(__FILE__)."/jpgraph/jpgraph_line.php"); include (dirname(__FILE__)."/jpgraph/jpgraph_scatter.php");
// get our db settings without loading all of wordpress every save $html = implode('',file("../../../wp-config.php")); $html = str_replace ("require_once","// ",$html); $html = str_replace ("<?php","",$html); $html = str_replace ("?>","",$html); eval($html);
mysql_connect(DB_HOST,DB_USER,DB_PASSWORD); mysql_select_db(DB_NAME);
+if (!is_numeric($_GET["user"]) || !is_numeric($_GET["weeks"])) { + exit; +}
$weeks = $_GET["weeks"]; $start_date = $_GET["start_date"]; $end_date = $_GET["end_date"]; $goal = $_GET["goal"]; $user_id = $_GET["user"]; $maint_mode = $_GET["maint_mode"];
if ($weeks) { - $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = $user_id and date >\"".date("Y-m-d",strtotime("$weeks weeks ago"))."\"order by date asc"; + $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = \"". $user_id . "\"and date >\"".date("Y-m-d",strtotime("$weeks weeks ago"))."\"order by date asc"; } else if ($start_date and $end_date) { - $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = $user_id and date >= \"$start_date\"and date <= \"$end_date\"order by date asc"; + $query = "select date,weight,trend from ".$table_prefix."hackdiet_weightlog where wp_id = \"". $user_id . "\"and date >= \"$start_date\"and date <= \"$end_date\"order by date asc"; }
result = mysql_query($query); if (mysql_num_rows($result)) { if (mysql_num_rows($result) == 1) { // only one day,gotta finagle the display
$row = mysql_fetch_assoc($result);
// fake day before $weight_data[] = 0; if ($goal >0) { $goal_data[] = $goal; } $x_data[] = date("n/j",strtotime("yesterday",strtotime($row["date"])));
// data $weight_data[] = $row["weight"]; if ($goal >0) { $goal_data[] = $goal; } $x_data[] = date("n/j",strtotime($row["date"]));
// fake day after $weight_data[] = 0; if ($goal >0) { $goal_data[] = $goal; } $x_data[] = date("n/j",strtotime("tomorrow",strtotime($row["date"]))); } else { $num_rows = mysql_num_rows($result); if ($num_rows <= 7 * 2) { // 0-2 weeks $ticks = "daily"; } else if ($num_rows <= 31 * 4) { // 2 weeks - 4 months $ticks = "weekly"; } else { // 4 months + $ticks = "monthly"; }
$count = 1; while ($row = mysql_fetch_assoc($result)) { $weight_data[] = $row["weight"]; $trend_data[] = $row["trend"]; if ($goal >0) { $goal_data[] = $goal; } switch ($ticks) { case "weekly": if ($count == 1) { $x_data[] = date("n/j",strtotime($row["date"])); } else { $x_data[] = ""; if ($count == 7) { $count = 0; } } break; case "monthly": if (date("j",strtotime($row["date"])) == "1") { $x_data[] = date("n/j",strtotime($row["date"])); } else { $x_data[] = ""; } break; case "daily": default: $x_data[] = date("n/j",strtotime($row["date"])); break; }
$count++; } } |
DetailsAffected Software:DojoToolkit Fixed in Version:1.4.2 Issue Type:XSS Original Code: Found Here DescriptionThis week’s vulnerability is a DOM based XSS that could be found in a JavaScript file provided by the DojoToolkit. This JavaScript file was included (via script src) in many pages throughout the DojoToolkit,making those pages vulnerable to XSS. Unlike traditional XSS bugs,server side processing is not required for certain types of DOM based XSS. This is an important concept to understand as some code auditors will skip static pages assuming the attacker will not have the ability to control any values used by the page. The bug starts here: if(window.location.href.indexOf(“?”) >-1){
The JavaScript pulls the address of the loaded page and checks to see if the address contains the “?” character. If the “?” character is found,the JavaScript begins parsing and splitting the URI into various arrays. This parsing and splitting is done in the lines provided below: var str = window.location.href.substr(window.location.href.indexOf(“?”)+1).split(/#/); var ary = str[0].split(/&/); for(var i=0;i<ary.length;i++){ var split = ary[i].split(/=/),
The vulnerable assignment occurs here: value = split[1];
The JavaScript above essentially grabs a querystring value (attacker supplied) and assigns it to the “value” variable. Later,the “value” variable is used in several places,for example: dojo.config.locale = locale = value; document.getElementsByTagName(“html”)[0].dir = value; theme = value;
Considering the assignments listed above,we have a couple different variables that are tainted. I’ve highlighted the tainted variables in red. Tracing the “theme” assignment shown above,we see the tainted value being passed to a document.write statement,resulting in XSS. var themeCss = d.moduleUrl(“dijit.themes”,theme+”/”+theme+”.css”); var themeCssRtl = d.moduleUrl(“dijit.themes”,theme+”/”+theme+”_rtl.css”); document.write(‘<link rel=”stylesheet”type=”text/css”href=”‘+themeCss+’”>’); document.write(‘<link rel=”stylesheet”type=”text/css”href=”‘+themeCssRtl+’”>’);
The patch checked in by the DojoToolkit team sanitizes the “value” JavaScript variable by allowing only word characters (^\w). Developers Solution1 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
| if(window.location.href.indexOf("?") >-1){ var str = window.location.href.substr(window.location.href.indexOf("?")+1).split(/#/); var ary = str[0].split(/&/); for(var i=0;i<ary.length;i++){ var split = ary[i].split(/=/), key = split[0], -value = split[1]; +value = split[1].replace(/[^\w]/g,"");// replace() to prevent XSS attack switch(key){ case "locale": // locale string | null dojo.config.locale = locale = value; break; case "dir": // rtl | null document.getElementsByTagName("html")[0].dir = value; break; case "theme": // tundra | soria | noir | squid | nihilo | null theme = value; break; case "a11y": if(value){ testMode = "dijit_a11y";} } } }
// always include the default theme files: if(theme || testMode){
if(theme){ var themeCss = d.moduleUrl("dijit.themes",theme+"/"+theme+".css"); var themeCssRtl = d.moduleUrl("dijit.themes",theme+"/"+theme+"_rtl.css"); document.write('<link rel="stylesheet"type="text/css" href="'+themeCss+'">'); document.write('<link rel="stylesheet"type="text/css" href="'+themeCssRtl+'">'); }
if(dojo.config.parseOnLoad){ dojo.config.parseOnLoad = false; dojo.config._deferParsing = true; }
d.addOnLoad(function(){
// set the classes var b = dojo.body(); if(theme){ dojo.removeClass(b,defTheme); if(!d.hasClass(b,theme)){ d.addClass(b,theme);} var n = d.byId("themeStyles"); if(n){ d.destroy(n);} } if(testMode){ d.addClass(b,testMode);} if(dojo.config._deferParsing){ // attempt to elimiate race condition introduced by this // test helper file. 120ms to allow CSS to finish/process? setTimeout(dojo.hitch(d.parser,"parse",b),120); }
}); }
})(); |
DetailsAffected Software:Openfire by Ignite Realtime Fixed in Version:3.6.3 Issue Type:XSS Original Code: Found Here DescriptionXSS bug in Openfire by Ignite Realtime. Openfire is an Open Source,real time collaboration server. The bug is very straightforward and a simple string like the one presented below takes advantage of the vulnerability. http://www.example.com/group-summary.jsp?search=%22%3E%3C[xss]
This bug was actually part of a number of security bugs reported by Core Security Technologies. You can read their advisory here. The patch simply HTML encodes the tainted search parameter… Developers Solution1 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
| <% // Get parameters int start = ParamUtils.getIntParameter(request,"start",0); int range = ParamUtils.getIntParameter(request,"range",webManager.getRowsPerPage("group-summary", 15));
if (request.getParameter("range") != null) { webManager.setRowsPerPage("group-summary", range); }
int groupCount = webManager.getGroupManager().getGroupCount(); Collection<Group> groups = webManager.getGroupManager().getGroups(start, range);
String search = null; if (webManager.getGroupManager().isSearchSupported() && request.getParameter("search") != null && !request.getParameter("search").trim().equals("")) { search = request.getParameter("search"); + // Santize variables to prevent vulnerabilities + search = StringUtils.escapeHTMLTags(search);
// Use the search terms to get the list of groups and group count. groups = webManager.getGroupManager().search(search, start, range); // Get the count as a search for *all* groups. That will let us do pagination even // though it's a bummer to execute the search twice. groupCount = webManager.getGroupManager().search(search).size(); }
// paginator vars int numPages = (int)Math.ceil((double)groupCount/(double)range); int curPage = (start/range) + 1; %>
<% if (request.getParameter("deletesuccess") != null) { %>
<div class="jive-success"> <table cellpadding="0" cellspacing="0" border="0"> <tbody> <tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0" alt=""></td> <td class="jive-icon-label"> <fmt:message key="group.summary.delete_group" /> </td></tr> </tbody> </table> </div><br>
<% } %>
<% if (webManager.getGroupManager().isSearchSupported()) { %>
<form action="group-summary.jsp" method="get" name="searchForm"> <table border="0" width="100%" cellpadding="0" cellspacing="0"> <tr> <td valign="bottom"> <fmt:message key="group.summary.total_group" /> <b><%= groupCount %></b> <% if (numPages > 1) { %>
, <fmt:message key="global.showing" /> <%= LocaleUtils.getLocalizedNumber(start+1) %>-<%= LocaleUtils.getLocalizedNumberstartrange > groupCount ? groupCount:start+range) %>
<% } %> </td> <td align="right" valign="bottom"> <fmt:message key="group.summary.search" />: <input type="text" size="30" maxlength="150" name="search" value="<%= ((search!=null) ? search : "") %>"> </td> </tr> </table> </form>
<script language="JavaScript" type="text/javascript"> document.searchForm.search.focus(); </script>
<% } // Otherwise, searching is not supported. else { %> <p> <fmt:message key="group.summary.total_group" /> <b><%= groupCount %></b> <% if (numPages > 1) { %>
, <fmt:message key="global.showing" /> <%= (start+1) %>-<%= (start+range) %>
<% } %> </p> <% } %>
<% if (numPages > 1) { %>
<p> <fmt:message key="global.pages" /> [ <% for (int i=0; i<numPages; i++) { String sep = ((i+1)<numPages) ? " " : ""; boolean isCurrent = (i+1) == curPage; %> <a href="group-summary.jsp?start=<%= (i*range) %><%= search!=null? "&search=" + URLEncoder.encode(search, "UTF-8") : ""%>" class="<%= ((isCurrent) ? "jive-current" : "") %>" ><%= (i+1) %></a><%= sep %>
<% } %> ] </p> |
DetailsAffected Software:WP Category Manager plugin Fixed in Version:1.3.1.0 Issue Type:Sql Injection Original Code: Found Here DescriptionThis week’s vulnerability affected the WP Category Manager plugin. There were two interesting characteristics I noticed with this code fix. First,while there were a number of SQL injection vulnerabilities fixed with this change list,there were also a large number of non security fixes included in this change list as well. It’s generally a good idea to keep security change lists separate from other change lists. The number of non security fixes included in this particular list was so distracting,I removed them from the post. The SQL injection fixes are pretty straight forward,changing dynamically built SQL statements into WordPress’ built-in $wpdb->prepare() function. The second characteristic that caught my attention was usage of numeric IDs at the end of SQL statements. For example: where object_id = $postId and term_taxonomy_id= $categoryId”;
This syntax creates a condition in which the typical addslashes() used to protect against SQL injection can be bypassed. For example,an attacker could craft a SQL injection string like: Sqli.php?categoryId=-1 union select 1,2,3,4,5–
As you can see,the injection string above contains no special characters that would be escaped by addslashes(). Fortunately,the Category Manager plugin developers chose to utilze $wpdb->prepare() instead of addslashes(). Developers Solution1 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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| <?php
include_once('wpcm-options.php');
if( ! class_exists('wpcm_functions')):
class wpcm_functions { public static function remove_category($postId,$categoryId) { - global $wpdb; - $wpdb->show_errors(); - $queryStr = "DELETE FROM $wpdb->term_relationships - where object_id = $postId and term_taxonomy_id= $categoryId"; + echo $postId;
- $wpdb->query($queryStr); + if(is_int(intval($postId))) + { + global $wpdb; + + $wpdb->show_errors(); + + $queryStr = $wpdb->prepare("DELETE FROM $wpdb->term_relationships where object_id = %d and term_taxonomy_id= %s",$postId,$categoryId); + $wpdb->query($queryStr); + } }
public static function get_posts($category,$page) { global $wpdb; $wpdb->show_errors();
// First figure out how many posts to show per page. This will be your limit $pageSize = wpcm_options::get_option('postsperpage');
$finalQueryLine = '';
if($pageSize != -1) { // Next figure out how many posts to skip. This will be your offset $offset = $pageSize * $page;
$finalQueryLine = "limit ". $pageSize . "offset ". $offset;
+ } + + $querystr = $wpdb->prepare("select wposts.*,wp_term_taxonomy.term_taxonomy_id + from $wpdb->posts wposts + LEFT JOIN $wpdb->term_relationships wp_term_relationships ON wposts.ID = wp_term_relationships.object_id + LEFT JOIN $wpdb->term_taxonomy wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id + LEFT JOIN $wpdb->terms wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id + WHERE wp_term_taxonomy.taxonomy = 'category' + and wp_terms.name = '%s' + and wposts.post_status='publish' + ORDER BY wposts.ID ". $finalQueryLine ,$category); + + $postlist = $wpdb->get_results($querystr); + return $postlist; } - $querystr = "select wposts.*,wp_term_taxonomy.term_taxonomy_id - from $wpdb->posts wposts - LEFT JOIN $wpdb->term_relationships wp_term_relationships ON wposts.ID = wp_term_relationships.object_id - LEFT JOIN $wpdb->term_taxonomy wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id - LEFT JOIN $wpdb->terms wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id - WHERE wp_term_taxonomy.taxonomy = 'category' - and wp_terms.name = '". $category . "' - and wposts.post_status='publish' - ORDER BY wposts.ID ". $finalQueryLine; - - $postlist = $wpdb->get_results($querystr); - return $postlist; }
public static function get_postCount($category) { global $wpdb; $wpdb->show_errors();
- $querystr = "select count(*) - from $wpdb->posts wposts - LEFT JOIN $wpdb->term_relationships wp_term_relationships ON wposts.ID = wp_term_relationships.object_id - LEFT JOIN $wpdb->term_taxonomy wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id - LEFT JOIN $wpdb->terms wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id - WHERE wp_term_taxonomy.taxonomy = 'category' - and wp_terms.name = '". $category . "' - and wposts.post_status='publish'"; + $querystr = $wpdb->prepare("select count(*) + from $wpdb->posts wposts + LEFT JOIN $wpdb->term_relationships wp_term_relationships ON wposts.ID = wp_term_relationships.object_id + LEFT JOIN $wpdb->term_taxonomy wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id + LEFT JOIN $wpdb->terms wp_terms ON wp_terms.term_id = wp_term_taxonomy.term_id + WHERE wp_term_taxonomy.taxonomy = 'category' + and wp_terms.name = '%s' + and wposts.post_status='publish'",$category);
$result = $wpdb->get_var($querystr,0,0); return $result;
}
public static function render_posts($postlist) { if($postlist) { foreach($postlist as $post) { echo '<div id="catmanagerpost'. $post->ID .'">'; echo '<span ><a href="'. get_permalink($post->ID) .'"title="'.$post->post_title . '">' . $post->post_title . '</a></span><span >' . date_format(date_create($post->post_date),"F j,Y") . '</span>'; echo '<p ><a href="javascript:void(0);"postID="'.$post->ID.'"catID="'. $post->term_taxonomy_id .'"id="catmanremovepost'. $post->ID .'"title="Remove post from this category">Remove</a>| '; echo edit_post_link('Edit Post','','',$post->ID); echo '</p></div>'; } } else { echo '<strong>No posts found</strong>'; } }
public static function render_postcount($category) { $count = wpcm_functions::get_postCount($category);
echo '<span id="wpcmpostcount">'.$count.'</span>'; }
public static function get_categories() { global $wpdb;
$wpdb->show_errors();
$querystr = "select wt.name,wt.term_id from $wpdb->terms wt join $wpdb->term_taxonomy wtt on wtt.term_id = wt.term_id where wtt.taxonomy = 'category' order by wt.name";
$catlist = $wpdb->get_results($querystr); return $catlist; } } endif;
?> |
DetailsAffected Software:AskApache Password Protect Fixed in Version: 4.3.2 Issue Type:Insecure Logging (Defense in Depth) Original Code: Found Here DescriptionThis week’s bug was discovered in the AskApache Password Protect plugin for WordPress. Once again,we are examining “security software” that is designed to provide various security protection mechanisms for a deployed WordPress blog. The description for the AskApache security plug-in is as follows: Advanced Security:Password Protection,Anti-Spam,Anti-Exploits,more to come
A very noble effort indeed This vulnerability was in the aa_pp_hashit() function. The aa_pp_hashit() function takes three arguments:$format,$user,and $pass. The aa_pp_hashit() function then attempts to create a hash containing the creds. Whenever I see functions utilizing crypto,I’m always reminded of this scene in Office Space . In this particular patch,vulnerability was in this line: aa_pp_mess(‘Created ‘.$format.’Hash for ‘.$user.’with Password ‘.$pass);
The aa_pp_mess() function actually logged the clear text username and password before putting it through a hashing function. There is rarely a need to log a clear text password… in fact,I’m going to go out on a limb here and say there is NEVER a good time when you should log a clear text password. Even password hashes or other weird representations of passwords shouldn’t be logged. Logging sensitive data is always tricky. If you’re logging sensitive data please consider the permissions required to access that sensitive data,ensure the file is properly ACL’d and conduct regular audits of log file access. Most importantly,ask yourself: Why do I need to log this data? The vulnerability was fixed by removing references to user password (and even references to the user that called the function). Now I just have to figure out why the AskApache devs are passing a default value for $pass Developers Solution1 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
| // aa_pp_hashit //------------------------------------------------------------------------------------------- function aa_pp_hashit($format,$user='',$pass=''){ global $aa_PP; - aa_pp_mess('Created '.$format.' Hash for '.$user.' with Password '.$pass); + aa_pp_mess('Created '.$format.' Hash'); $hash=''; switch ($format){ case 'TEST': $hash=array(); foreach($aa_PP['algorithms'] as $key=>$value)$hash[]=aa_pp_hashit($key,"test{$key}","test{$key}"); return $hash; break; case 'PLAIN': $hash=$user.':'.$pass; break; case 'CRYPT': $seed = NULL; for ($i = 0;$i <8;$i++) {$seed .= substr('0123456789abcdef',rand(0,15),1);} $hash=$user.':'.crypt($pass,"$1$".$seed); break; case 'SHA1': $hash=$user.':{SHA}'.base64_encode(pack("H*",sha1($pass))); break; case 'MD5':// php.net/crypt.php#73619 $saltt = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"),0,8); $len = strlen($pass);$text = $pass.'$apr1$'.$saltt;$bin = pack("H32",md5($pass.$saltt.$pass)); for($i = $len;$i >0;$i -= 16) { $text .= substr($bin,0,min(16,$i));} for($i = $len;$i >0;$i >>= 1) { $text .= ($i &1) ? chr(0):$pass{0};} $bin = pack("H32",md5($text)); for($i=0;$i<1000;$i++) { $new = ($i &1) ? $pass:$bin;if ($i % 3) $new .= $saltt;if ($i % 7) $new .= $pass;$new .= ($i &1) ? $bin:$pass;$bin = pack("H32",md5($new));} for($i=0;$i<5;$i++) { $k = $i + 6;$j=$i + 12;if($j==16){ $j = 5;} $TRp = $bin[$i].$bin[$k].$bin[$j].$TRp;} $TRp = chr(0).chr(0).$bin[11].$TRp; $TRp = strtr(strrev(substr(base64_encode($TRp),2)),"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); $hash="$user:$"."apr1"."$".$saltt."$".$TRp; break; }
return $hash; }//========================================================================================================================= // aa_pp_show_encryptions //------------------------------------------------------------------------------------------- function aa_pp_show_encryptions($label,$type=0){ global $aa_PP; if($type==0) { ?> <p><label><?php _e($label);?><br /> <select name="aapassformat"id="aapassformat"> <?php foreach($aa_PP['algorithms'] as $key=>$value){?> <option value="<?php echo $key;?>"<?php if($aa_PP['format']==$key)echo ' selected="selected"';elseif($aa_PP['algorithms'][$key]['enabled']!='1')echo ' disabled="disabled"';?>><?php echo $key;?> </option> <?php }?> </select> </label></p> <?php } elseif($type==3) { ?> <p><label><?php _e($label);?><br /> <input id="aapassformat"name="aapassformat"type="hidden"value="<?php echo $aa_PP['format'];?>"/></label></p> <ul> <?php foreach($aa_PP['algorithms'] as $key=>$value){?> <li><label><input name="aapassformat"id="aapassformat<?php echo strtolower($key);?>"type="radio"value="<?php echo $key;?>"<?php if($aa_PP['format']==$key)echo 'checked="checked"'; elseif($aa_PP['algorithms'][$key]['enabled']!='1')echo 'disabled="disabled"';?>/><strong><?php echo $key;?></strong>- <?php echo $aa_PP['algorithms'][$key]['desc'];?></label></li> <?php }?> </ul> <?php } else if($type==4) { ?> <h4><?php _e($label);?></h4> <?php foreach($aa_PP['algorithms'] as $key=>$value){?> <p><strong><?php echo $key;?></strong>- <?php echo $aa_PP['algorithms'][$key]['desc'];?></p> <?php }?> <hr style="visibility:hidden;padding-top:.25em;clear:both;"/> <?php } }//=========================================================================================================================
// aa_pp_mess //------------------------------------------------------------------------------------------- function aa_pp_mess($message=''){ if(@defined('AA_PP_DEBUG_LOGFILE'))error_log($message,3,AA_PP_DEBUG_LOGFILE); - else error_log($message); + else if(AA_PP_DEBUG)error_log($message) if(AA_PP_DEBUG){ ?><div id="message"style="margin:1em auto;"><p><?php echo $message;?></p></div><?php } }//========================================================================================================================= |
|