WordPress 5.0.0 远程代码执行

这篇博客详细介绍了路径遍历和本地文件包含漏洞的组合如何导致WordPress核心中的远程代码执行。这个漏洞在WordPress核心中暴露了6年多。

影响

攻击者可以访问目标WordPress站点上至少具有作者权限的帐户,并在底层服务器上执行任意PHP代码,从而导致完全的远程接管。我们向WordPress安全团队发送了关于WordPress核心中另一个漏洞的详细信息,该漏洞可以让攻击者准确地访问任何WordPress站点,该站点目前尚未修复。

谁受影响?

本文中解释的漏洞在版本4.9.95.0.1中的另一个安全补丁中无法利用。然而,路径遍历仍然是可能的,并且当前未修补。任何安装了插件的WordPress站点,如果不正确地处理Post Meta条目,仍然可以进行开发。在过去的WordPress 安全月的准备期间,我们已经看到有数百万活跃安装的插件犯了这个错误。

根据WordPress的下载页面显示,超过33%的网站使用该软件。考虑到插件可能会重新引入这个问题,并考虑到过时的站点等因素,受影响的安装数量仍然是数百万。

技术分析

我们领先的SAST解决方案在3分钟的扫描时间内通过单击一个按钮自动检测路径遍历和本地文件包含漏洞。然而,乍一看这些bug似乎不可利用。事实证明,漏洞的利用要复杂得多,但却是可能的。

请参阅RIPS扫描报告

https://demo-3.ripstech.com/scan/44/55/

背景 – WordPress 图片管理

当一个图片被上传到WordPress安装时,它首先被移动到上传目录(wp-content/uploads)。WordPress还将在数据库中创建图片的内部引用,以跟踪诸如图片所有者或上传时间等元信息。
这个元信息作为Post Meta条目存储在数据库中。每个条目都是一个key/value对,分配给某个ID

示例 Post Meta 对上传图片’evil.jpg’的引用

