WordPress 5.1漏洞:从CSRF到远程代码执行
导语:上个月,我们在WordPress 5.0中发布了一个需经过身份验证的远程代码执行(RCE)漏洞。本文主要讲解了WordPress 5.1的另一个关键漏洞利用链,使得未经身份验证的攻击者能针对5.1.1之前任意版本的WordPress实现远程代码执行。
一、概述
上个月,我们在WordPress 5.0中发布了一个需经过身份验证的远程代码执行(RCE)漏洞。本文主要讲解了WordPress 5.1的另一个关键漏洞利用链,使得未经身份验证的攻击者能针对5.1.1之前任意版本的WordPress实现远程代码执行。
二、影响
攻击者可以通过诱导目标网站的管理员访问攻击者设置的网站,以实现接管任意WordPress站点。一旦受害管理员访问恶意网站,恶意网站就会在后台针对目标WordPress站点执行跨站请求伪造(CSRF)漏洞利用,这一漏洞利用不会被受害者发现。该CSRF漏洞利用方式利用了多个逻辑缺陷和清理(Sanitization)错误,这些错误组合后将导致远程代码执行和站点的完全接管。
这些漏洞存在于5.1.1之前版本的WordPress中,在默认配置的版本中就可以被利用。
根据WordPress的官方下载页面显示,有超过33%的互联网网站使用WordPress。考虑到评论是WordPress的核心功能,并且默认情况下会启用,因此推测该漏洞将影响数百个网站。
三、技术分析
视频:https://blog.ripstech.com/videos/wordpress-csrf-to-rce.mp4
3.1 评论表单中存在CSRF漏洞导致HTML注入
当用户发表新评论时,WordPress不会执行防CSRF的验证。这是因为,如果存在任何验证,某些WordPress功能(例如Trackbacks和Pingbacks)将会被破坏。这意味着,攻击者可以通过CSRF攻击,以WordPress站点管理员用户的名义发表评论。
这可能会产生安全问题,因为WordPress站点的管理员用户可以在评论中使用任意HTML标签,甚至是<script>标签。理论上,攻击者可能会滥用CSRF漏洞来创建包含恶意JavaScript代码的评论。
WordPress尝试通过在评论表单中为管理员生成额外的nonce来解决此漏洞。当管理员提交评论并提供有效的nonce时,将会直接创建评论,而不经过任何清理。如果nonce无效,则仍然会创建评论,但创建前会对其进行清理。
下面代码展示了WordPress核心中是如何处理这一步骤的,代码位于/wp-includes/comment.php,已经经过简化:
⋮ 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防护。
但是,我们在管理员的清理(Sanitization)过程中发现了一个逻辑缺陷漏洞。正如大家在上述代码片段中所看到的,除非创建评论的用户是具有unfiltered_html功能的管理员,否则评论会始终使用wp_filter_kses()进行清理。如果是这种情况,并且没有提供有效的随机数,则会使用wp_filter_post_kses()来代替(上述代码的第4行)。
wp_filter_post_kses()和wp_filter_kses()之间的区别在于二者的严格程度。这两个函数都接受未经过清理的注释,并且只在字符串中保留选定的HTML标签和属性列表。通常,使用wp_filter_kses()清除注释,wp_filter_kses()仅允许非常基本的HTML标签和属性,例如<a>标签与href属性的组合。
这通常允许攻击者创建评论,这些评论与通常情况下允许提交的评论相比,可以包含更多的HTML标签和属性。但是,尽管wp_filter_post_kses()的限制更加宽松,但它仍然会删除任何可能导致跨站脚本漏洞的HTML标签和属性。
3.2 将其他HTLM注入升级为存储型XSS
我们仍然可以注入额外的HTML标签和属性,这一事实会导致WordPress核心中存在存储型XSS漏洞。这是因为,通常无法在评论中设置的某些属性会被以错误的方式进行解析和操作,从而导致任意属性注入。
完成WordPress的评论清理之后,它将修改评论字符串中的<a>标签,进行优化,从而实现SEO(搜索引擎优化)的目的。
具体来说,这一过程是通过将<a>标签的属性字符串(例如:href="#" title="some link" rel="nofollow")解析为关联数组(下面代码片段的第3行)来完成的,其中的关键是属性名称和属性值。
wp-includes/formatting.php:
function wp_rel_nofollow_callback( $matches ) { $text = $matches[1]; $atts = shortcode_parse_atts($matches[1]); ⋮
随后,WordPress将检查是否设置了rel属性。只有在wp_filter_post_kses()过滤了注释时,才能设置此属性。如果设置了rel属性,则会将其进行处理,然后将<a>标志放回原位。
wp-includes/formatting.php:
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>标签,并将anchor的title属性设置为title='XSS " onmouseover=alert(1) id="'。这个属性在HTML中是有效的,并且可以通过清理的步骤。但是,这只是因为精心制作的title标签使用了单引号。
当属性被重新组合在一起时,title属性的值会以双引号括起来(上述代码的第6行)。这意味着,攻击者可以通过注入额外的双引号,来关闭title属性,从而注入其他HTML属性。
例如:<a title='XSS " onmouseover=evilCode() id=" '>经过处理后,将会变为<a title="XSS " onmouseover=evilCode() id=" ">。
3.3 通过iframe直接执行XSS
要获取远程代码执行,攻击者在创建恶意评论后,下一步就是要使管理员执行注入的JavaScript。评论内容将会显示在目标WordPress站点的前端。WordPress自身不会受到X-Frame-Options标头的保护。这意味着,评论可以显示在攻击者网站上隐藏的<iframe>中。由于注入的属性是onmouseover(鼠标指针移动到元素上)Event Handler,所以攻击者可以使iframe跟随受害者的鼠标,并立即触发XSS Payload。
这允许攻击者利用在目标住哪点上触发CSRF漏洞的管理员会话,执行任意JavaScript代码。所有JavaScript执行都在后台进行,并且受害者管理员无法注意到这一点。
3.4 将JavaScript执行升级为远程代码执行
现在,可以使用管理员的会话执行任意JavaScript代码,从而轻松实现远程代码执行。默认情况下,WordPress允许站点管理员直接在管理仪表盘上编辑主题和插件的.php文件。只需要简单地插入PHP后门,攻击者就可以在远程服务器上获得任意PHP代码执行。
四、修复方式
默认情况下,WordPress会自动安装安全更新。在更新安装后,最新版本应该为5.1.1。如果服务器或托管服务商出于某种原因禁用了自动更新功能,那么可以在安装安全修复程序之前禁用评论功能。最重要的是,需要管理员注意,在访问其他网站前务必注销管理员会话。
五、时间节点
2018年10月24日 在Hackerone上,报告利用CSRF漏洞在WordPress中实现更多HTML标签的注入。
2018年10月25日 WordPress对这一漏洞进行了分类。
2019年2月5日 WordPress发布补丁,我们对这一补丁进行了评估和反馈。
2019年3月1日 通知WordPress我们成功将额外的HTML注入升级为存储型XSS漏洞。
2019年3月1日 WordPress通知我们,WordPress安全团队的一名成员已经发现该问题,并且已经准备好补丁。
2019年3月13日 WordPress 5.1.1发布安全补丁。
六、总结
本文详细介绍了一个由CSRF漏洞引发的漏洞利用链。该利用链允许任何具有默认设置的WordPress站点被攻击者接管,只需要事先引诱该网站的管理员访问恶意网站即可。受害管理员不会在攻击者的恶意网站上发现任何可疑之处。除了访问攻击者创建的网站之外,不需要进行任何其他形式的交互。
最后,我们要感谢WordPress安全团队,他们在这一漏洞问题上,与我们进行了非常友好以及专业的合作。
发表评论