wordpress提权与注入分析--CVE-2015-5623
in 漏洞分析 with 0 comment

wordpress提权与注入分析--CVE-2015-5623

in 漏洞分析 with 0 comment

这是Wordpress4.2.3提权与SQL注入漏洞,网上已经有很多分析了
最早是p分析的版本,之后绿盟的分析也很好
早就想拜读p的这篇分析,但是水平不够,看不太懂
今天把这个漏洞完整的看了一遍,赞叹作者的脑洞的同时
也深深感觉到挖洞不仅仅是代码水平与对常见漏洞的掌握程度
更加考验逻辑思维能力,说明白点就是猥琐的思路。
p的分析已经写的很详细了,在我第一次看的时候确实没太看懂
p是从验证函数开始分析的,可能需要我们提前了解一下整个代码
我在这里就从一开始的地方post.php开始分析

0x01.越权漏洞

wordpress中用户权限分为订阅者、投稿者、作者、编辑和管理员。
其中订阅中只能订阅文章和查看文章,没有编辑的权限的
wordpress开启注册后默认注册的用户就是订阅者。国内的freebuf就是这样。
我们先看到编辑文章的链接是这样的:wordpress/wp-admin/post.php?post=42&action=edit
当然这是文章的作者才能进行的操作,订阅者是不行的。
我们来看一下这部分代码,先看到检查文章是否存在的代码
QQ20170520-194908@2x.png
这里是如果GET中有post参数就从GET中获取,如果GET中没有就从POST中获取
也就是可以说post_id是来自GET的。
我们再看到post.php页面中的post_edit()函数
这个函数就是处理上面action=edit的函数
QQ20170520-194922@2x.png
首先这个函数接收完数据之后就验证用户有没有权限访问这个页面,当然,订阅者是没法访问的
文章的作者是可以访问的,这个验证的函数就是current_user_can().
我们注意这里的post_ID,很明显这个post_ID是POST过来,
我们上面检查文章是否存在的时候是GET过来的,
这里GET,POST没有一致,混用了,我们跟进这个函数看看
QQ20170520-194939@2x.png
这个函数获取参数之后就调用了has_cap,跟进,先来看这个函数
QQ20170520-194948@2x.png
前面就调用了map_meta_cap(),获取的$caps
这个$caps在后面的验证中至关重要
我们先来看后面怎么验证$caps的
QQ20170520-195015@2x.png
如何才能return ture呢
要么你is_super_admin验证通过,是超级管理员
要么$capabilities[$cap]非空,但是如果我们的$caps本来就是一个空数组呢
那么$cap就根本没有值了,那这个foreach就没有意义了,直接就到最后return ture了
我们再来看看$caps是如何获取的
map_meta_cap()中,这个函数很长,出问题的地方在这里
QQ20170520-195033@2x.png
当$post不存在时,直接就break出这个switch了
那我们传一个不存在的post_id,这个$post不就不存在了吗
直接break之后就返回了一个空的$caps
那么我们就能成功的绕过权限验证了。
这里就是一个不存在的文章的编辑权限!!
有同学说wordpress不会验证文章是否存在吗?
当然会,在一开始就说了,验证文章是否存在取post_id是通过GET方式
但是验证权限的时候是通过POST方式,也就是说我们在GET里传入一个正确的post_id
然后再POST里传入一个不存在的post_id就可以绕过这个检查了
不过能edit一个不存在的文章又有啥用呢。
我们能够绕过current_user_can这个函数之后,就继续执行post.php中edit_post()剩下的内容
我们看到这个函数后面真正执行update语句的地方
QQ20170520-195043@2x.png
对文章有编辑权限就是能够update语句,如果我update一个不存在的文章
sql语句肯定会爆错的吧,但是在这个update语句前面还有故事
QQ20170520-195058@2x.png
在update前面还接收了POST中的tax_input
我们可以看到tax_input中的值被’,’分开,
然后把分开的每一部分放到get_terms中执行,
get_terms这个函数很长,其中有select操作,
这个地方作者的脑洞开始开了,假如我传入的值是1,2,3,4,......,10000这样,
那么它是不是要执行10000次select查询,这里就有一个延迟了,
假如这10000次select查询需要20秒,在这20秒中,如果我插入了一篇文章呢!!!
这时还没执行到update的地方!!
这样打比方吧,假如总共有100篇文章,我们经过上面越权操作的漏洞得到了101号文章的操作权限,
post_id=101传进current_user_can()的时候还没有101号文章,
这样那个update语句就会出错,
但是如果在10000次select查询造成的20秒延时的过程中刚好插入了一篇文章,
那么文章总数就到了101,那我正好就得到了这个文章的操作权限,
但是我只是个订阅者,却获得了文章的操作权限!!!!
还有一个问题,我们怎么去插入文章呢,难道要等别人凑巧在这个时候插入了一篇文章?
当然不可能,我们要自己来插入一篇文章

