# CORS - 配置错误和绕过
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
* 你在一家**网络安全公司**工作吗?你想在HackTricks中看到你的**公司广告**吗?或者你想获得**PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass),或**关注**我在**Twitter**上的[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享你的黑客技巧。**
## 什么是CORS?
CORS(跨源资源共享)标准是必需的,因为它**允许服务器指定谁可以访问其资源**以及允许来自外部资源的哪些**HTTP请求方法**。
**同源策略**要求**请求资源的服务器**和**资源所在的服务器**使用相同的协议([http://),域名](http://\),域名)和相同的**端口**(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将允许此访问,因为IE在应用同源策略时不考虑端口号。_
### `Access-Control-Allow-Origin` 头部
`Access-Control-Allow-Origin` 的规范允许**多个来源**,或值为**`null`**,或通配符**`*`**。然而,**没有浏览器支持多个来源**,并且对使用通配符**`*`**有**限制**。(_通配符只能单独使用,这将失败 `Access-Control-Allow-Origin: https://*.normal-website.com`,并且不能与_ _Access-Control-Allow-Credentials: true_ _一起使用_)
当网站请求跨域资源时,浏览器会添加一个`Origin`头部,服务器在返回时会包含这个`Access-Control-Allow-Origin`头部。
### `Access-Control-Allow-Credentials` 头部
跨域资源请求的**默认**行为是**不传递凭据**,如cookies和Authorization头部。然而,跨域服务器可以通过将CORS的`Access-Control-Allow-Credentials`头部设置为**`true`**来允许读取**响应**时传递给它的**凭据**。
如果值设置为`true`,则浏览器将发送凭据(cookies、授权头部或TLS客户端证书)。
```javascript
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);
```
```javascript
fetch(url, {
credentials: 'include'
})
```
```javascript
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('Arun');
```
### 预检请求
在某些情况下,当跨域请求:
- 包含**非标准的HTTP方法(HEAD,GET,POST)**
- 包含新的**头部**
- 包含特殊的**Content-Type头部值**
{% hint style="info" %}
**请查看**[**此链接**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests)**中请求的条件,以避免发送预检请求**
{% endhint %}
跨域请求会在**`OPTIONS`方法**的**请求**之前进行,CORS协议要求在允许跨域请求之前对**方法和头部进行初始检查**。这被称为**预检查**。服务器会返回一个允许的方法列表,以及受信任的来源,浏览器会检查请求网站的方法是否被允许。
{% hint style="danger" %}
请注意,即使不发送预检请求,因为"常规请求"的条件得到了遵守,**响应仍然需要具有授权头部**,否则**浏览器将无法读取请求的响应**。
{% endhint %}
例如,下面是一个预检请求,它试图与一个名为`Special-Request-Header`的**自定义**请求**头部**一起使用**`PUT`方法**:
```
OPTIONS /data HTTP/1.1
Host:
...
Origin: https://normal-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Special-Request-Header
```
服务器可能返回以下响应:
```
HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Special-Request-Header
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` 跨域请求想要发送的请求头
* `Access-Control-Request-Method` 跨域请求想要使用的请求方法
* `Origin` 跨域请求的来源(由浏览器自动设置)
![](../.gitbook/assets/preflight.svg)
请注意,通常情况下(取决于内容类型和设置的请求头),在**GET/POST请求中不会发送预检请求**(请求会**直接发送**),但是如果您想要访问响应的**请求头/主体**,它必须包含一个允许的_Access-Control-Allow-Origin_头。\
**因此,CORS不能防止CSRF(但它可能有所帮助)。**
### **本地网络请求的预检请求**
当请求发送到本地网络IP地址时,会发送2个额外的CORS头:
* `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://public.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地址可用于**绕过**访问本地主机的要求,因为该IP地址不被视为“本地”。
如果您使用本地端点的**公共IP地址**(如路由器的公共IP地址),还可以**绕过本地网络要求**。因为在许多情况下,即使访问的是**公共IP**,如果是**来自本地网络**,也会被授予访问权限。
{% endhint %}
## 可利用的配置错误
请注意,大多数**真实攻击需要将`Access-Control-Allow-Credentials`**设置为**`true`**,因为这将允许浏览器发送凭据并读取响应。没有凭据,许多攻击变得无关紧要;这意味着您无法利用用户的Cookie,因此让他们的浏览器发出请求而不是自己发出请求是没有任何收益的。
一个值得注意的例外是当**受害者的网络位置充当一种身份验证方式**。您可以使用受害者的浏览器作为代理来绕过基于IP的身份验证并访问内部网络应用程序。在影响方面,这与DNS重绑定类似,但要利用起来要简单得多。
### 在`Access-Control-Allow-Origin`中反射`Origin`
在现实世界中,**这两个标头的值不允许同时出现**。\
同样,许多开发人员希望**在CORS中允许多个URL**,但不允许使用子域通配符或URL列表。因此,一些开发人员会**动态生成**\*\*`Access-Control-Allow-Origin`\*\*标头,并且在多个情况下,他们只是**复制Origin标头的值**。
在这种情况下,**同样的漏洞可能会被利用**。
在其他情况下,开发人员可以检查**域**(_victimdomain.com_)**是否出现**在**Origin标头**中,然后,攻击者可以使用名为**`attackervictimdomain.com`**的域来窃取机密信息。
```html
```
### `null` Origin
`null`是**Origin**头的一个特殊值。规范中提到它会在重定向和本地HTML文件中触发。一些应用程序可能会将`null` origin列入白名单,以支持应用程序的本地开发。\
这很好,因为**一些应用程序允许CORS中的这个值**,并且**任何网站都可以通过使用沙盒iframe轻松获取null origin**:
```html
```
```html
```
### **正则表达式绕过**
如果你发现域名 _victim.com_ 被**白名单**了,你应该检查 _victim.com.**attacker.com**_ 是否也被**白名单**,或者,如果你可以**接管某个子域名**,检查 _**somesubdomain**.victim.com_ 是否被白名单。
### **高级正则表达式绕过**
大多数用于在字符串中识别域名的正则表达式将关注字母数字ASCII字符和`.-`。因此,像 `victimdomain.com{.attacker.com` 这样的字符串在 Origin 头部中将被解释为域名是 `victimdomain.com`,但浏览器(在这种情况下 Safari 支持该字符作为域名)将访问 `attacker.com` 这个域名。
下划线 `_` 字符(在子域名中)不仅在 Safari 中支持,而且在 Chrome 和 Firefox 中也支持!
**因此,使用其中一个子域名,你可以绕过一些“常见”的正则表达式来找到 URL 的主域名。**
**有关此绕过的更多信息和设置,请查看:**[**https://www.corben.io/advanced-cors-techniques/**](https://www.corben.io/advanced-cors-techniques/) **和**[**https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397**](https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397)
![](<../.gitbook/assets/image (153).png>)
### 来自子域名内的 XSS 攻击
开发人员用于防御 CORS 攻击的一种机制是将经常请求访问信息的域名加入白名单。然而,这并不完全安全,因为即使**一个**被**白名单**的域名的子域名容易受到其他攻击(如 XSS)的影响,它也可以启用 CORS 攻击。
让我们来看一个例子,下面的代码显示了允许 _requester.com_ 的子域名访问 _provider.com_ 资源的配置。
```javascript
if ($_SERVER['HTTP_HOST'] == '*.requester.com')
{
//Access data
else{ // unauthorized access}
}
```
假设用户可以访问sub.requester.com但无法访问requester.com,并且假设`sub.requester.com`易受XSS攻击。用户可以通过使用跨站脚本攻击方法来利用`provider.com`。
### **服务器端缓存污染**
如果条件成熟,我们可以利用通过HTTP头注入进行服务器端缓存污染,从而创建一个[存储型XSS](https://portswigger.net/web-security/cross-site-scripting/stored)漏洞。
如果一个应用程序**反射**了**Origin头**而没有对其进行非法字符检查,例如逗号,我们实际上就有了一个**针对IE/Edge用户的HTTP头注入漏洞,因为Internet Explorer和Edge将\r(0x0d)视为有效的HTTP头终止符**:`GET / HTTP/1.1`\
`Origin: z[0x0d]Content-Type: text/html; charset=UTF-7`
Internet Explorer将响应视为:
`HTTP/1.1 200 OK`\
`Access-Control-Allow-Origin: z`\
`Content-Type: text/html; charset=UTF-7`
这并不是直接可利用的,因为攻击者无法让某人的Web浏览器发送这样的格式错误的头部,但是我可以**在Burp Suite中手动构造此请求,并且服务器端缓存可能会保存响应并将其提供给其他人**。我使用的有效载荷将更改页面的字符集为**UTF-7**,这在创建XSS漏洞方面非常有用。
### **客户端缓存污染**
您可能偶尔会遇到一个页面,其中自定义HTTP头中存在[反射型XSS](https://portswigger.net/web-security/cross-site-scripting/reflected)。假设一个网页反射了一个自定义头的内容而没有进行编码:
```http
GET / HTTP/1.1
Host: example.com
X-User-id: <svg/onload=alert\(1\)>
HTTP/1.1 200 OK
Access-Control-Allow-Origin: \*
Access-Control-Allow-Headers: X-User-id
Content-Type: text/html
...
Invalid user: <svg/onload=alert\(1\)>\
```
使用CORS,我们可以在Header中发送任何值。单独来说,**这是无用的**,因为包含我们**注入的JavaScript的响应不会被渲染**。然而,**如果没有指定Vary: Origin**,响应**可能会被存储在浏览器的缓存中,并在浏览器导航到相关URL时直接显示**。我已经创建了一个fiddle来[尝试在您选择的URL上进行此攻击](https://jsfiddle.net/3gk8u8wu/3/)。由于此攻击使用客户端缓存,它实际上非常可靠。
```markup
```
## 绕过
### XSSI(跨站脚本包含)/ JSONP
XSSI指的是一种利用`script`标签包含资源时,由于脚本需要能够跨域包含,因此SOP不适用的漏洞。攻击者可以通过使用`script`标签来读取所有被包含的内容。
当涉及到动态JavaScript或JSONP时,这一点尤其有趣,因为这些情况下使用了所谓的环境授权信息,比如cookies用于身份验证。当从不同的主机请求资源时,这些cookies会被包含进来。BurpSuite插件:[https://github.com/kapytein/jsonp](https://github.com/kapytein/jsonp)
[**在这里阅读更多关于不同类型的XSSI以及如何利用它们的信息。**](xssi-cross-site-script-inclusion.md)
尝试在请求中添加一个**`callback`** **参数**。也许页面已经准备好将数据作为JSONP发送。在这种情况下,页面将以`Content-Type: application/javascript`的形式发送数据,从而绕过CORS策略。
![](<../.gitbook/assets/image (229).png>)
### 简单(无用?)绕过
您可以要求Web应用程序代表您发出请求并返回响应。这将绕过**`Access-Control-Allow-Origin`**,但请注意,**最终受害者的凭据不会被发送**,因为您将会**与不同的域**(代表您发出请求的域)进行联系。
[**CORS-escape**](https://github.com/shalvah/cors-escape)
CORS-escape提供了一个**代理**,它会将我们的**请求**和其**头部**一起**传递**,并且还会**伪造**Origin头部(Origin = **请求的域**)。因此,**CORS策略被绕过**。\
源代码位于[Github上](https://github.com/shalvah/cors-escape),因此您可以**自己托管**。
```javascript
xhr.open("GET", "https://cors-escape.herokuapp.com/https://maximum.blog/@shalvah/posts");
```
[**simple-cors-escape**](https://github.com/shalvah/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](xss-cross-site-scripting/iframes-in-xss-and-csp.md)
{% endcontent-ref %}
### 通过TTL进行DNS Rebinding
![](<../.gitbook/assets/image (108).png>)
基本上,你让受害者访问你的页面,然后你改变你的域名的DNS(即IP),使其指向受害者的网页。当TTL结束时,你让受害者执行一些操作(JS),这样就会发出新的DNS请求,然后你就能够收集信息(因为你始终将用户保留在你的域名中,他不会向受害者服务器发送任何cookie,所以这个选项滥用了受害者IP的特权)。
即使你将TTL设置得非常低(0或1),浏览器也有一个缓存,会阻止你在几秒钟/分钟内滥用这个功能。
因此,这种技术对于绕过显式检查很有用(受害者明确执行DNS请求以检查域名的IP,当调用机器人时,它将执行自己的请求)。
或者当你可以让用户/机器人在同一个页面上停留很长时间(这样你就可以等待缓存过期)。
如果你需要快速滥用这个功能,你可以使用像[https://lock.cmpxchg8b.com/rebinder.html](https://lock.cmpxchg8b.com/rebinder.html)这样的服务。
如果你想运行自己的DNS rebinding服务器,你可以使用像[**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**](http://rebind.it/singularity.html)上查看公开运行的服务器。
### 通过**DNS缓存洪泛**进行DNS Rebinding
正如前一节所述,**浏览器**将域名的IP地址**缓存的时间比TTL指定的时间长**。然而,有一种方法可以绕过这种防御。
你可以有一个服务工作者,它将**洪泛DNS缓存以强制进行第二个DNS请求**。所以流程将是这样的:
1. DNS请求响应为攻击者地址
2. 服务工作者洪泛DNS缓存(删除了缓存的攻击者服务器名称)
3. 第二个DNS请求,这次响应为127.0.0.1
![](<../.gitbook/assets/image (375) (1).png>)
_蓝色是第一个DNS请求,橙色是洪泛。_
### 通过**缓存**进行DNS Rebinding
正如前一节所述,**浏览器**将域名的IP地址**缓存的时间比TTL指定的时间长**。然而,还有另一种绕过这种防御的方法。
你可以在**DNS提供商**中为**同一个子域**创建**2个A记录**(或**1个带有2个IP的A记录**),当浏览器检查它们时,它将得到两者。
现在,如果**浏览器决定首先使用攻击者IP地址**,攻击者将能够提供将**执行HTTP请求**到同一**域**的**有效负载**。然而,现在攻击者知道受害者的IP,**他将停止回答受害者的浏览器**。
当浏览器发现**域名对他不响应**时,它将**使用给定的第二个IP**,这样他将**绕过SOP访问不同的位置**。攻击者可以利用这一点来获取信息并将其外泄。
{% hint style="warning" %}
请注意,为了访问本地主机,你应该尝试在Windows中重新绑定**127.0.0.1**,在Linux中重新绑定**0.0.0.0**。\
像godaddy或cloudflare这样的提供商不允许我使用IP 0.0.0.0,但AWS route53允许我创建一个带有2个IP的A记录,其中一个是"0.0.0.0"
{% endhint %}
![](<../.gitbook/assets/image (620) (4).png>)
有关更多信息,请参见[https://unit42.paloaltonetworks.com/dns-rebinding/](https://unit42.paloaltonetworks.com/dns-rebinding/)
### 其他常见绕过方式
* 如果**不允许使用内部IP**,可能**忘记禁止0.0.0.0**(在Linux和Mac上有效)
* 如果**不允许使用内部IP**作为DNS响应,你可以将**CNAME响应**返回给**localhost**(在Linux和Mac上有效)
* 如果**不允许使用内部IP**作为DNS响应,你可以将**CNAME响应**返回给**内部服务**,例如www.corporate.internal。
### 武器化的DNS Rebinding
你可以在演讲[Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference](https://www.youtube.com/watch?v=y9-0lICNjOQ)中找到有关前面绕过技术的更多信息以及如何使用以下工具。
[**`Singularity of Origin`**](https://github.com/nccgroup/singularity)是一个用于执行[DNS rebinding](https://en.wikipedia.org/wiki/DNS\_rebinding)攻击的工具。它包括将攻击服务器DNS名称的IP地址重新绑定到目标机器的IP地址以及提供攻击有效负载以利用目标机器上的易受攻击软件所需的组件。
### 防止 DNS 重绑定的真实保护措施
* 在内部服务中使用 TLS
* 请求身份验证以访问数据
* 验证 Host 标头
* [https://wicg.github.io/private-network-access/](https://wicg.github.io/private-network-access/):建议在公共服务器要访问内部服务器时始终发送预检请求
## **工具**
**模糊测试 CORS 策略中的可能配置错误**
* [https://github.com/chenjj/CORScanner](https://github.com/chenjj/CORScanner)
* [https://github.com/lc/theftfuzzer](https://github.com/lc/theftfuzzer)
* [https://github.com/s0md3v/Corsy](https://github.com/s0md3v/Corsy)
* [https://github.com/Shivangx01b/CorsMe](https://github.com/Shivangx01b/CorsMe)
## 参考资料
{% embed url="https://portswigger.net/web-security/cors" %}
{% embed url="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#CORS" %}
{% embed url="https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties" %}
{% embed url="https://www.codecademy.com/articles/what-is-cors" %}
{% embed url="https://www.we45.com/blog/3-ways-to-exploit-misconfigured-cross-origin-resource-sharing-cors" %}
{% embed url="https://medium.com/netscape/hacking-it-out-when-cors-wont-let-you-be-great-35f6206cc646" %}
{% embed url="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CORS%20Misconfiguration" %}
{% embed url="https://medium.com/entersoftsecurity/every-bug-bounty-hunter-should-know-the-evil-smile-of-the-jsonp-over-the-browsers-same-origin-438af3a0ac3b" %}
☁️ HackTricks 云 ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
* 你在一家 **网络安全公司** 工作吗?想要在 HackTricks 中 **为你的公司做广告** 吗?或者想要获得 **PEASS 的最新版本或下载 PDF 格式的 HackTricks** 吗?请查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
* 发现我们的独家 [**NFTs**](https://opensea.io/collection/the-peass-family) 集合 [**The PEASS Family**](https://opensea.io/collection/the-peass-family)
* 获取 [**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* **加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass) 或 **关注** 我的 **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
* **通过向** [**hacktricks 仓库**](https://github.com/carlospolop/hacktricks) **和** [**hacktricks-cloud 仓库**](https://github.com/carlospolop/hacktricks-cloud) **提交 PR 来分享你的黑客技巧。**