文章来源:https://blog.ripstech.com/2019/wordpress-csrf-to-rce/?utm_medium=CPC&utm_source=Twitter&utm_campaign=275844&utm_content=WordPress%205.1%20CSRF%20to%20Remote%20Code%20Execution


前言

上个月我们公开了WordPress 5.0中需要身份验证的远程代码执行漏洞。这篇博文将揭露另WordPress 5.1的另一个高危漏洞链,允许未经身份验证的攻击者在WordPress 5.1.1之前的任何版本获取远程代码执行。

影响

通过诱导该站点管理员访问攻击者设置的网站,攻击者可以接管任何启用评论的WordPress站点。只要受害管理员访问恶意网站,一个针对WordPress博客的跨站请求伪造(CSRF)漏洞就会在后台运行,并且受害者浑然不觉。这个CSRF漏洞利用了多个逻辑缺陷和过滤的错误,当组合起来时导致远程代码执行从而接管目标站点。

这些漏洞存在于WordPress 5.1.1以前的所有版本,并且可以通过默认设置进行攻击。

WordPress被互联网上超过33%的网站使用,它的下载页面如是说。考虑到评论是博客的一项核心功能并且默认开启,此项漏洞将影响数百万个站点。

技术分析

评论形式的CSRF导致HTML注入

用户发表新评论时WordPress没有进行CSRF验证。这是因为如果评论处存在验证,一些WordPress功能(比如说trackbacks and pingbacks)将无法使用。因此,攻击者通过CSRF攻击能够使用WordPress博客的某个管理员用户的身份来创建评论。

这能够演变成一个安全事故,因为WordPress博客的管理员们可以在评论处使用任意HTML标签,甚至是<script>。从理论上说,攻击者能滥用该CSRF漏洞来创建一个含有恶意JS代码的评论。

WordPress尝试通过在评论表单处为管理员创建一个额外的nonce来解决这个问题。管理员携带有效的nonce提交评论时,这个评论将不会进行任何过略。如果nonce是无效的,那么这个评论仍然可以创建但是会被过滤处理。

下面是WordPress核心中的部分解决代码:

⋮
if ( current_user_can( 'unfiltered_html' ) ) {
    if (! wp_verify_nonce( $_POST['_wp_unfiltered_html_comment'], 'unfiltered-html-comment' )) {
        $_POST['comment'] = wp_filter_post_kses($_POST['comment']);
    }
} else {
    $_POST['comment'] = wp_filter_kses($_POST['comment']);
}
⋮

事实上早在2009年,我们都知道评论表单中已经不存在CSRF保护了。

然而,我们在管理员消毒程序中发现了一个逻辑缺陷。正如你在代码片段所见,评论一直使用wp_filter_kses()来消毒,除非评论者是管理员时才会使用unfiltered_html。如果是这种情况并且管理员没有提供有效的nonce,那么将使用wp_filter_post_kses()代替消毒(上述代码块的第四行)。

wp_filter_post_kses()wp_filter_kses()的不同之处是过滤程度。这两个函数都允许未消毒的评论,但是字符串只能是属于一个确定的HTML标签和属性列表。通常wp_filter_kses()函数对评论消毒时只允许一些基本的HTML标签和属性,例如<a>标签结合href属性使用。

另一个函数允许包含更多的HTML标签和属性。但是尽管wp_filter_post_kses()权限更宽松,一些可以导致跨站脚本漏洞的标签仍然会被删除。

HTML注入到储存型XSS

事实上我们仍然可以注入额外的HTML标签和属性来造成WordPress核心的储存型XSS漏洞。这是因为一些属性即使不允许在评论处设置,但是仍然可以被错误解析和操作,从而导致任意属性注入。

WordPress完成评论消毒后,它将会修改<a>标签以实现搜索引擎优化。

这是通过解析<a>标签的属性字符串(比如href="#" title="some link" rel="nofollow")到一个关联数组来实现的(下面代码第三行),其中key为属性名value为属性值。

function wp_rel_nofollow_callback( $matches ) {
    $text = $matches[1];
    $atts = shortcode_parse_atts($matches[1]);
    ⋮

WordPress然后回检查rel属性是否设置。只有评论是以wp_filter_post_kses()函数过滤的,该属性才可以被设置。如果存在,那么rel标签将会和<a>标签放在一起。

if (!empty($atts['rel'])) {
        // the processing of the 'rel' attribute happens here
        ⋮
        $text = '';
        foreach ($atts as $name => $value) {
            $text .= $name . '="' . $value . '" ';
        }
    }
    return '<a ' . $text . ' rel="' . $rel . '">';
}

此缺陷对映上述代码块中的第5,6行,其属性值被连接在一起而没有被转义。

攻击者可以创建一个含有<a>的评论,比如说设置title属性锚点为title='XSS " onmouseover=alert(1) id="'。该属性是有效的HTML并且可以通过消毒步骤。然而,构造的title标签使用单引号时才有效。

当这些标签组合在一起,title属性将被双引号包装起来(第六行)。因此,攻击者能够通过注入额外的双引号关闭title属性来注入额外的HTML属性。

举个例子:<a title='XSS " onmouseover=evilCode() id=" '>经过处理后会变成<a title="XSS " onmouseover=evilCode() id=" ">

因为此时评论已经经过消毒处理,所以注入的onmouseover事件程序已经储存到数据库中。这允许攻击者通过CSRF漏洞和过略缺陷注入储存型XSS有效载荷到目标网站。

通过iframe执行XSS

只要管理员查看注入JS代码的恶意评论,攻击者就能够获取远程代码执行。此评论展示在目标WordPress博客的前端。对于WordPress本身来说,前端并不受X-Frame-Options保护。因此,恶意评论可以储存在一个不可见的<iframe>中,并且此<iframe>储存在攻击者控制的网站中。因为注入的属性是一个onmouseover事件程序,攻击者可以制作<iframe>标签结合受害者鼠标移动来触发XSS有效载荷。

这允许攻击者加载目标网站触发CSRF漏洞的管理员会话执行任意JS代码。所有的JS代码都在后台执行,受害者浑然不觉。

从XSS到远程代码执行

现在我们可使用管理员会话执行任意JS代码,因此实现远程代码执行变得简单起来了。WordpRress在后台管理页面默认允许博客管理员直接编辑主题和插件的.php文件。只需简单地插入一个PHP后门,攻击者就能实现任意PHP代码执行。

补救措施

默认情况下,WordPress会自动安装补丁,你应该已经是5.1.1版本了。但是如果你由于某种原因不能更新,那么在升级前你应该禁用评论功能。最重要的一点,在浏览其他网站前确保注销管理员会话。

总结

本文详细阐述了一个CSRF漏洞起始的漏洞链。此漏洞链允许任何WordPress站点在默认设置情况下被攻击者接管,只需目标网站管理员访问一个恶意网站,并且受害者在攻击者控制的网站上不会发现任何异常。除了访问攻击者设置的网站以外,不需要任何形式的交互。

时间线

  • 2018/10/24 报告WordPress,通过CSRF可以注入更多的HTML标签
  • 2018/10/25 Hackone上,WordPress团队确认了此漏洞
  • 2019/02/05 WordPress准备发布补丁,请求我们的建议
  • 2019/03/01 报告WordPress,HTML注入可导致存储型XSS漏洞
  • 2019/03/01 WordPress反馈:安全团队已了解并准备发布补丁
  • 2019/03/13 发布WordPress 5.1.1

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