| 关键词: Nonce allowed html WordPress kses 管理员 超级 wp 数值 用户 |
WordPress是使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站。也可以把 WordPress当作一个内容管理系统(CMS)来使用。前些日子,RIPS放了一个WordPress5.1的CSRF漏洞通过本文将对此次CSRF漏洞进行详细分析,RCE相关的分析见后续分析文章 预备知识
比如,在评论中输入 ![]() ![]() 直接弹框 但是超级管理员在提交评论表单时,wordpress需要校验其Nonce值 想理解这个漏洞,首先要了解下wordpress的Nonce ( number used once )防御机制 Wordpress的Nonce ( number used once ) 机制,是用来防止CSRF而引进的。WordPress会为一些请求提供一个随机数进行校验,以防止未授权的请求的发生。
来看下wordpress的Nonce机制是如何使用的: 1、使用wp_create_nonce生成 nonce值: ![]() 可见,其实nonce值与$i、$action、$uid、$token有关 这里的$i 是nonce创建的时间相关变量,由wp_nonce_tick()生成,其余的$action、$uid、$token很好理解。 由这里我们可以看出,nonce的生成,与其操作也是有关系的
2、将生成的 nonce传递给需要提交时验证的前端模板 3、需要验证的表单被提交后,验证其中nonce,例如下图中,本次漏洞点 Nonce讲解完毕,言归正传,分析本次漏洞 漏洞分析
但从本次漏洞处来看,如下图 这里虽然没有通过Nonce的验证(wp_verify_nonce),但是并未终止操作。Wordpress在这里使用了两个过滤方法对后续的数据进行过滤。
至于为什么没有终止,而采用了如下的过滤逻辑,据说是因为WordPress其中有一些特殊的功能例如trackbacks and pingbacks会受到该值的影响,笔者没有进一步考究,感兴趣的同学可以自己分析下。
到目前为止,我们虽然没有合法的nonce值,但我们的payload仍然幸存, 接下来,看看逻辑里的 kses_init_filters()这个方法 超级管理员&非法Nonce情况:
![]()
果然进入下图断点
紧接着,进入如下断点 使用wp_filter_post_kses对输入的数据进行过滤 普通用户情况:
![]() 直接调用wp_filter_kses进行过滤
以上思路以及明朗了 超级管理员&合法nonce ->不做任何过滤 超级管理员&不合法nonce ->wp_filter_post_kses 普通用户 –>wp_filter_kses
先来看看普通用户提交和超级管理员无nonce提交时调用的过滤函数有什么区别
普通用户提交过滤函数:
超级管理员无nonce提交过滤函数:
可以看出只是wp_kses中第二个参数不同,一个是current_filter(),一个是’post’ 这里不同的,对应wp_kses中,应该是allowed_html参数值
这里举个普通用户评论的例子,普通用户提交评论,current_filter()方法返回的值是pre_comment_content,也就是说allowed_html参数值为pre_comment_content。可见下图动态调试结果 ![]() 对应的,超级管理员无nonce提交时,这里的allowed_html参数值为”post”
那么allowed_html值不同,到底会有什么区别呢? $allowed_html被传入wp_kses_split方法
进一步看wp_kses_split 注意到这里$pass_allowed_html = $allowed_html; 现在$allowed_html传给了$pass_allowed_html 我们要看看这两个不同的$allowed_html最终传递到哪里被用到
跟进_wp_kses_split_callback,$allowed_html传给了wp_kses_split2 跟进wp_kses_split2,$allowed_html被传给了wp_kses_attr 跟进wp_kses_attr,$allowed_html被传给了wp_kses_allowed_html 跟进wp_kses_allowed_html 一路跟踪,到了这里,$allowed_html终于有作用了 回顾一下, 超级管理员无nonce提交时,这里的allowed_html参数值为”post” 普通用户提交评论时, allowed_html参数值为”pre_comment_content”。 首先看超级管理员无nonce提交吗,allowed_html参数值为”post”,进入post分支 可以看到这里有一个wp_kses_allowed_html方法,跟进去看看 ![]() 相当于一个白名单机制,再看看白名单上都有什么,看看$allowedposttags ![]() 这里’a’标签运行’rel’属性
再看看普通用户提交评论时, allowed_html参数值为”pre_comment_content”情况。
这里白名单是$allowedtags ![]() 只允许’href’与’title’ 看到这里,明白wp_filter_post_kses 、wp_filter_ kses两个过滤函数有什么区别了吗?
可以用’rel’属性与不可以用’rel’,有什么区别呢?如何造成这次的csrf呢?看下图 wp-includesformatting.php ![]() 可以看到属性值在没有被转义处理的情况下就再次拼接在一起, 在a标签最终被拼接时,title的属性会被封装到双引号中,这样我们就可以构造数据使其闭合,从而执行js Payload: ![]() 被双引号包裹后 ![]() 单鼠标放置时,js执行
但是这个wp_rel_nofollow_callback哪里来的呢?
看一下wordpress对comment_content都采用了哪些默认的过滤器
wp-includesdefault-filters.php 上图三个分别是: wp_rel_nofollow convert_invalid_entities balanceTags
看下wp_rel_nofollow wp_rel_nofollow_callback是在这里被加载并使用的 结语
此次漏洞的流程是: (超级管理员&不合法nonce) ->(wp_filter_post_kses)->(’rel’属性在白名单中逃逸)->(wordpress加载默认评论内容过滤器wp_rel_nofollow)->(加载wp_rel_nofollow_callback) ->(未过滤并用双引号包裹title值)->(js执行)->(RCE |
| 本文出处: https://www.toutiao.com/a6810297047107764748/ |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|