WordPress <= 4.9.6 任意文件删除漏洞
最近 RIPS 团队公开了一个 WordPress 的任意文件删除漏洞(需要登录),目前该漏洞仍然未修复(2018年06月27日),该漏洞影响 Wordpress 最新版 4.9.6。
漏洞原理与危害
该漏洞出现的原因是由于在 WordPress 的 wp-includes/post.php
文件中 wp_delete_attachement()
函数在接收删除文件参数时未进行安全处理,直接进行执行导致。
function wp_delete_attachment( $post_id, $force_delete = false ) {
...
$meta = wp_get_attachment_metadata( $post_id );
...
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) );
}
}
...
}
如图所示,在 wp_delete_attachement()
中,unlink()
传入的 $meta['thumb']
,未经过任何过滤处理直接被调用。这段代码的目的是为了在删除图像的同时删除图像的缩略图。在 WordPress 中通过媒体管理器上传的图像被表示为附件类型的内容。$meta['thumb']
的值,从数据库中检索,并保存成表示图像的文章自定义字段。因此,在从数据库检索到 unlink()
函数调用之间表示缩略图文件名的值没有经过任何检查和过滤。如果该值在保存到数据库之前也没有经过对过滤不安全内容处理措施,将可能导致出现利用该功能执行任意文件删除。
...
switch($action) {
...
case 'editattachment':
check_admin_referer('update-post_' . $post_id);
...
// 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 上传目录的相对路径中,当附件被删除时,该文件将被删除。攻击者可利用此漏洞进而执行任意代码。
修复建议
可将下面的代码加载到当前主题的 function.php
中进行弥补:
add_filter('wp_update_attachment_metadata', function ($data){
if(isset($data['thumb'])){
$data['thumb'] = basename($data['thumb']);
}
return $data;
});