Prototype pollution — bu JavaScript zaifligi bo'lib, hujumchiga global obyekt prototiplariga ixtiyoriy xususiyatlar (property) qo'shishga imkon beradi. Bu xususiyatlar keyinchalik foydalanuvchi tomonidan yaratilgan obyektlar tomonidan meros qilib olinishi mumkin.
Prototype pollution ko'pincha mustaqil zaiflik sifatida ekspluatatsiya qilib bo'lmasa-da, u hujumchiga boshqacha yo'l bilan yetib bo'lmaydigan obyekt xususiyatlarini nazorat qilishga imkon beradi. Agar ilova keyinchalik hujumchi nazoratidagi xususiyatni xavfli tarzda ishlatsa, buni boshqa zaifliklar bilan zanjirlash mumkin. Client-side JavaScriptda bu odatda DOM XSS'ga, server-side prototype pollution esa hatto masofaviy kod ijrosiga (RCE) olib kelishi mumkin.
JavaScriptdagi deyarli har bir obyekt yaratilishida avtomatik ravishda prototip deb ataladigan boshqa obyektga bog'lanadi. Prototip — bu meros qilib olinadigan standart xususiyatlar va metodlar to'plamini o'z ichiga olgan tayyor obyekt. Obyektda mavjud bo'lmagan xususiyatga murojaat qilinganda, JavaScript uni prototip zanjiri (prototype chain) bo'ylab qidiradi — obyektning o'z prototipida, so'ng uning prototipida va hokazo.
Ko'pchilik obyektlar oxir-oqibat o'rnatilgan global Object.prototype dan meros oladi. Obyekt prototipiga __proto__ maxsus aksessor xususiyati orqali murojaat qilish mumkin:
let myObject = {};
myObject.__proto__; // Object.prototype ga havola
Object.getPrototypeOf(myObject); // aynan shu narsaPrototype pollution zaifliklari odatda JavaScript funksiyasi foydalanuvchi nazoratidagi xususiyatlarni o'z ichiga olgan obyektni mavjud obyektga rekursiv ravishda birlashtirganda (merge), kalitlarni oldindan tozalamasdan yuzaga keladi. Bu hujumchiga __proto__ kabi kalit va ixtiyoriy ichma-ich xususiyatlarni kiritishga imkon beradi. __proto__ ning JavaScriptdagi maxsus ma'nosi tufayli, merge operatsiyasi bu xususiyatlarni maqsad obyektga emas, balki uning prototipiga tayinlashi mumkin.
Muvaffaqiyatli ekspluatatsiya uchun uch komponent kerak:
Manba — prototip obyektlariga ixtiyoriy xususiyat qo'shishga imkon beruvchi har qanday foydalanuvchi nazoratidagi kirish. Eng keng tarqalganlari: URL (query yoki fragment/hash orqali), JSON-asosidagi kirish va web message'lar.
Hujumchi tuzgan quyidagi query stringni ko'rib chiqing:
https://vulnerable-website.com/?__proto__[evilProperty]=payloadBu kalit:qiymat juftlari mavjud obyektga birlashtirilganda, rekursiv merge quyidagiga teng amalni bajarishi mumkin:
targetObject.__proto__.evilProperty = 'payload';Bu tayinlash paytida JavaScript dvigateli __proto__ ni prototip uchun getter sifatida ko'radi. Natijada evilProperty maqsad obyektga emas, qaytarilgan prototip obyektiga tayinlanadi — va runtime'dagi barcha obyektlar endi uni meros qilib oladi.
Foydalanuvchi nazoratidagi obyektlar ko'pincha JSON.parse() orqali JSON satridan olinadi. Qizig'i, JSON.parse() __proto__ kabi har qanday kalitni ixtiyoriy satr sifatida qabul qiladi:
const objectLiteral = {__proto__: {evilProperty: 'payload'}};
const objectFromJson = JSON.parse('{"__proto__": {"evilProperty": "payload"}}');
objectLiteral.hasOwnProperty('__proto__'); // false
objectFromJson.hasOwnProperty('__proto__'); // trueKo'rib turganingizdek, JSON.parse() orqali yaratilgan obyekt haqiqatan ham o'z __proto__ xususiyatiga ega bo'ladi — u keyin merge qilinganda prototip ifloslanadi.
Sink — prototype pollution orqali kirish mumkin bo'lgan va ixtiyoriy JavaScript yoki tizim buyruqlarini bajarishga imkon beruvchi JavaScript funksiyasi yoki DOM elementi (masalan innerHTML, eval()). Gadjet — zaiflikni haqiqiy ekspluatatsiyaga aylantiruvchi vosita: ilova tomonidan xavfli tarzda ishlatiladigan VA prototype pollution orqali hujumchi nazorat qila oladigan xususiyat.
Agar xususiyat obyektning o'zida to'g'ridan-to'g'ri aniqlangan bo'lsa, u gadjet bo'la olmaydi — obyektning o'z versiyasi prototipdagi zararli versiyadan ustun turadi. Mustahkam saytlar obyekt prototipini null ga o'rnatib, hech qanday xususiyat meros olinmasligini ta'minlashi mumkin.
Ko'p JavaScript kutubxonalari sozlamalar uchun config obyektini qabul qiladi. Agar biror sozlama mavjud bo'lmasa, standart qiymat ishlatiladi:
let transport_url = config.transport_url || defaults.transport_url;
let script = document.createElement('script');
script.src = `${transport_url}/example.js`;
document.body.appendChild(script);Agar sayt ishlab chiquvchilari transport_url ni o'rnatmagan bo'lsa, hujumchi global prototipni o'z transport_url bilan ifloslab, skript manbasini o'z domeniga yo'naltirishi mumkin:
https://vulnerable-website.com/?__proto__[transport_url]=data:,alert(1);//Oxiridagi // qattiq kodlangan /example.js qo'shimchasini izohga (comment) aylantirish uchun.
Endi asosiy tushunchalar bilan tanishdik. Prototype pollutionni real ilovalarda qanday topish va ekspluatatsiya qilishni ko'rib chiqamiz: Client-side prototype pollution, Server-side prototype pollution va oldini olish.