MariaDB [wordpress]> SELECT * FROM wp_postmeta WHERE post_ID = 50;
+---------+-------------------------+----------------------------+
| post_id | meta_key                | meta_value                 |
+---------+-------------------------+----------------------------+
|      50 | _wp_attached_file       | evil.jpg                   |
|      50 | _wp_attachment_metadata | a:5:{s:5:"width";i:450 ... |
...
+---------+-------------------------+----------------------------+

在本例中,已经为图片分配了post_ID 50。如果用户希望在将来使用或编辑具有该ID的图片,WordPress将查找匹配的_wp_attached_file元条目,并使用它的值来查找wp-content/upload目录中的文件。

核心问题 – Post Meta 可以被覆盖

WordPress 4.9.95.0.1之前,这些Post Meta条目的问题是可以修改任何条目并将它们设置为任意值。

当一个图片被更新(例如,它的描述被改变),edit_post()函数就会被调用,这个函数直接作用于$_POST数组。

可以更新任意 Post Meta 值

function edit_post( $post_data = null ) {

    if ( empty($postarr) )
        $postarr = &$_POST;if ( ! empty( $postarr['meta_input'] ) ) {
        foreach ( $postarr['meta_input'] as $field => $value ) {
            update_post_meta( $post_ID, $field, $value );
        }
    }

可以看到,可以插入任意Post Meta条目。由于没有检查修改了哪些条目,攻击者可以更新_wp_attached_file元条目并将其设置为任何值。这并不会以任何方式重命名该文件,它只会更改WordPress在编辑图片时要查找的文件,这将导致稍后的路径遍历。

通过修改的 Post Meta 进行路径遍历

当用户裁剪图片时调用wp_crop_image()函数函数,路径遍历就会发生在此函数中。函数获取要裁剪的图片的ID($attachment_id),并从数据库中获取相应的_wp_attached_file Post Meta条目。请记住,由于edit_post()中的缺陷,$src_file可以设置为任意值。

简化 wp_crop_image()函数,实际代码位于 wp-admin/includes/image.php 中:

function wp_crop_image( $attachment_id, $src_x, ...) {

    $src_file = $file = get_post_meta( $attachment_id, '_wp_attached_file' );

在下一步,WordPress必须确保图片确实存在并加载它。WordPress有两种加载给定图片的方法:第一种方法是在wp-content/upload目录中查找_wp_attached_file Post元条目提供的文件名(下一段代码的第2行)。
如果这个方法失败了,WordPress会尝试从它自己的服务器上下载图片作为备份。为此,它将生成一个下载URL,其中包含wp-content/upload目录的URL和存储在_wp_attached_file Post元条目中的文件名(第6行)。

举个具体的例子:如果存储在_wp_attached_file Post元条目中的值是evil.jpg,那么WordPress首先会尝试检查文件wp-content/uploads/evil.jpg是否存在。如果不存在,它将尝试从以下URL下载此文件:https://targetserver.com/wp-content/uploads/evil.jpg

尝试下载而不在本地查找图片的原因是,当URL被访问时,一些插件会动态生成图片,注意这里没有进行任何处理过滤。WordPress只需将上传目录和URL$src_file用户输入连接起来。一旦WordPress通过wp_get_image_editor()成功加载了一个有效的图片,便会将裁剪该图片。

...
if ( ! file_exists( "wp-content/uploads/" . $src_file ) ) {
        // If the file doesn't exist, attempt a URL fopen on the src link.
        // This can occur with certain file replication plugins.
        $uploads = wp_get_upload_dir();
        $src = $uploads['baseurl'] . "/" . $src_file;
    } else {
        $src = "wp-content/uploads/" . $src_file;
    }

$editor = wp_get_image_editor( $src );
...

裁剪后的图片保存回了文件系统中(无论是否下载)。生成的文件名将是get_post_meta()返回的$src_file值,该文件处于攻击者的控制之下。对生成的文件名字符串所做的唯一修改是,截取文件的basename(下一个代码片段的第4行)作为前缀。按照evil.jpg的示例,生成的文件名会是cropped-evil.jpg

WordPress然后通过wp_mkdir_p()(第6行)在结果路径中创建任何还不存在的目录。

最后使用图片编辑器对象的save()方法将其写入文件系统。save()方法也不对给定文件名执行路径遍历检查。

...
$src = $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs );
    
$dst_file = str_replace( basename( $src_file ), 'cropped-' . basename( $src_file ), $src_file );
    
wp_mkdir_p( dirname( $dst_file ) );
    
$result = $editor->save( $dst_file );

关于想法

到目前为止,我们已经讨论了将一个文件加载到图片编辑器中是可能的,因为没有执行任何检查处理。但是,如果文件不是有效的图片,图片编辑器将抛出异常。第一个假设是,只能在上传目录之外裁剪图片。但是,如果没有找到图片,WordPress会尝试下载,这会导致远程代码执行漏洞。

本地文件 HTTP 下载
上传的文件 evil.jpg evil.jpg
_wp_attached_file evil.jpg?shell.php evil.jpg?shell.php
生成将被加载的结果文件 wp-content/uploads/evil.jpg?shell.php https://targetserver.com/wp-content/uploads/evil.jpg?shell.php
实际位置 wp-content/uploads/evil.jpg https://targetserver.com/wp-content/uploads/evil.jpg
结果文件名 None – image loading fails evil.jpg?cropped-shell.php

想法是设置_wp_attached_fileevil.jpg?shell.php,这将导致对以下URL发出HTTP请求:https://targetserver.com/wp-content/uploads/evil.jpg?shell.php。此请求将返回有效的图片文件,因为?在此上下文中忽略了所有内容。生成的文件名将是evil.jpg?shell.php

然而,尽管图片编辑器的save()方法不检查路径遍历攻击,但它将把加载的图片的mime类型的扩展附加到结果文件名中。在这种情况下,生成的文件名将是evil.jpg?cropped-shell.php.jpg,这使得新创建的文件再次变得无害。
但是,仍然可以使用诸如evil.jpg?/.. ./evil.jpg之类的payload将生成的图片植入任何目录中。

主题目录中的路径遍历利用- LFI

每个WordPress主题仅仅是位于WordPresswp-content/themes目录中的一个目录,并为不同的情况提供模板文件。例如,如果博客的访问者想要查看博客文章,WordPress会在当前活动主题的目录中查找post.php文件。如果找到模板,将使用include()函数包含它。

为了添加额外的自定义层,可以为某些帖子选择自定义模板。为此,用户必须将数据库中的_wp_page_template Post Meta条目设置为自定义的文件名。
这里唯一的限制是,被include()函数包含过的文件必须位于当前活动主题的目录中。

通常,无法访问该目录,也无法上传文件。然而,通过滥用上面描述的路径遍历,可以将恶意制作的图片上传到当前使用的主题的目录中。然后攻击者可以创建一个新的文章并利用,使它能够更新_wp_attached_file Post Meta条目,进而包含此图片。通过向图片中注入PHP代码,攻击者可以获得任意的远程代码执行。

制作一个恶意的图片- GD vs Imagick

WordPress支持PHP的两个图片编辑扩展:GDImagick。它们之间的不同之处在于,Imagick不剥离可以存储PHP代码的图片的exif元数据。GD压缩它编辑的每个图片并删除所有exif元数据。这是GD处理图片的结果。然而exploit利用仍然是可能的,方法是创建一个包含精心制作的像素的图片,这些像素以一种方式翻转,一旦GD裁剪完图片,就会导致PHP代码执行。在我们研究PHPGD扩展的内部结构时,在libgd中发现了一个可利用的内存损坏缺陷。(cve-2019-69772)

总结

这篇博文详细介绍了WordPress核心中的远程执行代码,该代码已存在超过 6 年。对于RIPS5.0.14.9.9版本中报告的另一个漏洞的补丁,它变得不可利用。但是,路径遍历仍然可以使用,如果安装了仍允许覆盖任意Post Data的插件,则可以利用它。由于需要对目标WordPress站点进行某些身份验证以进行利用,因此我们决定在最初报告漏洞4个月后公开此漏洞。

我们要感谢WordPress安全团队的志愿者,他们在这个问题上与我们合作时非常友好并且专业。

这篇博客详细介绍了WordPress核心中一个存在了6年多的远程代码执行。随着版本5.0.14.9.9RIPS报告的另一个漏洞的补丁,它变得不可利用。然而,路径遍历仍然是可能的,如果安装的插件仍然允许覆盖任意Post数据,则可以利用该路径遍历。由于攻击需要对目标WordPress站点进行特定的身份验证,所以在最初报告漏洞4个月后,我们决定将漏洞公开。
我们要感谢WordPress安全团队的志愿者们,在这个问题上他们和我们一起工作时表现得非常友好和专业。

https://wordpress.org/download/ 
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6977

原文链接:

https://blog.ripstech.com/2019/wordpress-image-remote-code-execution/

2 条评论

发表评论

*

  • 目前POC 已经出来了。。。关键是一般的后台没有作者权限,有作者权限就有其他方法拿shell 了