Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20130326192938.GB15070@kludge.henri.nerv.fi>
Date: Tue, 26 Mar 2013 21:29:38 +0200
From: Henri Salo <henri@...v.fi>
To: oss-security@...ts.openwall.com
Subject: CVE request: WordPress plugin user-photo file upload arbitrary PHP
 code execution

Hello Kurt and list members,

Can I get CVE identifier for WordPress plugin user-photo file upload arbitrary
PHP code execution security vulnerability. Different issue than CVE-2012-2920.

References:
    http://osvdb.org/71071
    http://seclists.org/fulldisclosure/2011/Feb/354

Affected: 0.9.4 (older probably affected too)
OSVDB currently lists fixed version as 0.9.5.1, but fixed in version is 0.9.5
Discovery date: 2010-07-01
Vendor informed date: 2011-01-27
Time to exploit: 231 days

Someone had fun for a long time. Should get CVE-2011-XXXX, yes?

By looking at the patch for example lines below can be bypassed using null
character in the filename:

+      else if( !preg_match("/\.(" . join('|', $userphoto_validextensions) . ")$/i", $_FILES['userphoto_image_file']['name']) ){
+        $error = sprintf(__("The file extension &ldquo;%s&rdquo; is not allowed. Must be one of: %s.", 'user-photo'), preg_replace('/.*\./', '', $_FILES['userphoto_image_file']['name']), join(', ', $userphoto_validextensions));
+      }

Line below renames the file to e.g. 1.jpg so it should not be executable in well
configured www-server:

+          $imagefile = "$userID." . preg_replace('{^.+?\.(?=\w+$)}', '', strtolower($_FILES['userphoto_image_file']['name']));

Whole diff below:

"""
 Plugin Name: User Photo
 Plugin URI: http://wordpress.org/extend/plugins/user-photo/
 Description: Allows users to associate photos with their accounts by accessing their "Your Profile" page. Uploaded images are resized to fit the dimensions specified on the options page; a thumbnail image is also generated. New template tags introduced are: <code>userphoto_the_author_photo</code>, <code>userphoto_the_author_thumbnail</code>, <code>userphoto_comment_author_photo</code>, and <code>userphoto_comment_author_thumbnail</code>. Uploaded images may be moderated by administrators.
-Version: 0.9.4
-Author: <a href="http://weston.ruter.net/">Weston Ruter</a>, <a href="http://dev.dave-wagner.com/">Dave Wagner's Dev Site</a>
+Version: 0.9.5
+Author: <a href="http://weston.ruter.net/">Weston Ruter</a>
 
 Original code by Weston Ruter <http://weston.ruter.net> at Shepherd Interactive <http://shepherd-interactive.com>.
-Continued development and maintenance by Dave Wagner <http://dev.dave-wagner.com/>
+Continued development and maintenance by Dave Wagner (cptnwinky) <http://dev.dave-wagner.com/>
 
 GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
 This program is free software; you can redistribute it and/or modify
@@ -47,6 +47,7 @@
   "image/png" => true,
   "image/x-png" => true
 );
+$userphoto_validextensions = array('jpeg', 'jpg', 'gif', 'png');
 
 define('USERPHOTO_PENDING', 0);
 define('USERPHOTO_REJECTED', 1);
@@ -316,6 +317,7 @@ function userphoto_thumbnail($user, $before = '', $after = '', $attributes = arr
 
 function userphoto_profile_update($userID){
   global $userphoto_validtypes;
+  global $userphoto_validextensions;
   global $current_user;
   
   $userdata = get_userdata($userID);
@@ -376,10 +378,15 @@ function userphoto_profile_update($userID){
             $error = __("File upload failed due to unknown error.", 'user-photo');
         }
       }
-      else if(!$_FILES['userphoto_image_file']['size'])
+      else if( !$_FILES['userphoto_image_file']['size'] ){
         $error = sprintf(__("The file &ldquo;%s&rdquo; was not uploaded. Did you provide the correct filename?", 'user-photo'), $_FILES['userphoto_image_file']['name']);
-      else if(@!$userphoto_validtypes[$_FILES['userphoto_image_file']['type']]) //!preg_match("/\.(" . join('|', $userphoto_validextensions) . ")$/i", $_FILES['userphoto_image_file']['name'])) ||
+      }
+      else if( !preg_match("/\.(" . join('|', $userphoto_validextensions) . ")$/i", $_FILES['userphoto_image_file']['name']) ){
+        $error = sprintf(__("The file extension &ldquo;%s&rdquo; is not allowed. Must be one of: %s.", 'user-photo'), preg_replace('/.*\./', '', $_FILES['userphoto_image_file']['name']), join(', ', $userphoto_validextensions));
+      }
+      else if( @!$userphoto_validtypes[$_FILES['userphoto_image_file']['type']] ){
         $error = sprintf(__("The uploaded file type &ldquo;%s&rdquo; is not allowed.", 'user-photo'), $_FILES['userphoto_image_file']['type']);
+      }
       
       $tmppath = $_FILES['userphoto_image_file']['tmp_name'];
       
@@ -414,8 +421,10 @@ function userphoto_profile_update($userID){
         #umask($umask);
         
         if(!$error){
-          #$oldFile = basename($userdata->userphoto_image_file);
-          $imagefile = preg_replace('/^.+(?=\.\w+$)/', $userdata->user_nicename, strtolower($_FILES['userphoto_image_file']['name']));
+          $oldimagefile = basename($userdata->userphoto_image_file);
+          $oldthumbfile = basename($userdata->userphoto_thumb_file);
+          #$imagefile = preg_replace('/^.+(?=\.\w+$)/', $userdata->user_nicename, strtolower($_FILES['userphoto_image_file']['name']));
+          $imagefile = "$userID." . preg_replace('{^.+?\.(?=\w+$)}', '', strtolower($_FILES['userphoto_image_file']['name']));
           $imagepath = $dir . '/' . $imagefile;
           $thumbfile = preg_replace("/(?=\.\w+$)/", '.thumbnail', $imagefile);
           $thumbpath = $dir . '/' . $thumbfile;
@@ -448,7 +457,7 @@ function userphoto_profile_update($userID){
                 $admin = get_userdata($admin_notified);
                 @wp_mail($admin->user_email,
                          "User Photo for " . $userdata->display_name . " Needs Approval",
-                         get_option("home") . "/wp-admin/user-edit.php?user_id=" . $userdata->ID . "#userphoto");
+                         get_option("siteurl") . "/wp-admin/user-edit.php?user_id=" . $userdata->ID . "#userphoto");
               }
             }
             else {
@@ -460,9 +469,12 @@ function userphoto_profile_update($userID){
             update_usermeta($userID, "userphoto_thumb_file", $thumbfile);
             update_usermeta($userID, "userphoto_thumb_width", $thumbinfo[0]);
             update_usermeta($userID, "userphoto_thumb_height", $thumbinfo[1]);
-      
-            #if($oldFile && $oldFile != $newFile)
-            #  @unlink($dir . '/' . $oldFile);
+            
+            //Delete old thumbnail if it has a different filename (extension)
+            if($oldimagefile != $imagefile)
+              @unlink($dir . '/' . $oldimagefile);
+            if($oldthumbfile != $thumbfile)
+              @unlink($dir . '/' . $oldthumbfile);
           }
         }
       }
"""

--
Henri Salo

Download attachment "signature.asc" of type "application/pgp-signature" (199 bytes)

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.