SQL Injection (Information_schema 사용)

고둑·2022년 1월 8일
0
post-thumbnail

0. Information_schema란?

MySQL에서는 기본적으로 만들어져 있는 DB가 있습니다.
그 중 information_schema라는 논리적 데이터베이스에는 모든 DB에 대한 모든 정보가 담겨있습니다.
생각보다 많은 사람들이 자신이 만들 데이터베이스만 생각하고 데이터베이스를 설계하다보니까 information_schema와 같이 자신이 직접 만들지 않은 데이터베이스는 생각하지 못한 경우가 있었습니다. 하지만 우리는 이걸 이용해서 정상적으론 접근 할 수 없는 정보에 접근할 수 있습니다.

1. 데이터베이스 이름 확인

우리가 정상적인 상황에서 데이터베이스들을 조회할때 SHOW databases를 이용하여 확인을 합니다. 하지만 문제 풀이 환경에서는 select문만 이용하여 위 같은 작업을 수행해야할 수 도 있습니다.

이럴때 우리는 SCHEMATA라는 테이블을 조회해보면 됩니다.
SCHEMATA의 컬럼에 대한 자세한 설명이 궁금하시면 공식 홈페이지에서 보시면 되고 우리가 자세히 봐야할 컬럼은 SCHEMA_NAME입니다.

select schema_name from information_schema.schemata;


SELECT문을 이용하여 SCHEMA_NAME을 보면 데이터베이스들의 이름이 나오는걸 볼 수 있습니다.
이 방식을 이용하여 존재하는 모든 데이터베이스 이름을 알아낼 수 있고 추후에 다른 공격에서 이용할 수 있습니다.
추가적으로 @mysqli_fetch_array와 같이 1개의 레코드만 반환하는 경우는 limit문을 이용하여 1줄씩 반환 받을 수 있습니다.

이 외에도 database()를 이용하면 현재 사용중인 데이터베이스를 조회할 수 있습니다.

2. 테이블 이름 확인

우리가 정상적인 상황에서 테이블들을 조회할때 SHOW tables를 이용하여 확인을 합니다. 하지만 위에서 말한 대회나 문제 풀이 환경에서는 대부분 기존 select문에 추가적인 명령어를 삽입하여 우리가 원하는 방식으로 쿼리를 바꾸게 됩니다. 따라서 select를 이용하여 테이블들을 조회할 수 있어야합니다.

이런 정보를 얻기 위해서는 information_schema에 존재하는 tables테이블을 참조해야합니다. tables 테이블에 사용되는 컬럼의 자세한 설명은 공식 페이지에서 찾아보면 되고 이 중 우리가 알아야할 컬럼은 table_schema, table_name입니다.

table_schema는 해당 테이블이 속해있는 데이터베이스의 이름입니다.
table_name은 해당 테이블의 이름이 들어가있는 컬럼입니다.

따라서 tables에서 table_schematable_name을 모두 조회하면 존재하는 모든 데이터베이스에서 모든 테이블의 이름이 나타나게됩니다. 하지만 모든 데이터베이스라는 것은 논리적 데이터베이스인 information_schema, mysql, performance_schema, sys에 존재하는 모든 데이터베이스를 포함하는 결과 값입니다. 따라서 실제적으로 데이터가 존재하는 데이터베이스만을 보려면 논리적 데이터베이스를 where문으로 결과에서 제외시켜야합니다.

select table_schema, table_name from information_schema.tables where TABLE_SCHEMA != "sys" and TABLE_SCHEMA != "information_schema" and TABLE_SCHEMA != "mysql" and TABLE_SCHEMA != "performance_schema";

이 방식으로 쿼리를 전송하면 아래와 같이 존재하는 모든 테이블 명을 얻을 수 있습니다.

이 방법을 1번에서 얻었던 데이터베이스의 이름과 함께 사용하면

select table_schema, table_name from information_schema.tables where TABLE_SCHEMA = "sqli_test";


이런 식으로 공격하고 싶은 특정한 데이터베이스의 테이블 이름만 가져오는 것이 가능합니다.

3. 컬럼 이름 확인

데이터베이스에서 데이터를 조회하기 위해서는 컬럼의 이름이 필요합니다. 정상적인 접근일 경우 개발자 측에서 필요한 모든 정보를 세팅해서 우리가 저런 사소한 정보까지 모르고 지나갈 수 있으나 정상적인 접근이 아닌 경우 우리가 직접 추출할 데이터를 지정해야합니다.
위 1,2번 에서 데이터베이스의 이름과 테이블의 이름까지 모두 추출했으므로 마지막으로 컬럼의 이름을 알아내면 성공적으로 데이터를 조회할 수 있습니다.

컬럼에 관한 정보는 information_schemacolumns 테이블에 저장되어있습니다.
columns 테이블에 대한 자세한 정보는 공식 홈페이지에 자세히 나와있습니다.
이 중에서 우리가 봐야할 컬럼은 위에서 사용했던 table_schema, table_name을 포함하여 column_name을 추가로 확인해야합니다.
column_name은 말 그대로 컬럼의 이름을 저장하고 있는 테이블입니다.

select table_schema, table_name, column_name from information_schema.columns;

따라서 위 쿼리로 column_name를 조회할 수는 있지만 2번에서 말했던 것처럼 사용할 필요가 없는 논리적 데이터베이스의 정보까지 조회가 되므로 table_schema의 이름을 필터링해주면 됩니다.

select table_schema, table_name, column_name from information_schema.columns where TABLE_SCHEMA != "mysql" and TABLE_SCHEMA != "sys" and TABLE_SCHEMA != "information_schema" and  TABLE_SCHEMA != "performance_schema";


이런 식으로 필터링을 해주면 개발자가 만든 데이터베이스에 존재하는 모든 테이블에 존재하는 모든 컬럼의 이름을 조회 할 수 있습니다.

여기서도 1,2번 방식으로 알아냈던 추가적인 데이터베이스의 이름이나 테이블의 이름을 통해서 조회할 대상을 지정할 수 있습니다.

select table_schema, table_name, column_name from information_schema.columns where TABLE_SCHEMA = "sqli_test";

select table_schema, table_name, column_name from information_schema.columns where TABLE_SCHEMA = "sqli_test" and TABLE_NAME = "sqli_test_1";

이런 식으로 알고 있는 정보를 이용하여 구체적으로 대상을 지목 할 수 있습니다.

profile
문워킹은 하지말자

0개의 댓글