0x02.csrf_token泄露导致插入文章

Wordpress对csrf的防御是利用token,
在wordpress里叫做_wpnonce,而且对_wpnonce的设置很严格,
不同的操作有不同的_wpnonce,比如添加文章和添加评论的_wpnonce就不同,
我们看到在action=post-quickdraft-save的时候这是一个存储草稿的操作。
QQ20170520-195122@2x.png
我们并没有正确的_wpnonce,所以我们会出错,
进入到wp-dashboard_quick_press()中,我们跟进看看
QQ20170520-195140@2x.png
我们看到这个函数在后面居然把_wpnonce输出到了表单中,
这是add-post功能的_wpnonce,我们看看这中_wpnonce能做什么
QQ20170520-195148@2x.png
当$post_type为post的时候_wpnonce就是add-post,
很明显,这个_wpnonce是action=post-quickdraft-save中泄露出来的,
肯定能用在action=post-quickdraft-save中,这个就是插入一个草稿的功能
我们就可以通过插入这个草稿,然后通过上面的越权漏洞获取这个草稿的编辑权限,
但是还有一个问题,为了获取_wpnonce,已经执行过post-quickdraft-save了。
执行post-quickdraft-save会在数据库插入一篇status为auto-draft的文章,
但每个用户最多只能插入一篇文章。也就是说我们获取到了_wpnonce却不能插入文章了。
在check-point的原文中,它提到的方法是,
等待一个星期,wordpress会自动将这篇文章删除,而_wpnonce会多保留一天,
这样在这天我们再次执行post-quickdraft-save又可以插入一篇文章了。
从而获取编辑权限,
但是p的方法更好,再注册一个订阅者身份的账户,
用第一个账户获取_wpnonce,第二个用户发帖
这样就组成了一个完整的越权操作漏洞
GP混用+信息泄露(_wpnonce)+程序执行时间可控,三个小漏洞组合起来构成这个越权漏洞,环环相扣,实在是精彩!!!

0x03.untrash文章时造成sql注入漏洞

先说这个注入的原理,这里盗用p总的几张图,在/wp-includes/post.php中
QQ20170520-195206@2x.png
这是untrash的一个操作,
把垃圾箱的数据取出来update到还原的文章中,
这里很明显是一个二次注入,
$statuses从数据库中取出来并没有进行过滤,直接放到updata语句中了,
$statuses是从_wp_trash_meta_comments_status这个字段中取出来的,
那么我们看看这个字段数据是从哪里存进去的,
看到这里wp_trash_post_comments()函数,
这个函数是删除文章的时候删除评论的函数
QQ20170520-195219@2x.png
我们看到这个$statuses还是通过$comments生成的,
而$comments又是从数据库中取出来的,
那么这个评论应该是在添加评论或者修改评论的时候加进去的
QQ20170520-195235@2x.png
在修改评论的函数中,我么看到了comment_approved这个字段,
应该就是从这里传进去的,所以这里就是一个二次注入的漏洞。

0x04.越权与注入综合利用

这里,能够对文章进行评论然后untrash操作的应该是文章的作者或者管理员,
所以这个注入漏洞的权限最起码是文章的作者,
但是,我们通过前面的越权操作,导致我们订阅者也能操作文章,
从而引发这个注入漏洞。这个漏洞的利用思路就是:

看似没有什么问题,不知道各位还记不记得我们上文说的_wpnonce。
对!就是这个坑!作者通篇没有提到这个漏洞要怎么获取_wpnonce!
我们只能获取到一个_wpnonce,是用来插入文章的,
实际上后面的每一步(增加、编辑评论、trash文章、untrash文章)都需要不同的_wpnonce,
那么这些_wpnonce我们怎么获得?
我猜测作者没有提及这个问题,要么是他自己也没找到,这篇文章其实只是个标题党,
要么是他藏了一手。从作者前后漏洞关联的那么紧密来看,
我比较倾向于后一种原因。在绿盟的文章中提到了trick
QQ20170520-195250@2x.png
p牛的文章
绿盟的文章

Comments are closed.