【漏洞分析】WordPress任意文件上传漏洞

影响版本: WordPress <= 2.8.5漏洞描述: BUGTRAQ ID: 37005 WordPress是一款免费的论坛Blog系统。 WordPress中负责上传文件的代码如下: wp-admin/includes/file.php: ---[cut]--- line 217: function wp_handle_upload( &$file, $overrides = false, $time = null ) { ---[cut]--- // All tests are on by default. Most can be turned off by $override[{test_name}] = \ false; $test_form = true; $test_size = true; // If you override this, you must provide $ext and $type!!!! $test_type = true; $mimes = false; ---[cut]--- // A properly uploaded file will pass this test. There should be no reason to \ override this one. if (! @ is_uploaded_file( $file['tmp_name'] ) ) return $upload_error_handler( $file, __( 'Specified file failed upload test.' \ )); // A correct MIME type will pass this test. Override $mimes or use the upload_mimes \ filter. if ( $test_type ) { $wp_filetype = wp_check_filetype( $file['name'], $mimes ); extract( $wp_filetype ); if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) ) return $upload_error_handler( $file, __( 'File type does not meet security guidelines. Try another.' )); if ( !$ext ) $ext = ltrim(strrchr($file['name'], '.'), '.'); if ( !$type ) $type = $file['type']; } else { $type = ''; } // A writable uploads dir will pass this test. Again, there's no point overriding \ this one. if ( ! ( ( $uploads = wp_upload_dir($time) ) && false === $uploads['error'] \ ) ) return $upload_error_handler( $file, $uploads['error'] ); $filename = wp_unique_filename( $uploads['path'], $file['name'], \ $unique_filename_callback ); // Move the file to the uploads dir $new_file = $uploads['path'] . "/$filename"; if ( false === @ move_uploaded_file( $file['tmp_name'], $new_file ) ) { return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $uploads['path'] ) \ ); } ---[cut ]--- 从上面代码可见所提供的文件名由$wp_filetype = wp_check_filetype( $file['name'], $mimes );执行检查。以下是wp_check_filetype()函数: wp-includes/functions.php: ---[cut]--- line 2228: function wp_check_filetype( $filename, $mimes = null ) { // Accepted MIME types are set here as PCRE unless provided. $mimes = ( is_array( $mimes ) ) ? $mimes : apply_filters( 'upload_mimes', \ array( 'jpg|jpeg|jpe' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', 'bmp' => 'image/bmp', 'tif|tiff' => 'image/tiff', 'ico' => 'image/x-icon', 'asf|asx|wax|wmv|wmx' => 'video/asf', 'avi' => 'video/avi', ---[cut, more mime types]--- line 2279: $type = false; $ext = false; foreach ( $mimes as $ext_preg => $mime_match ) { $ext_preg = '!\.(' . $ext_preg . ')$!i'; if ( preg_match( $ext_preg, $filename, $ext_matches ) ) { $type = $mime_match; $ext = $ext_matches[1]; break; } } return compact( 'ext', 'type' ); } 文件的类型被设置为匹配所提供扩展名的预定义MIME类型,扩展名是从匹配最后一个句号后mime ext.字符串的正则表达式获得的。如果$type列表中没有扩展名,$ext就会被设置为FALSE,wordpress会生成以下出错消息:“File type does not meet security guidelines. Try another”。 以下函数在文件上传之前对文件名执行了其他一些检查: $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback ); wp-includes/functions.php: line 2096: function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) { // sanitize the file name before we begin processing $filename = sanitize_file_name($filename); ---[cut, code that only matters if uploaded file already exists]--- line 2126: return $filename; } 如果要完全了解wordpress所执行的文件过滤,还要了解sanitize_file_name()函数: wp-includes/formatting.php: line 601: function sanitize_file_name( $filename ) { $filename_raw = $filename; $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", \ ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", \ chr(0)); $special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw); $filename = str_replace($special_chars, '', $filename); $filename = preg_replace('/[\s-]+/', '-', $filename); $filename = trim($filename, '.-_'); return apply_filters('sanitize_file_name', $filename, $filename_raw); } 过滤过程没有考虑到带有多个扩展名的文件,用户可以上传带有.php.jpg扩展名的任意PHP脚本,并通过直接请求上传的文件来执行恶意脚本。
posted @ 2011-08-10 13:51  Mr.Jim  阅读(1694)  评论(0编辑  收藏  举报