WP Super Cache远程代码执行漏洞分析
0x0漏洞简介
【产品描述】WP Super Cache是WordPress的一个插件,主要用来缓存加速网页数据的。
【受影响版本】<= 1.7.1
【漏洞摘要】管理后台再向缓存配置文件写入数据时过滤不严谨导致可以植入恶意代码,进而导致远程代码执行。
0x1 漏洞复现
首先登陆管理后台,找到WP Super Cache的设置页面,通常URL为 / w p − a d m i n / o p t i o n s − g e n e r a l . p h p ? p a g e = w p s u p e r c a c h e & t a b = s e t t i n g s \textcolor{cornflowerblue}{/wp-admin/options-general.php?page=wpsupercache\&tab=settings} /wp−admin/options−general.php?page=wpsupercache&tab=settings
在缓存路径设置一栏中插入恶意代码:$\textcolor{orange}{’;\$\_GET[c]
;#}$
点击更新,恶意代码会跟随缓存配置文件的更新一并写入到配置文件wp-cache-config.php中去。
通过访问当前页面并附上参数 c = c m d \textcolor{orange}{c=cmd} c=cmd(cmd表示要执行的命令)即可触发漏洞!
0x3 漏洞分析
漏洞关键代码位置: / w p − c o n t e n t / p l u g i n s / w p − s u p e r − c a c h e / w p − c a c h e . p h p : 586 \textcolor{orange}{/wp-content/plugins/wp-super-cache/wp-cache.php:586} /wp−content/plugins/wp−super−cache/wp−cache.php:586
if( isset( $_POST[ 'action' ] ) && $_POST[ 'action' ] == 'scupdates' ) {//在判断各数据不为空情况下写入数据
if( isset( $_POST[ 'wp_cache_location' ] ) && $_POST[ 'wp_cache_location' ] != '' ) {
/*
* dirname():获取文件(夹)所在的父目录
* trailingslashit():保证目录是以/结尾
*/
$dir = realpath( trailingslashit( dirname( $_POST[ 'wp_cache_location' ] ) ) );//先获取原来的缓存路径设置中的缓存位置所在的父目录
if ( $dir == false )
$dir = WP_CONTENT_DIR . '/cache/';
else
/*
* wpsc_deep_replace():将所有的..替换为\
* basename():获取路径尾部名称
*/
$dir = trailingslashit( $dir ) . trailingslashit(wpsc_deep_replace( array( '..', '\\' ), basename( $_POST[ 'wp_cache_location' ] ) ) );
$new_cache_path = $dir;
} else {
$new_cache_path = WP_CONTENT_DIR . '/cache/';
}
if ( $new_cache_path != $cache_path ) {
if ( file_exists( $new_cache_path ) == false )//重命名目录或文件
rename( $cache_path, $new_cache_path );
$cache_path = $new_cache_path;
wp_cache_replace_line('^ *\$cache_path', "\$cache_path = '" . $cache_path . "';", $wp_cache_config_file);//更新cache_path字段的数据
}
...
w p c a c h e r e p l a c e l i n e ( ) \textcolor{cornflowerblue}{wp_cache_replace_line()} wpcachereplaceline()函数实现在 / w p − c o n t e n t / p l u g i n s / w p − s u p e r − c a c h e / w p − c a c h e − p h a s e 2. p h p : 1183 \textcolor{orange}{/wp-content/plugins/wp-super-cache/wp-cache-phase2.php:1183} /wp−content/plugins/wp−super−cache/wp−cache−phase2.php:1183
function wp_cache_replace_line( $old, $new, $my_file ) {
if ( @is_file( $my_file ) == false ) {//判断配置文件是否存在
if ( function_exists( 'set_transient' ) ) {
set_transient( 'wpsc_config_error', 'config_file_missing', 10 );
}
return false;
}
...
$found = false;
$loaded = false;
$c = 0;
$lines = array();
while( ! $loaded ) {
$lines = file( $my_file );
if ( ! empty( $lines ) && is_array( $lines ) ) {
$loaded = true;
} else {
$c++;
if ( $c > 100 ) {
...
return false;
}
}
}
foreach( (array) $lines as $line ) {
if (
trim( $new ) != '' &&
trim( $new ) == trim( $line )
) {
wp_cache_debug( "wp_cache_replace_line: setting not changed - $new" );
return true;
} elseif ( preg_match( "/$old/", $line ) ) {
wp_cache_debug( "wp_cache_replace_line: changing line " . trim( $line ) . " to *$new*" );
$found = true;
}
}
$tmp_config_filename = tempnam( $GLOBALS['cache_path'], 'wpsc' );//创建一个唯一的文件,如果目录不存在,就会在系统临时目录中创建
rename( $tmp_config_filename, $tmp_config_filename . ".php" );
$tmp_config_filename .= ".php";
$fd = fopen( $tmp_config_filename, 'w' );//打开文件
if ( ! $fd ) {
...
}
if ( $found ) {
foreach( (array) $lines as $line ) {
if ( ! preg_match( "/$old/", $line ) ) {//正则匹配欲修改的字段
fputs( $fd, $line );
} elseif ( $new != '' ) {
fputs( $fd, "$new\n" );//更新字段,恶意代码被植入!
}
}
} else {
...
}
fclose( $fd );
rename( $tmp_config_filename, $my_file );//配置文件后缀为php
...
return true;
}
- 最终写入文件的数据:
$cache_path = 'F:\phpstudy_pro\WWW\wordpress\wp-content\cache/';`$_GET[c]`;#/';
- 一路分析下来,该插件将数据写入配置文件的过程中根本没有检查数据的合法性,所以造成了RCE。