CalderaForms 1.5.9.1 XSS(WordPress插件) - 教程
CalderaForm 是一个 WordPress 插件,允许通过拖放轻松创建表单。 在最近的一次活动中,我测试了一些门户网站,其中一个恰好使用了这个插件创建的联系表单。 该实例的自定义配置让我发现了一个漏洞:由于其简单、教科书式的性质,我认为这是一个很好的机会,可以向初学者说明一些机制。
仅用于教育目的 - 不要使用这些信息在未经明确授权的情况下测试目标,也不要用于非法目的 - 不要在消化时跳入冷水 - 天热时要像洋葱一样分层穿衣
完整利用:
https://www.exploit-db.com/exploits/44489/
CVE:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7747
在分析的目标配置中,表单被设置为向用户显示一条感谢消息,并使用刚刚输入的名字称呼用户。
为了复现测试环境,请在本地安装一个 WordPress 实例,并安装 CalderaForms 1.5.9.1 版本(可从此处或此处下载)。
安装完成后,从 WordPress 管理控制台 > 左侧栏 > "Caldera Forms" > 顶部按钮 > "New Form" > 选择 Contact Form,重命名并点击 "Create Form"

创建完成后,可以修改其配置:顶部按钮 > "Form Settings" > 修改 Success Message,使其包含用户输入的某个数据。点击框,会出现一个提示下拉菜单。
添加 %first_name%

顶部按钮 > "Save Form"
将表单插入页面:左侧栏 > "Pages" > "Sample Page" > "Edit" > "Caldera Form" > 选择刚刚创建的表单 > "Insert Form" > 右侧栏 > "Update"

完成。
让我们逐步分解构建此类攻击所需的步骤,遵循分治原则。
在测试阶段,与组件交互时,必须始终注意其对给定刺激的反应;特别地,我们关注我们输入数据的“路径”以及它们所经历的任何转换。
对于我们案例的一个具体示例如下:
访问包含表单的页面:http://127.0.0.1/wordpress/sample-page/
使用以下数据填写表单
"First Name": myName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
数据根据插件逻辑进行处理
收到的感谢消息包含我们在 First Name 字段中输入的字符串
"Thank you myName, form has been successfully submitted."

我们在 "First Name" 字段中输入的字符串被返回到感谢消息中。
特别地,该字符串包含在一个 HTML div 标签中。
我们的输入最终出现在页面的 HTML 中。
思考:"这很好。我们有了一个接触点。"
让我们更进一步。在所谓的“处理”阶段(第2步),我们的输入是如何被对待的?特别地,我们想知道的是:我们在字符(及其组合)的使用上是否存在限制?
显然,我们的目标是能够注入“东西”。当尝试进行注入时,必须记住我们的输入最终会到达哪里,并使用合适的“语言”。
我们的输入是由 SQL 解释器处理吗?我们需要说它的语言。
我们的输入是由 PHP 脚本处理吗?我们需要说它的语言。
我们的输入最终出现在 HTML 页面上吗?……
因此,我们关心的是是否可以使用 HTML 的典型字符和构造,特别是考虑到这种语言能够包含/解释 JavaScript 代码,我们需要找到一种策略,将我们的代码插入到“着陆区”,即之前注意到的 div 标签。
为此,我们在 "First Name" 字段中插入一个简单的 HTML 标签,看看它是否被“sanitized”(净化),即是否被修改以使其无害/无法被解释,或者是否原封不动地返回。为此,我们使用 <br> 标签,它用于在文本中插入换行符。
按照之前的编号:
使用以下数据填写表单
"First Name": m<br>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
感谢消息包含我们的 HTML 标签,它没有被修改,并且被正确解释,在消息中间插入了一个换行符
"Thank you m
yName, form has been successfully submitted."

思考:"这很好。我们可以使用小于号和大写号,可以插入 HTML 标签,它们没有被净化并且被解释。"
下一步。将格式化标签替换为更有用的东西,比如 <script> 标签,它允许我们在页面中插入和执行 JavaScript 代码。
使用以下数据填写表单
"First Name": m<script>alert(1);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
感谢消息包含我们的 HTML 标签,它没有被修改,并且被正确解释,显示了一个 alert 框

思考1:"这很好。我们可以在用户浏览器上下文中执行任意 JavaScript 代码。"
思考2:"这不好。执行 JavaScript 的用户是我们自己。"
情况是这样的:我们可以在一个不受我们控制的网站上,在用户浏览器上下文中执行 JavaScript,但这个用户,目前,就是输入表单值的人。这基本上是无用的。
思路是:有没有办法调用包含我们要执行代码的感谢消息?
回到我们第一次的提交,即“探查”提交(或重新执行初始步骤)。
通过分析网络流量或页面源代码,我们发现该表单向以下地址发起了一个 POST 请求
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4
(最后部分可能不同,请在后续所有示例中相应修改)
即指向地址
http://<target>/cf-api/<form-id>
并且该请求的响应是一个 JSON,其中包含一些数据,包括感谢消息,结构如下:
{
"data":
{"cf_id":"48"},
"html":"<div class=\" alert alert-success\">Thank you myName, form has been successfully submitted.<\/div>",
"type":"complete",
"form_id":"CF5ad9b3176c0f4",
"form_name":"MyContactForm",
"status":"complete"
}
我们保留这条信息,稍后会用到;特别要注意 "form_id" 和 "cf_id" 字段。
发起 POST 请求的地址上有什么?没有太多猜测,我们看看如果执行 GET 请求会发生什么,即访问 http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4 这个页面,我们会发现,无非就是相关表单的 HTML。
并检查提交产生的网络流量

这次我们收到一个 HTTP 302(重定向) 到 location /wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=49,它返回的正是包含感谢消息 div 标签的 HTML。
注意这个地址的格式:
http://<target>/cf-api/<form-id>/?cf_su=1&cf_id=<cf-id>
其中 <form-id> 和 <cf-id> 的值正是之前分析的 JSON 中的 "form_id" 和 "cf_id"。
我们回答了一开始的问题吗?是的。我们找到了一种方法来调用感谢消息的内容。
思考:"这很好。我们可以根据需要调用包含我们数据的消息。"
总结一下,将我们到目前为止收集的所有信息结合起来,包装成一个攻击。
1) 将我们的恶意代码保存到目标上
2) 收集检索该代码所需的数据
3) 构建适合“触发”我们攻击的 URL
使用以下数据填写表单(从两个页面中的任何一个都可以)
"First Name": m<script>document.body.innerHTML=String.fromCodePoint(128046);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
通过分析生成的流量(无论是 sample-page 页面的 JSON 响应,还是仅包含表单的页面的重定向),获取 form_id 和 cf_id 标识符
{
"data":
{"cf_id":"69"},
"html":"...",
"type":"...",
"form_id":"CF5ad9b3176c0f4",
"form_name":"...",
"status":"..."
}
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=69

几点思考:
如果读者感兴趣,可以尝试以下练习:
'(单引号)、"(双引号)或 `(反引号)的情况下重复上述练习(意大利键盘布局上没有反引号)