Wordpress<=4.9.6 任意文件删除漏洞复现分析
第一章 漏洞简介及危害分析
1.1漏洞介绍
WordPress可以说是当今最受欢迎的(我想说没有之一)基于PHP的开源CMS,其目前的全球用户高达数百万,并拥有超过4600万次的超高下载量。它是一个开源的系统,其次它的功能也十分强大,源代码可以在这里找到。也正因为此,WordPress也成了众多黑客的攻击目标,一旦得手也就意味着数百万用户的沦陷。这种广泛的采用使其成为网络犯罪分子的一个有趣目标。这次实验的漏洞是在WordPress核心中的一个经过身份验证的任意文件删除漏洞CVE-2018-20714
该漏洞可能导致攻击者执行任意代码。该漏洞自发现到报告给WordPress安全团队7个月,但仍未修补。自首次报告以来已经过去很长时间没有任何补丁或具体计划。现在wordpress4.9.6及以下版本都存在此漏洞。
1.2漏洞的利用条件
为了利用下面讨论的漏洞,攻击者需要获得预先编辑和删除媒体文件的权限。也就是拥有作者权限。这里我们也要了解一下wordpress有哪些权限用户。
- 超级管理员(Super Admin) – 有权访问站点网络管理功能和所有其他功能。
- 管理员(Administrator) – 有权访问单个站点内的所有管理功能。
- 编辑(Editor) – 可以发布和管理帖子,包括其他用户的帖子。
- 作者(Author) – 可以发布和管理自己帖子。
- 贡献者(Contributor ) – 可以编写和管理他们自己的帖子但不能发布。
- 订阅者(Subscriber ) – 只能管理他们个人资料的人。
我们发现作者权限用户原本只可以发布和管理自己的帖子,但通过这个漏洞却可以劫持整个网站并在服务器上执行任意代码,也就是通过这个WordPress漏洞,黑客可轻松控制网站。
该漏洞存在于用户永久删除上传图像的缩略图时在后台运行的WordPress核心功能之一。
1.3漏洞的危害
至少一个作者帐户的要求会在某种程度上自动降低此漏洞的严重程度,这可能会被流氓内容撰稿人或黑客利用网络钓鱼,密码重用或其他攻击以某种方式获取作者的凭证所利用。
利用此漏洞可以使攻击者能够删除WordPress安装的任何文件(+ PHP进程用户具有删除权限的服务器上的任何其他文件)。除了擦除整个WordPress安装的可能性,如果没有可用的当前备份可能会带来灾难性的后果,攻击者可以利用任意文件删除的能力来规避一些安全措施并在Web服务器上执行任意代码。更准确地说,可以删除以下文件:
- .htaccess:通常,删除此文件不会产生任何安全后果。但是,在某些情况下,.htaccess文件包含与安全性相关的约束(例如,对某些文件夹的访问约束)。删除此文件将停用这些安全约束。
- index.php文件:通常将空的index.php文件放入目录中,以防止Web服务器无法执行此操作的目录列表。删除这些文件会向攻击者授予受此度量保护的目录中所有文件的列表。
- wp-config.php:删除WordPress安装的这个文件会在下次访问网站时触发WordPress安装过程。这是因为wp-config.php包含数据库凭据,并且没有它的存在,WordPress就像尚未安装一样。攻击者可以删除此文件,使用他为管理员帐户选择的凭据进行安装过程,最后在服务器上执行任意代码。
但是,应该注意的是,由于攻击者无法直接读取wp-config.php文件的内容来知道现有的“数据库名称”,“mysql用户名”及其“密码”,所以他可以重新设置目标站点在他的控制下使用远程数据库服务器。一旦完成,攻击者可以创建一个新的管理员帐户并完全控制网站,包括在服务器上执行任意代码的能力。“除了删除整个WordPress安装的可能性,如果没有当前的备份可用会造成灾难性的后果,攻击者可以利用任意文件删除的功能来规避一些安全措施并在Web服务器上执行任意代码
第二章 漏洞环境搭建及复现
2.1.搭建环境
前往wordpress中文官网https://cn.wordpress.org/download/releases/下载有此漏洞的版本
(1)安装wordpress
WordPress 4.9.6
安装成功后,在后台添加一个“作者”权限账户 “xy” 只有写作功能,用于测试
2.2漏洞复现测试
(1)用新添加的作者权限用户登陆到网站后台
(2)添加媒体,上传一张图片
(3)点击编辑
(4)在页面源码中找出 _wpnonce 值,通过页面源码查找 值为“388054b4f3”并将cookie复制下来。
(5)然后使用curl或burp构造http请求。
发送到repeater构造数据包然后发送post数据包 (需要带入cookie值)
payload: action=editattachment&_wpnonce=388054b4f3&thumb=../../../../wp-config.php'
POST /wp-admin/post.php?post=21&action=edit HTTP/1.1
发送成功会返回302状态
(6)此时在点击删除按钮
(7)抓包查看,也是返回302包
(8)再次访问主网站就会要求重新安装wordpress
第三章 漏洞代码审计以及临时手动修复
3.1 源码审计
(1)既然是任意文件删除漏洞,那我们就从删除功能入手,先来看wp-admin/post.php的246-268行:
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();
(2)由于我们删除的是图片附件,所以程序会进入wp_delete_attachment函数,跟进: wp-include/post.php,函数太长,只截取关键部分。
function wp_delete_attachment( $post_id, $force_delete = false ) {
....
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);
/** 该过滤器记录在wp-includes / functions.php中 */
$thumbfile = apply_filters( 'wp_delete_file', $thumbfile );
@ unlink( path_join($uploadpath['basedir'], $thumbfile) );
}
}
. . . .
wp_delete_file( $file );
$meta['thumb']来自与数据库,是图片的属性之一。代码未检查$meta['thumb']的内容,直接带入unlink函数,如果$meta['thumb']可控
(3) 那么可控点在哪呢?还记得漏洞利用的第一步吗?现在我们就回到wp-admin/post.php看一下具体代码
/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 );
//获取附件的属性
$newmeta['thumb'] = $_POST['thumb'];
wp_update_attachment_metadata( $post_id, $newmeta );
//更新数据库中的信息
代码片段/wp-admin/post.php
表示如何将属于附件的缩略图的文件名保存到数据库中。在从保存的用户输入检索$_POST[‘thumb’]
和保存到数据库wp_update_attachment_metadata()
之间,没有安全措施来确保该值确实代表正在编辑的附件的缩略图。值$_POST[‘thumb’]
可以变更修改为相对于WordPress上传目录的任何文件的路径,当附件被删除时,文件将被删除,如第一个列表中所示。
总结一句就是该漏洞出现的原因是由于在WordPress的wp-includes/post.php文件中wp_delete_attachement()
函数在接收删除文件参数时未进行安全处理,直接进行执行导致。
3.2临时手动修复
(1)在上面我们了解了漏洞生成的原因之后,我们将进行尝试性的漏洞修复。
首先针对漏洞细节提出修复方向
1. 过滤. \等关键字符
2. 挂钩wp_update_attachement_metadata()
调用并确保为meta[‘thumb’]
值提供的数据thumb
不包含任何可以进行路径遍历的部分.
3. 将$newmeta['thumb'] = $_POST['thumb'];改为$newmeta['thumb'] = basename($_POST['thumb']);
(2)修复代码
通过将修复程序添加到functions.php
当前活动的主题/子主题的文件中,可以将修复程序集成到现有的WordPress安装中。
add_filter('wp_update_attachment_metadata','rips_unlink_tempfix';
function rips_unlink_tempfix( $data ) {
if( isset($data['thumb']) ) {
$data['thumb'] = basename($data['thumb']);
}
return $data;
}
我们将补丁放入指定位置之后,再来测试漏洞。
可以看到在手动打了补丁之后,虽然发包和回显跟之前区别不大,但是已经无法任意删除文件了
第四章 漏洞操作的流量分析
总体操作与上文漏洞复现差不多,但为了监控流量和避免干扰便于分析,本次操作在虚拟机中进行并使用wireshark分析流量。
(1)使用wireshark捕获恶意操作的流量数据
服务器返回302
我们发现恶意数据最主要的特征就是向服务器传入了一个“thumb”自定义的值
(2)我们追踪这个包的tcp流
也出现了我们构造的关键代码,但由于这个漏洞可以删除任意文件,所以我们需要关注的就是thumb传入的数值,不管上传请求的方式是什么,总需要传入
thumb=xxxx
所以当流量中出现这些异常并指定thumb的值的时候,就需要引起我们的注意,要查看数值是否合法。