CORS - Misconfigurations & Bypass
Last updated
Last updated
学习和实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习和实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
跨源资源共享 (CORS) 标准 使服务器能够定义谁可以访问其资产 和 哪些 HTTP 请求方法被允许 来自外部来源。
同源 策略要求 请求 资源的服务器和托管 资源 的服务器共享相同的协议(例如,http://
)、域名(例如,internal-web.com
)和 端口(例如,80)。在此策略下,仅允许来自同一域和端口的网页访问资源。
在 http://normal-website.com/example/example.html
的上下文中,同源策略的应用如下所示:
访问的 URL | 允许访问? |
---|---|
| 是:相同的协议、域名和端口 |
| 是:相同的协议、域名和端口 |
| 否:不同的协议和端口 |
| 否:不同的域名 |
| 否:不同的域名 |
| 否:不同的端口* |
*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 客户端证书)。
在特定条件下发起跨域请求时,例如使用 非标准 HTTP 方法(除了 HEAD、GET、POST 以外的任何方法)、引入新的 头部,或使用特殊的 Content-Type 头部值,可能需要进行预检请求。这个初步请求利用 OPTIONS
方法,旨在通知服务器即将到来的跨源请求的意图,包括它打算使用的 HTTP 方法和头部。
跨源资源共享 (CORS) 协议要求进行此预检检查,以确定请求的跨源操作的可行性,通过验证允许的方法、头部和来源的可信度。有关哪些条件可以绕过预检请求的详细理解,请参考 Mozilla Developer Network (MDN) 提供的综合指南。
需要注意的是,缺少预检请求并不意味着响应不需要携带授权头部。没有这些头部,浏览器将无法处理来自跨源请求的响应。
考虑以下旨在使用 PUT
方法以及名为 Special-Request-Header
的自定义头部的预检请求示例:
作为响应,服务器可能会返回指示接受的方法、允许的来源和其他CORS策略细节的头,如下所示:
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
:
请注意,linux 0.0.0.0 IP 可以用来 绕过 这些要求以访问 localhost,因为该 IP 地址不被视为“本地”。
如果使用 本地端点的公共 IP 地址(例如路由器的公共 IP),也可以 绕过本地网络要求。因为在多种情况下,即使正在访问 公共 IP,如果它是 来自本地网络,也会被允许访问。
请注意,即使以下配置看起来非常宽松:
这在浏览器中是不允许的,因此凭据不会随请求发送。
已观察到,将 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
头。这种方法可能引入漏洞,特别是当攻击者使用一个看似合法的域名时,从而欺骗验证逻辑。
null
源null
源在重定向或本地 HTML 文件等情况中指定,具有独特的地位。一些应用程序将此源列入白名单以便于本地开发,无意中允许任何网站通过沙箱 iframe 模仿 null
源,从而绕过 CORS 限制。
当遇到域名白名单时,测试绕过机会至关重要,例如将攻击者的域名附加到白名单域名或利用子域名接管漏洞。此外,用于域名验证的正则表达式可能会忽视域名命名规则中的细微差别,从而提供进一步的绕过机会。
正则表达式模式通常集中于字母数字、点 (.) 和连字符 (-) 字符,忽略其他可能性。例如,构造一个包含浏览器和正则表达式模式以不同方式解释的字符的域名,可以绕过安全检查。Safari、Chrome 和 Firefox 对子域名中下划线字符的处理说明了如何利用这些差异来规避域名验证逻辑。
有关此绕过检查的更多信息和设置: https://www.corben.io/advanced-cors-techniques/ 和 https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397
开发人员通常实施防御机制,以通过白名单允许请求信息的域名来保护免受 CORS 利用。尽管采取了这些预防措施,系统的安全性并非万无一失。在白名单域名中,即使存在一个脆弱的子域名,也可能通过其他漏洞(如 XSS(跨站脚本))打开 CORS 利用的大门。
例如,考虑一个场景,其中域名 requester.com
被列入白名单以访问另一个域名 provider.com
的资源。服务器端配置可能如下所示:
在这个设置中,requester.com
的所有子域都被允许访问。然而,如果一个子域,比如 sub.requester.com
,存在 XSS 漏洞,攻击者可以利用这个弱点。例如,拥有 sub.requester.com
访问权限的攻击者可以利用 XSS 漏洞绕过 CORS 策略,恶意访问 provider.com
上的资源。
PortSwigger 的 URL 验证绕过备忘单 发现某些浏览器支持域名中的奇怪字符。
Chrome 和 Firefox 支持下划线 _
,可以绕过用于验证 Origin
头的正则表达式:
Safari 在接受域名中的特殊字符方面甚至更加宽松:
通过 HTTP 头注入利用服务器端缓存中毒,可能会引发存储的跨站脚本(XSS)漏洞。当应用程序未能清理 Origin
头中的非法字符时,这种情况就会发生,特别是对 Internet Explorer 和 Edge 用户而言。这些浏览器将 (0x0d) 视为合法的 HTTP 头终止符,从而导致 HTTP 头注入漏洞。
考虑以下请求,其中 Origin
头被操纵:
Internet Explorer 和 Edge 将响应解释为:
虽然通过使网络浏览器发送格式错误的头部直接利用此漏洞并不可行,但可以使用像 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 的简要分解:
XSSI,也称为跨站脚本包含,是一种利用同源策略(SOP)在使用脚本标签包含资源时不适用的漏洞。这是因为脚本需要能够从不同域中包含。此漏洞允许攻击者访问和读取任何通过脚本标签包含的内容。
当涉及动态JavaScript或JSONP(带填充的JSON)时,这个漏洞尤其重要,特别是当使用像cookies这样的环境权限信息进行身份验证时。当从不同主机请求资源时,cookies会被包含,使得攻击者可以访问。
为了更好地理解和缓解此漏洞,您可以使用可在https://github.com/kapytein/jsonp找到的BurpSuite插件。此插件可以帮助识别和解决您Web应用程序中的潜在XSSI漏洞。
尝试在请求中添加一个**callback
** 参数。也许该页面已准备好将数据作为JSONP发送。在这种情况下,页面将以Content-Type: application/javascript
返回数据,从而绕过CORS策略。
绕过Access-Control-Allow-Origin
限制的一种方法是请求Web应用程序代表您发出请求并发送回响应。然而,在这种情况下,最终受害者的凭据不会被发送,因为请求是发往不同的域。
CORS-escape:此工具提供一个代理,转发您的请求及其头,同时伪造Origin头以匹配请求的域。这有效地绕过了CORS政策。以下是使用XMLHttpRequest的示例:
simple-cors-escape:此工具提供了一种替代的请求代理方法。服务器不是直接传递您的请求,而是使用指定的参数发出自己的请求。
您可以通过创建一个iframe并从中打开一个新窗口来绕过CORS检查,例如e.origin === window.origin
。更多信息请参见以下页面:
通过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缓存洪水进行DNS重绑定是另一种用于绕过浏览器缓存机制并强制第二个DNS请求的技术。其工作原理如下:
最初,当受害者发出DNS请求时,响应为攻击者的IP地址。
为了绕过缓存防御,攻击者利用服务工作者。服务工作者洪水式地填充DNS缓存,有效地删除了缓存的攻击者服务器名称。
当受害者的浏览器发出第二个DNS请求时,现在响应为IP地址127.0.0.1,通常指向本地主机。
通过使用服务工作者洪水填充DNS缓存,攻击者可以操纵DNS解析过程并强制受害者的浏览器发出第二个请求,这次解析为攻击者所需的IP地址。
绕过缓存防御的另一种方法是利用DNS提供商中同一子域的多个IP地址。其工作原理如下:
攻击者在DNS提供商中为同一子域设置两个A记录(或一个具有两个IP的单个A记录)。
当浏览器检查这些记录时,它接收到两个IP地址。
如果浏览器决定首先使用攻击者的IP地址,攻击者可以提供一个有效负载,执行对同一域的HTTP请求。
然而,一旦攻击者获得受害者的IP地址,他们就停止响应受害者的浏览器。
受害者的浏览器在意识到该域无响应后,转而使用第二个给定的IP地址。
通过访问第二个IP地址,浏览器绕过同源策略(SOP),允许攻击者滥用这一点并收集和外泄信息。
此技术利用了浏览器在为域提供多个IP地址时的行为。通过战略性地控制响应并操纵浏览器的IP地址选择,攻击者可以利用SOP并访问受害者的信息。
请注意,为了访问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/
如果不允许内部IP,他们可能忘记禁止0.0.0.0(在Linux和Mac上有效)
如果不允许内部IP,则响应CNAME到localhost(在Linux和Mac上有效)
如果不允许内部IP作为DNS响应,您可以响应CNAME到内部服务,例如www.corporate.internal。
您可以在演讲Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference中找到有关先前绕过技术的更多信息以及如何使用以下工具。
Singularity of Origin
是一个执行DNS重绑定攻击的工具。它包括将攻击服务器DNS名称的IP地址重新绑定到目标机器的IP地址并提供攻击有效负载以利用目标机器上脆弱软件所需的组件。
在内部服务中使用TLS
请求身份验证以访问数据
验证Host头
https://wicg.github.io/private-network-access/:提议在公共服务器想要访问内部服务器时始终发送预检请求
Fuzz可能的CORS政策配置错误
学习和实践AWS黑客攻击:HackTricks Training AWS Red Team Expert (ARTE) 学习和实践GCP黑客攻击:HackTricks Training GCP Red Team Expert (GRTE)