0x00 漏洞背景

WordPress在5.2.3以及之前版本,存在着一处未授权页面查看漏洞,攻击者可以在未授权的情况下,查看所有private页面或是已经删除至回收站的页面。

受影响版本:WordPress <= 5.2.3(但我在5.2.3版本上并没有复现成功)

0x01 环境搭建

  • WordPress 5.2.2
  • Ubuntu18.04
  • php7.2
  • mysql5.7
  • apache2

0x02 漏洞复现

以admin的身份登录后台,新建一个private属性的页面(page),而不是文章(post)。

img

img

当你以普通用户的身份去访问http://192.168.92.132/wordpress522/private/的时候是看不到这个private页面的。

使用下面的payload:

1
http://192.168.92.132/wordpress522/?static=1&order=asc

我们可以看到已经被放回回收站的page和私密的page。

img

0x03 漏洞细节

wordpress在wp-includes/class-wp.php中定义了一个WP类,WP类中有一个公共变量$this->public_query_vars,这个变量定义了用户支持的查询参数,其中有一项是static

img

WP类中还有一个main()函数,这个函数会这是wordpress需要的环境变量

img

parse_request方法的作用是,解析请求(GET/POST)以找到正确的WordPress查询,根据请求设置查询变量。

img

这个方法中的foreach循环会检查$this->public_query_vars中的参数是不是在$_GET请求中,如果是的话就将对应的$_GET[]请求参数赋值给$this->query_vars.

img

img

接下来看下wp-includes\class-wp-query.php中的parse_query()方法

img

$qv['static']的值不为空的时候,$this->is_page会被赋值为true,这是后面进入错误执行逻辑的关键点之一

img

继续来到3043行,因为$this->is_page为true,所以只要$this->posts不是空就可以进入下列if语句。

当前的sql查询语句是这样的,它会将数据库中的post和page全都取出来,然后按照发布的时间从早到晚进行排序。

1
SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_type = 'page'  ORDER BY wp_posts.post_date ASC

img

当前已经取出了四篇文章,第一篇是当时建站是就已经存在的示例文章:

img

第3篇是已经被放回回收站的:

img

最后一篇是private状态的页面:

img

如果当前取出的第一篇文章的状态不是public就会进入if分支,会根据用户是否登录或者文章的状态来决定后续处理。这也是为什么payload中加上了order=asc的原因,这样取出的第一篇文章就是原来默认建站就存在的示例文章(前提是你没有进行删除),当然如果你的第一篇文章是private状态的,那么这个payload就没办法起作用了。这是攻击成功的关键点之二

img

0x04 官方修复

官方给出的修复是直接去掉static字段。

img

img

0x05 preferences