欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

WordPress-5.1.1-CSRF-To-RCE安全事件详析

来源:本站整理 作者:佚名 时间:2019-03-25 TAG: 我要投稿

0×01 概述
1.1 前言
2019 年 3 月 13 号,RIPS 又放了一个 WordPress 的 CSRF,与此同时 WordPress 官方也提交相应的 Commit,算是一个比较新的洞。问题出在文章的评论上,其实是有防 CSRF 相应的 wpnonce,熟悉 wp 的人肯定不会陌生 wpnonce,这是 wp 的防御机制,动作和postid构成的token,用来验证reference,而且 wordpress 对标签的过滤机制比较严格的。白名单机制,列如 a 标签的名单为:

看起来是比较严格的,基本带动作的标签不可能出现,插不进 js。比较有趣是两个对评论的 filter 组合起来造成了,a 标签中的属性逃逸。RIPS 文章也说的比较简单,接下来看看具体的实现过程,其实存在利用条件的,RIPS 也没有指出来,总结时详细说明。
1.2 背景介绍
1.2.1 漏洞描述
漏洞存在于 5.1.1 之前的 WordPress 版本中,可以使用默认设置进行利用。
根据其 WordPress 官方下载页面,超过 33%的互联网网站正在使用 WordPress。文章评论是博客的核心功能并且默认情况下已启用,该漏洞会影响数百万个网站。
1.2.2 受影响版本
WordPress
1.3 测试环境
Kali 4.19.0 WordPress 5.1.1
0×02 漏洞实现过程
环境最新是 5.1.1 昨天才官方刚 commit 的修复过程,算是比较新。既然是是 CSRF,表单提交点在于每篇文章的评论处。wp-comments-post.php:25, wp_handle_comment_submission(wp_unslash( $_POST )),进入 comment_handler 函数 做了一些简单的赋值过程:

来看看上面对于用户身份判断的过程。评论需要用户为登录态。关键处:

其中判断用户能否不需要过滤 html,到下面的判断提交 comment 过程中的 wpnonce 验证,若是没有通过身份验证会重新定义kses 处理过程的中的 filter,具体看一下 kses_init_filters

这里为什么会重新删减 filter,在前面初始化的过程中在init标签的注册了一个 kses_init()

仅仅判断通过用户身份 Session 身份判断了,需不要添加过滤 html 的 filter。管理员用户在操作的时候,即默认是没有插入对 pre_comment_content 的过滤 html 的钩子,但是在判断添加评论的时候又因为在想要的 wpnonce 验证不通过的时候,又添加上了相应的 filter,官方还是考虑到了相应的安全问题,但是为什么又要加一层身份判断,添加不同的处理函数呢,直接插入 wp_filter_kses 不好吗?
正是因为 wp_filter_kses 和 wp_filter_post_kses 不同上造成了后面的 js 执行 他们的不同在于过滤的严格度上,其实都一样是白名单过滤。但是跟 pre_comment_content 的钩子函数组合起来,就发送了属性逃逸。
看一下这个两个函数的定义。

传入的第二参数不同,决定了后面允许使用的标签和属性的白名单不同。影响第二个钩子函数。即使这里 addslashes 转义了字符内容,紧接着下一个钩子涉及到对属性的处理,会恢复被转义字符内容。

pre_comment_content 标签的钩子有默认的 4 个钩子 (我习惯叫钩子函数),分别是 convert_invalid_entities,wp_targeted_link_rel,wp_rel_nofollow,balance 根据优先级排序。第一个把€ 及以后的实体转成相应的合法的 unicode 实体,第二个处理 a 标签 中target属性的,第三个是重点了两个重要钩子中的第二个,给 a 标签添加 rel 属性为 nofollow,如果存在 rel 属性则在其属性值中添加 nofollow,并去掉原来的 rel 属性值,其过程会重新拼接 a 标签。

wp_rel_nofollow 钩子在 pre_comment_content 中优先级为 15,当插入 wp_filter_post_kses 钩子时使用的默认值是 10,在 wp 中执行钩子时会有优先级判断,刚好 wp_filter_post_kses 也在前,所以也不涉及到对后面溢出的属性重新处理。
前面说了 wp_filter_post_kses 和 wp_filter_kses 的不同在于使用的白名单不同。前者传入的是 post,后者传入是 current_filter(), 这个值很好理解,这一系列钩子都在 pre_comment_content 标签下。所以理所当然是 pre_comment_content, 选择过程如下:

看当 post 的情况下,默认是没有注册 wp_kses_allowed_html 标签的,即每一步的 apply_filters() 返回输入的第一个值,post 的$allowedpostags 包含的标签及其属性是比较多的,pre_comment_content 只能走到默认 $allowedtags. 其中\$allowedtags 包含情况如下:

[1] [2]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载