| DetailsAffected Software:Dojo Toolkit Fixed in Version:1.4.1 Issue Type:Defense in Depth Original Code: Found Here DescriptionThis was a vulnerability affecting the Dojo toolkit. Apparently,the dojo toolkit shipped with a SWF file that had a few vulnerabilities. This particular vulnerability affected one of those SWF files. First,SWF files are compiled files,however they can be decompiled. Unlike traditional server side web application languages (PHP,ASP,JSP…etc),SWF files are downloaded and rendered on the clientside. Decompiling the SWF file gives the attacker full access to the ActionScript source code for the SWF application. In this particular SWF file,we see that the developers explicitly set the Security.allowDomain to “*”. This makes it so SWF flies from other,external domains can include the Dojo toolkit SWF file and script/access its internal functionality. The Dojo toolkit devs fixed this particular issue by removing the allowDomain call and adding an Externalinterface call checking to see if a particular wrapper was available in HTML. If you’re interested in Flash security,an excellent presentation on Flash security given by Stefano Di Paola can be found here: http://www.slideshare.net/guestb0af15/owasp-wasc-app-sec2007-san-jose-finding-vulnsin-flash-apps 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
| public class FLVideo extends Sprite { private var videoUrl:String; private var video:Video; private var connection:NetConnection; private var autoPlay:Boolean; private var videoStream:NetStream; private var videoWidth:Number; private var videoHeight:Number; private var _currentVideo:VideoContainer; private var preview:VideoContainer; private var currentVolume:Number = 1; private var isFullscreen:Boolean = false; private var playlist:VideoPlaylist; private var hasPlaylist:Boolean = false; private var mode:String = "preview";
public function FLVideo() { - Security.allowDomain("*"); + var secure:* = ExternalInterface.call("swfIsInHTML"); + if(secure !== true){ + return; + } + //Security.allowDomain("*");
stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; stage.addEventListener(Event.RESIZE,onStageResize); stage.addEventListener(FullScreenEvent.FULL_SCREEN ,onFullscreenChange); stage.addEventListener(MouseEvent.CLICK,onClick);
var obj:Object = LoaderInfo(this.root.loaderInfo).parameters; trace(obj)
if(!obj.videoUrl){ obj = { autoPlay:true, isDebug:true, videoUrl:"demo_video.flv" }; }
// ugh - booleans not coming through if(obj.autoPlay===true || obj.autoPlay=="true"){ autoPlay = true; }
if(obj.volume) { currentVolume = obj.volume; }
if(obj.isDebug===true || obj.isDebug=="true"){ console.isDebug(true); Tracer.init({both:true}) Tracer.log("FLVideo initialized...") }
+ Tracer.log("secure?::",secure) MovieIdentity.identity = obj.id || "default"; this.playlist = new VideoPlaylist(autoPlay,currentVolume);
if(obj.videoUrl) { videoUrl = obj.videoUrl; }
preview = new VideoContainer(videoUrl,autoPlay,currentVolume); addChild(preview); provideCallbacks(); }
public function get currentVideo():VideoContainer{
if(mode=="playlist"&&hasPlaylist){ return this.playlist.current; }else{ return preview; } } |
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: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 } }//========================================================================================================================= |
DetailsAffected Software:Login LockDown for WordPress Fixed in Version: 1.5 Issue Type:SQL Injection Original Code: Found Here DescriptionThis week’s code sample comes from the “Login Lockdown” plug-in for WordPress. It’s always interesting when “security” software ends up having serious security flaws…. This patch contained several bug fixes. The first bug fix we see in the patch is the inclusion of nonce checking to prevent CSRF. It’s difficult to detect CSRF vulnerabilities by looking at individual function logic and it’s ok if the reader missed these bugs. CSRF token validation should be done at the framework level and including CSRF nonce validation in the logic of every function can quickly become unwieldy. If an application wide CSRF solution cannot be implemented at the framework level,then auditing for CSRF must be done at a function by function level. Personally,I prefer to check for CSRF vulnerabilities by identifying any function that performs a Create,Update,or Delete operation,mapping those functions back to the HTML markup and checking the markup to see if a nonce is passed as part of the POST or GET request. This is of course is done after an extensive audit of the nonce validation code. The bugs that should have been spotted by the spotthevuln reader are the SQL injection and the XSS vulnerabilities in the code. The SQL Injection is pretty straight forward. The “releaseme” POST parameter is taken and is eventually passed directly to a dynamically built SQL statement without any sanitization. The developers fixed the vulnerability by utilizing the WordPress escape logic. Finally,the last line of the code snippet actually contained an XSS vulnerability,echoing a $_SERVER variable without any sanitization. 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
| function print_loginlockdownAdminPage() { global $wpdb; $table_name = $wpdb->prefix . "lockdowns"; $loginlockdownAdminOptions = get_loginlockdownOptions();
if (isset($_POST['update_loginlockdownSettings'])) {
+ //wp_nonce check + check_admin_referer('login-lockdown_update-options');
if (isset($_POST['ll_max_login_retries'])) { $loginlockdownAdminOptions['max_login_retries'] = $_POST['ll_max_login_retries']; } if (isset($_POST['ll_retries_within'])) { $loginlockdownAdminOptions['retries_within'] = $_POST['ll_retries_within']; } if (isset($_POST['ll_lockout_length'])) { $loginlockdownAdminOptions['lockout_length'] = $_POST['ll_lockout_length']; } if (isset($_POST['ll_lockout_invalid_usernames'])) { $loginlockdownAdminOptions['lockout_invalid_usernames'] = $_POST['ll_lockout_invalid_usernames']; } if (isset($_POST['ll_mask_login_errors'])) { $loginlockdownAdminOptions['mask_login_errors'] = $_POST['ll_mask_login_errors']; } update_option("loginlockdownAdminOptions",$loginlockdownAdminOptions); ?> <div><p><strong><?php _e("Settings Updated.","loginlockdown");?></strong></p></div> <?php } if (isset($_POST['release_lockdowns'])) {
+ //wp_nonce check + check_admin_referer('login-lockdown_release-lockdowns'); if (isset($_POST['releaseme'])) { $released = $_POST['releaseme']; foreach ( $released as $release_id ) { $results = $wpdb->query("UPDATE $table_name SET release_date = now() ". - "WHERE lockdown_ID = $release_id"); + "WHERE lockdown_ID = ". $wpdb->escape($release_id) . ""); } } update_option("loginlockdownAdminOptions",$loginlockdownAdminOptions); ?> <div><p><strong><?php _e("Lockdowns Released.","loginlockdown");?></strong></p></div> <?php } $dalist = listLockedDown(); ?> <div> -<form method="post"action="<?php echo $_SERVER["REQUEST_URI"];?>"> +<form method="post"action="<?php echo esc_attr($_SERVER["REQUEST_URI"]);?>"> |
|