읽어봐주세요!
- 해당 글은 제가 만든 사이트인 에서 실습해 볼 수 있습니다.
- 해당 글에서
배운 지식으로 타 사이트를 공격하는 것에 대하여 아무 책임도 지지 않고
, 문의 또한 받지 않습니다.
- 만약 해당 공격을 수행하실 경우, 반드시 관제시스템에 의하여 막힐뿐만 아니라 철창 신세를 질수도 있기 때문에 실습 환경에서만 연습하시기 바랍니다.
1. SQL이란
Sql는
Structured Query Language
의 약자로서 데이터를 관리하기 위해 설계한 특수 목적의 프로그래밍 언어입니다. Database, Table등을 생성, 수정, 삭제 할 때 사용됩니다.2. SQL INJECTION(SQLI)에 대한 이해
2.1 SQL Injection
SQL Injection은 웹사이트에서 SQL를 이용하여 데이터를 가져오는 섹션에서
의도치 않은 SQL query를 전송하여 공격자가 원하는 데이터베이스의 중요한 정보를 가져오는 해킹 기법
입니다. 2.2 왜 취약한가?
db의 권한에 따라 현재 사용하고 있는 테이블의 정보부터, 다른 테이블의 정보, 다른 db의 정보, 심지어 파일을 읽어오거나 파일을 생성할 수 있기 때문에 “매우 취약합니다”
2.3 현재는 멸종한 SQL Injection?
실제로 SQL Injection은 매우 취약한 취약점이기 때문에, 기업에서 많이 신경쓰는 부분입니다. 기술적으로도
prepare statement
라는 기술과, ORM
기술의 보편화로 현재는 SQL Injection을 굵직한 기업에서 보기는 거의 불가능합니다.하지만 현재 CVSS에 올라오는 취약점 목록을 보면,
외국계 PHP 스타트업이나, 오래되고 관리되지 않은 게시판을 갑자기 사용한다던가 할 때 취약점이 발생하기도 합니다.
따라서 완전히 사라진 취약점은 아닙니다.3. SQL Injection이 발생하는 케이스
보통 CRUD가 구현되어 있는 서비스에서 많이 발생합니다. 그 외에도
쿠키
나 URL PATH
등 정말 다양한 곳에서 일어날 수 있습니다.3.1 Select (질의)
여기서 말하는 질의란, 데이터를 가져오는 부분에 대한 것 입니다. 예를 들어
로그인 정보를 조회한다던가, 게시판의 ID로 글을 불러온다던가, 비밀번호를 찾거나 내용을 검색하는 부분
이 해당됩니다.예시
예시로 로그인을 수행할 때 해당 SQL 질의문을 사용합니다.
만약 여기서 SQL Injection 공격이 발생한다면 어떤 취약점이 발생할 수 있을까요?
- upw 부분(비밀번호)이 True(’’ or 1)로 바뀌면서
admin
으로 비밀번호를 몰라도 로그인을 할 수 있습니다.
- 로그인 우회 뿐만이 아니라
upw부분에 서브쿼리 혹은 조건식을 넣어 참/거짓반응을 통해 다른 데이터도 추출
할 수 있습니다.
실제 수행 (UNION SQL Injection을 이용한 공격)
- 게시판이 존재하고, 게시글이 현재 두개가 있습니다.
- 상단에 보면 검색 기능 또한 존재합니다.
- 게시글의 검색 부분의 쿼리는 다음과 같습니다.
- 여기서
search
부분에 SQL Injection을 수행할 수 있습니다.
- 만약 Select 쿼리가 올바르게 동작한다면 data가 row별로 들어가게 됩니다.
- 따라서 여기서는
union sql injection
을 통하여 원하는 값을 검색 글에 노출해보도록 하겠습니다.
- 사용자가 검색창에
test
라는 문자열을 입력하였을 때입니다.
- 정상적인 질의를 한다면 이런식으로 질의가 될 것입니다.
- 하지만 SQL Injection을 통하여
LIKE
부분을 false로 만들어서 조회되는 데이터가 없도록 하고, 뒤에 UNION을 사용하여 또 다른 행을 원하는 값으로 가져온다면 어떻게 될까요?
- 이런식으로
' and 0 UNION SELECT 1,@@version,database(),database(),database(),1,1#
문구를 검색에 삽입함으로서, mysql 버전과 사용하고 있는 database의 정보를 추출할 수 있었습니다.
- 이 외에도
information_schema
정보 등을 이용해서 사용자의 아이디, 비밀번호를 알아내거나 다른 데이터베이스의 정보를 추출하는 등, 권한에 따라 정말 많은 공격을 수행할 수 있습니다.
3.2 INSERT 구문 (삽입)
예시
회원가입을 진행한다고 할때, 다음과 같은 쿼리문을 사용할 것입니다.
- 아이디, 비밀번호, 닉네임 등을 받아서
user_table
에 삽입합니다.
➡️ SQL Injection을 이용한 고정 필드 우회
- 만약 회원가입의 권한이
user
로 고정되어 있다고 가정해 보겠습니다.
- 이때 해당 권한을
master
로 상승시켜 보겠습니다.
- nickname을 입력하는 부분에서 뒤에 따라오는 권한을 입력해주고 주석 처리를 하면
master
뒤에 있는user
이 주석 처리되어master
로 회원가입을 할 수 있습니다.
➡️ 컬럼 수 알아내기
- 대부분의 데이터베이스는 묵시적으로 정수형 데이터를 문자형으로 변환합니다. 따라서 필드의 개수를 파악하는데 정수형을 이용할 수 있습니다.
- 컬럼을 하나씩 늘려가면서 SQL Injection을 수행한 후, 만약
회원가입이 된다면 컬럼의 수를 알아낼 수 있습니다.
실습 (INSERT를 이용한 DB정보 추출)
- 글을 작성하는 부분이 존재합니다. 여기서 작성자는 고정으로 박혀있습니다.
- 글을 작성하는 쿼리는 다음과 같습니다.
- 여기서 앞서 예시로 배웠던 SQL Injection 공격을 통해, 데이터베이스 정보를 추출해 보겠습니다.
- 제목에는
SQLInjection
/ 작성자에는db
/ 내용은1
이 들어가게 됩니다.
- 이런식으로 Select가 아닌 insert로도 정보를 유출시킬 수 있습니다.
3.3 UPDATE 구문
예시
만약 사용자 이름과 비밀번호를 사용하여 유저 정보를 수정하는 SQL 구문이 존재한다고 가정할 때 SQL Injection을 통하여
비밀번호 자체를 삭제하거나
, 기존 비밀번호의 인증을 무시하고 변경
하는 취약점이 발생할 수 있습니다.- 비밀번호를 변경할 때, 보통 기존 비밀번호를 인증하여야 합니다.
- 하지만 SQL Injection을 통해
upw 섹션을 주석 처리하면, 무시가 되면서
뒤에 있는 upw(비밀번호)검증이 우회 됩니다.
- 또 다른 접근 방법으로,
password
부분을 공백으로 처리한다면, 비밀번호가 없는 아이디를 만들 수 있습니다.
3.4 DELETE 구문
UPDATE 구문과 마찬가지로 검증 로직 등을 SQL Injection을 통하여 우회할 수 있다면 사용자 정보 삭제 등 파급력이 엄청난 공격을 수행할 수 있습니다.
- 보통 DELETE 부분에선 SQL Injection의 파급력과, 미흡한 검증로직으로 자신이 소유하지 않은 자산에 대하여 삭제할 수 있는 취약점을 동시에 검색합니다.
추가로 미흡한 검증 로직에 대한 예시를 보여드리겠습니다.
예시 (타인의 글 삭제 가능)
- 자신이 생성한 글만 삭제할 수 있는 게시판이 존재합니다.
- 정확히 말하면, 세션에 있는 자신의 닉네임과 작성자의 닉네임이 일치하면
버튼을 표시합니다
- 자신이 아무 글이나 작성하고, 삭제 버튼을 누를 때,
파라미터에서 id 번호를 변경해서 글이 삭제된다면
미흡한 검증 로직 취약점으로 인정받을 수 있습니다.
4. 다양한 SQL INJECTION 방법
4.1 Blind SQL Injection
Blind SQL Injection에 대한 이해
Blind SQL Injection은 기본적으로 블랙박스 관점(소스코드가 주어지지 않은 상태)에서 공격 query를 날렸을 때 내부적인 반응으로 공격을 확인하는 기법입니다. SLEEP 함수를 사용하여 서버의 응답 시간을 체크하는 등 미세한 반응을 관찰한다.
Time-Based Blind SQLI
Time-Based Blind SQLI는 DBMS에서 시간 지연과 같은 함수들을 사용하여 요청 값이 참이면 응답이 느리게 오는 것을 이용한 SQL Injection 기법입니다. 공격자는 SLEEP, BENCHMARK 등을 이용하여 지연 시간을 보고 참/거짓을 판단하여 공격을 수행합니다.
예시로 만약 유저 테이블이 존재한다고 가정하고, SLEEP 함수를 이용해서 SQLI 공격을 수행할 수 있습니다.
- 이렇게 하면 admin의 password에 대한 값을 하나씩 추출하여 비교, 만약 비교한 문자열이 정답이라면 데이터베이스에서 SLEEP 함수를 실행합니다. SLEEP함수를 실행하게 되면 시간 지연이 발생함으로 공격자는
참/거짓 반응을 통해
비밀번호를 추출할 수 있습니다.
4.2 Error-Based SQLI
만약 db쿼리를 의도치 않게 변조하였는데 응답 페이지에서
Error 메세지가 출력 될 경우 Error-Based SQLI공격이 가능할 수 있습니다.
예시로 mysql에서는 extractvalue라는 함수는 첫번째 인자로 전달된 XML 데이터에서 두번째로 입력받는 값(XPATH 식) 을 통해 데이터를 추출합니다.
여기서 만약 일부로 에러를 발생 시켜서 에러 메세지에 삽입된 식의 결과를 출력하게 하면 어떻게 될까요?
이런 식으로 의도적으로 에러를 발생 시키고, 에러가 노출된다는 취약점을 이용하여 원하는 공격 구문을 삽입할 수 있습니다. 여기서
0x3b를 붙여준 이유는 올바르지 않은 xpath 식을 주입하기 위함입니다.
이외에도,
조건부가 참값일 경우 의도적으로 에러를 발생시켜 조건부를 확인할 수 있습니다.
만약 SQL Injection을 테스트 하는 중에 500에러
등 DB에서 에러가 발생하여 웹서버가 에러를 반환할 경우 Error_based로 SQLI를 테스트 해볼 수 있습니다.- 쿠키값에 SQLI를 하는 모습
- Oracle db에서 조건부 에러를 발생시켜 조건을 확인할 수 있는 모습입니다.
4.3 UNION SQL Injection
말 그대로 UNION함수를 사용한 SQL Injection입니다.
선행 쿼리와 컬럼 갯수만 일치한다면 UNION 구문 뒤에 나오는 쿼리를 출력 시킬 수 있습니다.
예시로 검색 기능에서 데이터베이스 이름을 노출 시키려면 다음과 같이 할 수 있습니다.
4.4 DB 메타데이터를 이용한 Blind SQL Injection
대부분의 웹사이트의 경우 SQL 쿼리 자체를 노출 시키는 경우는 없습니다. 따라서 공격자의 입장으로 보았을 때,
공격자는 해당 SQL 구조를 예상하고 해당 구조에 어떻게 SQL 구문을 집어넣을지 고민하여야 합니다.
SQL 구조를 알아내고 데이터를 추출해내는 과정은 다음과 같습니다.- db개수 파악
- db 이름 파악
- table 개수 파악
- table 이름 파악
- table 필드 개수 파악
- 필드 이름 파악
- 데이터 추출
SQL Injection을 하는 과정에서 무조건 해당 내용을 먼저 추출하여야 하는 것은 아닙니다. 하지만 만약
데이터베이스, 테이블, 컬럼에 대한 아무런 정보가 존재하지 않다면 해당 과정을 수행하여야 합니다
. mysql, sqlite, msSQL은 각각 메타 데이터가 포함된 데이터 베이스가 존재하고, 해당 내용을 추출할 수 있으면 DB정보 탈취가 가능합니다.예시로 mysql에서 메타데이터 추출을 시도하는 과정입니다.
- 앞서 말한 error-based, time-based 혹은 union을 이용한 데이터 추출, 다양한 방법으로 db 데이터추출이 가능합니다.
- 추출한 데이터로 이제 실제로 운용되고 있는 db의 정보를 탈취할 수 있다.
5. 정보 추출시 사용되는 공격 기법들
5.1 CHAR Extract binary search
추출하고 싶은 문자열을 십진수 형태로 변환한 후 이진탐색을 통하여 문자열을 맞추는 방식이다
- 해당 구문과 같이 범위 연산을 통하여 정답을 맞출 수 있다.
5.2 bit연산
추출하고 싶은 문자열을 이진수 형태로 만들어서 비트 계산을 통해 문자열을 계산하는 것이다. 보통의 문자열은 ascii code로 1~2^7-1 총 8비트 임으로 한자리씩 맞추면 된다
- 먼저 ord 함수를 통해 추출하고 싶은 문자열을 10진수로 변경한다
- 그 이후 bin함수를 통해 2진수로 변경한다.
- 최종적으로 한 자리수마다 8번의 비교 연산을 통해서 맞출 수 있다.
ord와 ascii 함수의 차이?
MySQL에서는 문자열을 저장할 때, 다양한 문자 집합을 사용할 수 있습니다. 이 때 멀티바이트 문자열이란, 문자 하나당 여러 개의 바이트를 사용하는 문자열을 말합니다. 예를 들어 한글은 UTF-8 인코딩을 사용할 때, 초성, 중성, 종성 각각이 하나의 바이트로 저장되며, 총 3개의 바이트로 이루어진 문자열입니다.
따라서, 멀티바이트 문자열을 다루는 경우, 문자 하나당 하나의 아스키 코드 값을 반환하는 ascii 함수는 적절하지 않습니다. 반면, ord 함수는 멀티바이트 문자열도 처리할 수 있도록 구현되어 있어, 해당 기능을 지원합니다.
이를 통해, ord 함수가 멀티바이트 문자열 처리에 더 효과적이며, ascii 함수는 해당 기능을 지원하지 않는다는 것을 알 수 있습니다.
6. 방어 기법
5.1 [고전] 특정 문자 필터링
개념
아주 옛날 호랑이 담배 피던 시절 사용된 방법으로 sql injection에 사용될 문자열 등을 필터링 하는 것입니다.
'
"
or
||
등등 SQL Injection에 사용되는 특수문자, 문자열 등을 이스케이핑 처리 합니다.
문제점
- 사용자가 사용하고자 하는 문자를 사용할 수 없을 수 있습니다. (가용성 침해)
- 안전한 시스템은 없습니다. SQL은 자신이 생각한 것보다 다양한 기능을 제공하고 있고, 반드시 뚫리게 되어있습니다.
- 관리가 어렵습니다.
5.2 Prepare stmt(prepare statement)
개념
SQL Injection을 방어하기 위해 등장한 개념으로, 사용자가 입력한 문자열을
문자열 그 자체
로 인식합니다. 어떠한 특수문자가 들어가거나, 쿼리문이 포함되어도 SQL Injection이 발생되지 않습니다.사용
각 플랫폼 별로 다르며, JAVA를 기반으로 만들어지는 SpringFramework의 경우 ORM을 지원하는데, 여기서 자동적으로 Prepare stmt를 지원한다.
5.3 ORM
JPA를 써봤다면 알것 같은데, ORM 형식의(객체와 관계형 데이터베이스의 데이터를 자동으로 매핑) 구조로 DB를 사용한다면, 자동적으로 PrePareStmt를 거의 지원하기 때문에 안전하다고 할 수 있습니다.
⚠️ 대신 db프레임 워크에서 취약점이 발생하는 경우도 있을 수 있습니다.
7. WAF Bypass
7.1 XML ENTITY
XML로 백엔드에 데이터를 전달할 경우, XML ENTITY를 이용하여 WAF를 무력화 시킬 수 있습니다.
예를 들어 XML형식으로 데이터를 보내는 웹사이트가 있다고 가정하겠습니다.
만약 여기에 SQL Injection이 터진다고 해도, WAF(웹 방화벽)이 있다면 무용지물이 될 수 있습니다.
이따 XML 엔티티를 이용하여 인코딩하게 되면, WAF를 우회할 수 있습니다
- burp suite를 쓰신다면 Hactivator에서
<@dec_entities>
를 사용하시면 됩니다.