WPDiscuz插件 – RCE漏洞分析

1 前言

Wordfence的威胁情报团队在一款名叫wpDiscuz的Wordpress评论插件中发现了一个高危漏洞,而这款插件目前已有超过80000个网站在使用了。这个漏洞将允许未经认证的攻击者在目标站点中上传任意文件,其中也包括PHP文件,该漏洞甚至还允许攻击者在目标站点的服务器中实现远程代码执行。

以下为该漏洞的漏洞描述,由于存在前台无限制文件上传漏洞,攻击者在无需任何权限的情况下可以直接接管服务器。

2 漏洞分析

这里测试环境为Wordpress v5.5 ,使用漏洞插件的版本为 wpdiscuz-7.0.3,这里直接将插件包部署在plugin目录后刷新即可。

之后访问初试的Hello World文章页,就会发现这里的评论界面已经变成了由WPDiscuz提供的界面了。

根据漏洞描述,在用户进行评论时,允许用户上传相应的图片文件,但是WPDiscuz对图片的后缀名没有做有效的校验,导致用户可以上传任意文件,其中包括可以执行代码的PHP后缀文件。

漏洞的路由定义点在wpdiscuz/utils/class.WpdiscuzHelperUpload.php的construct构造函数第40行代码

这里将wmuUploadFiles路由绑定到该类的uploadFiles函数,继续跟进该函数

这里可以看到在uploadFiles函数中开始对文件进行遍历操作,313行代码通过getMimeType函数获取了文件的MIME类型,跟进这个函数

这里可以看到获取文件的MIME类型是通过三个if语句来进行获取,与一般直接获取content-type导致rce的漏洞还不太一样,通俗点讲这里获取MIME类型其实是有先后顺序的,第一次判断是否mime_content_type函数,如果存在使用该函数获取MIME类型,如果不存在则使用finfo_file函数获取,如果前两个都不存在,那么使用wordpress自带的文件检验函数,对文件后缀进行白名单检查。

这里存在问题的是前两个判断语句:mime_content_type和finfo_file函数,如果有同学去搜下php manual就知道mime_content_type函数在php各版本中其实都没有废弃,而是一直保留着,只是不太推荐使用而已,因此这里在一般情况下其实都会使用mime_content_type函数来获取MIME类型,但是该函数在获取MIME类型是通过文件的十六进制起始字节来判断,因此当起始字节设置成“89 50 4E 47 0D 0A 1A 0A”,就表示该文件为png文件,所以这里的MIME类型就可以通过这种方式进行绕过。

实际上这里的finfo_file也是通过起始字节来获取MIME类型的,因此这里只要不进入最后的白名单检测,都是存在问题的。

那么回到原先的uploadFiles代码,最终进入到320行的判断函数isAllowedFileType

这里进行白名单匹配,如果在MIME的白名单里,则返回true,前面也说了这里的mimeType根据文件的起始字节来的,所以这里的检测也是能够绕过去的

最后判断MIME中是否出现“image/”,如果没有出现,则强制增加后缀“.jpg”,但是由于是伪造的MIME,因此这里后缀名保持不变,仍为我们上传的后缀名。

所以我们构造一个图片马,起始字节为png图片的起始字节,在起始字节后加上我们的shell代码

3 补丁分析

isAllowedFileType函数中加入了extension后缀的检测,当MIME与后缀不等时返回false,相当于使用MIME的白名单来对后缀进行约束,从而进行了漏洞的修复。