Oracle 学习

基础知识

  • 端口号:1521

  • 下载地址:

    • http://download.oracle.com/otn/nt/oracle11g/112010/win32_11gR2_database_1of2.zip

    • http://download.oracle.com/otn/nt/oracle11g/112010/win32_11gR2_database_2of2.zip

    • https://www.oracle.com/tools/downloads/sqldev-downloads.html

  • sqldeveloper 工具连接

  • Oracle 权限

    • ORACLE 系统提供三种权限:Object 对象级System 系统级Role 角色级

  • 如果授予一个权限给特殊用户 Public(用户 public 是 oracle 预定义的,每个用户享有这个用户享有的权限),那么就意味作将该权限授予了该数据库的所有用户

  • 权限被大体分为两类:

    • 系统权限:系统规定用户使用数据库的权限(系统权限是对用户而言)

      • 系统权限就是我们常见的 CREATE SESSION、ALTER SESSION 等权限,这些权限通常通过角色来进行分配

      • oracle 中有几个常见的预定义角色:

        • DBA: 拥有全部特权,是系统最高权限,只有DBA才可以创建数据库结构

        • RESOURCE: 拥有 Resource 权限的用户只可以创建实体,不可以创建数据库结构

        • CONNECT: 拥有 Connect 权限的用户只可以登录 Oracle,不可以创建实体,不可以创建数据库结构

      • 一般普通用户拥有 connect、resource 角色,而管理员拥有 connect、resource、dba 角色

    • 实体权限:某种权限用户对其它用户的表或视图的存取权限(是针对表或视图而言的)

      • 简单说就是用户对表、视图、存储过程等有什么权限

      • 表权限:SELECT、DELETE、UPDATE、INSERT、ALTER

      • 视图权限:SELECT、DELTE、INSERT、UPDATE

      • 过程、函数、程序包权限:EXECUTE、DEBUG

    • 权限查询

      -- 查看所有角色
      select * from dba_roles;
      
      -- 查看当前用户被激活的全部角色
      select * from session_roles;
      
      -- 查看当前用户被授予的角色
      select * from user_role_privs;
      
      -- 查看当前用户是否为DBA
      select t.DEFAULT_ROLE from user_role_privs t where t.granted_role='DBA';
      
      -- 查看当前用户所拥有的全部权限
      select * from session_privs;
      
      -- 查看当前用户的系统权限
      select * from user_sys_privs;
      
      -- 查看当前用户的表级权限
      select * from user_tab_privs;
      
      -- 查看某个用户所拥有的系统权限
      select * from dba_sys_privs;
      
      -- 查看角色(只能查看登陆用户拥有的角色)所包含的权限
      select * from role_sys_privs;
      
      -- 查看用户的java权限(用户名必须大写)
      select * from user_java_policy where grantee_name='SCOTT';
      
      -- 设置输出列宽,优化 sqlplus 交互式命令行的输出
      COL TYPE_NAME FOR A30;
      COL NAME FOR A30;
      COL ACTION FOR A10;
      select TYPE_NAME, NAME, ACTION from user_java_policy where grantee_name = 'TEST4';
    • 权限更改

      • 可以通过 GRANT 和 REVOKE 命令来对账户进行权限的授予和撤回,一般这些操作会由 DBA 用户(SYS 用户和 SYSTEM 用户)来执行

      • 而权限的赋予通常也是通过角色(Role)这个“桥梁”来做的(当然也可以直接赋给 user),举个例子,创建一个用户,并给该用户赋予 create sessioncreate procedure

      -- 进入交互式命令行
      sqlplus
      
      -- 创建一个的用户
      create user <用户名> identified by <密码>;
      
      -- 创建一个 role
      create role <角色名>;
      
      -- 将 connect 和 create procedure 赋给 testrole
      grant connect,create procedure to <角色名>;
      
      -- 将testrole这个角色给用户test
      grant <角色名> to <用户名>;
      
      -- 这样我们可以将 testrole 给多个用户,修改权限时只需要添加/删除角色的权限即可,方便批量管理,类似Active Directory中的组
      
      -- 使用 revoke 收回某个权限
      revoke create procedure from <角色名>;
      
      -- 修改用户密码
      alter user <用户名> identified by <密码>;
      
      -- 删除用户和角色
      drop user <用户名> cascade;
      drop role <角色名>;

PL/SQL注入

PL/SQL 是 Oracle 公司在标准 SQL语言 的基础上进行扩展,可以在数据库上进行设计编程的一种过程化的语言,类似程序语言 JAVA 一样可以实现逻辑判断、条件循环、异常处理等细节操作,可以处理复杂性问题

  1. 如果 PL/SQL 使用 AUTHID CURRENT_USER 关键词创建,它执行时会以调用者(invoker)的权限来执行

  2. 如果没有 AUTHID CURRENT_USER 这个关键词,它执行时会以它的定义者(definer)的权限来执行

  3. 注:Oracle不支持堆叠注入(多语句执行)

Cursor注入

下面这个 procedure 由 DBA(SYS) 创建,并赋予 public 执行权限,数据库能所有用户都可以调用这个 procedure

由于没有声明 AUTHID CURRENT_USER,所以该存储进程执行时的权限是其定义者(definer),也就是SYS

很明显 P_OBJNM 是存在 SQL 注入的,但由于 Oracle 不支持堆叠查询,我们只能够使用联合查询来注出一些数据,但仅仅查数据肯定不能满足我们的需求

创建一个执行其他命令的函数(需要 CREATE PROCEDURE 权限),并且加上 AUTHID CURRENT_USER,然后用 || 将函数注入到 SQL 语句中,当 SQL 语句以 SYS 权限执行时,这个被注入的函数作为 SQL 语句的一部分也会被执行

在这里的GET_DBA这种函数被称为辅助注入函数,如果我们没有办法自己创建辅助注入函数的话,就要寻找oracle上已经存在的、可以辅助注入的函数。其它的可以看这里:

  • https://www.t00ls.net/articles-23609.html

  • http://www.davidlitchfield.com/HackingAurora.pdf

Lateral SQL注入

主要针对以下两种情况:

  • Procedure 不接收用户输入的参数(参数不可控)

  • Procedure 中 SQL 语句拼接的参数被定义为 NUMBER 或 DATA 类型

下面这个存储过程接收一个日期类型的参数,并将参数动态拼接入 SQL 语句

下面这个存储进程不接收任何参数,拼接入 SQL 语句中的参数从 sysdate 中获取

权限提升

SET_OUTPUT_TO_JAVA

  • 权限要求:CREATE SESSION

  • 测试环境:Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit

  • 原理:该函数可以利用前面提到的 Lateral SQL Injection 来进行注入,进而获取 DBA 权限

    • 这个函数允许用户在另一个新的虚拟 session 中重定向 java 输出写入到 System.out 和 System.err,最后两个参数的 SQL 语句将在这个新 session 中执行

    • 如果攻击者可以得到一个属于 SYS 的使用 java 的 package 并将它写入 System.out 和 System.err,那么这个新会话的所属者就是 SYS,进而所执行的 SQL 语句也将以 SYS 权限执行

    • DBMS_CDC_ISUBSCRIBE 正是一个符合条件 package,它可被 public 执行,属于 SYS 并且是 definer 权限执行,通过将无效的订阅名传递给这个包的 e INT_PURGE_WINDOW 过程,则可以将错误强制写入 System.err,随后将以SYS权限执行前一个请求的参数中提供的SQL语句

  • 利用

GET_DOMAIN_INDEX_TABLES

  • 影响版本:Oracle Database <= 10g R2 (未打补丁的情况下)

  • 测试环境:Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

  • 权限要求:CREATE SESSION

  • 原理:

    • SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES 函数的定义

    • 可以看到当 GET_TABLES != 1 时,TYPE_NAMETYPE_SCHEMA 被直接动态拼接进 PL/SQL 语句中并执行,由于这个函数是以 definer 权限来执行的,所以我们注入的语句也会以 SYS 权限来执行

    • 因此我们构造语句,传入参数TYPE_NAME

    • 本地用 pl/sql 手动打印

LT.FINDRICSET

  • 测试环境:Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

  • 权限要求:CREATE SESSION CREATE PROCEDURE

  • 原理:该方法利用 SYS.LT.FINDRICSET 这个函数的注入漏洞来实现权限的提升

    • 函数定义

    • 这个函数又调用了 SYS.LTRIC.FINDRICSET,定义如下

    • IN_TABLE_OWNER和IN_TABLE_NAME 直接动态拼接到 SQL 语句中,是可以注入的点

    • 创建一个赋权的存储进程,然后闭合 SQL 语句,在参数处调用存储进程

  • 利用:

  • 注入环境中可使用 dbms_xmlquery.newcontext 来执行

SDO_DROP_USER_BEFORE

  • 测试环境:Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

  • 权限要求:CREATE SESSION

  • 这个是一个触发器(trigger)漏洞,触发器在数据库里以独立的对象存储,它与存储过程和函数不同的是,存储过程与函数需要用户显示调用才执行,而触发器是由一个事件来启动运行

  • 原理:

    • SDO_DROP_USER_BEFORE 触发器的的定义

    • 可以看出这个触发器是在 drop 用户时会执行对应的命令,而 dictionary_obj_name 被动态拼接到 PL/SQL 中,存在注入

    • SDO_DROP_USER_BEFORE 这个触发器属于 MDSYS,而且是以definer的权限来执行的,MDSYS 在 oracle 9i 中是 DBA 权限,后来在 10g R2 上被降权了,因此无法直接通过注入来获取DBA权限

    • 但是也不是毫无办法,MDSYS 拥有 create any trigger,也就是说我们可以利用这个注入来任意创建触发器

    • 那么我们完全可以在 SYSTEM 下创建一个触发器来执行我们想要的命令,然后触发这个新创建触发器,从而以 system 来执行我们的命令

    • 直接看 POC,使用游标创建一个 procedure(当然也可以不使用游标),该过程在 system 下创建一个触发器,当向 system.OL$ 中插入数据时(默认 public 可向该表中插入数据),就会触发执行 grant dba to public

    • 之后将注入该procedure的payload放到drop的用户名中,触发SDO_DROP_USER_BEFORE执行,再向system.OL$中插入数据即可

  • 利用

命令执行

DBMS_XMLQUERY

  • 测试环境:

    • Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit

    • Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

  • 权限要求:CREATE SESSION CREATE PROCEDURE

  • 创建用户

  • 创建 java source

  • 创建函数

  • 通过查询 OBJECT_ID 来判断函数是否创建成功

  • 赋予需要的三个 java 权限:当前用户为 DBA 时,通常只需要为该用户赋予第一个执行权限即可

  • 执行命令

创建存储进程执行命令

  • 测试环境:

    • Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit

    • Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

  • 权限要求:CREATE SESSION CREATE PROCEDURE

  • 有时执行命令也会碰到这种报错,此时需要为用户赋予 java 的对应权限,最好执行前先执行一次 dbms_xmlquery 中赋予那三个权限的命令,如果你已经创建完 javae 函数在执行命令时发现了这个报错,那么要再执行一次 2.sql,然后再执行 javae 函数

  • 将下面文件分别保存为:

    • 1.sql

    • 2.sql

  • 放在 sqlplus 同级目录下,然后分别执行

  • 执行命令

DBMS_JAVA.RUNJAVA

  • 测试环境:

    • Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit

    • Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

  • 权限要求:CREATE SESSION

  • 先给当前用户赋予 java.io.FilePermission

  • 执行命令

Web层面的利用

  • 前面提到过 Oracle 并不支持堆叠注入,但是前面介绍的 dbms_xmlquery.newcontext 是可以执行 PL/SQL 语句的,因此当我们遇到 Oracle 的 SQL 注入点时,就可以构造执行 dbms_xmlquery.newcontext 的语句来进行命令执行

  • 总结

    • 一般 PL/SQL 注入利用的条件:存在注入的 PL/SQL 属于高权限用户(一般关注SYS),且以 definer 权限执行

    • 对用户权限的要求:如果用户没有 CREATE PROCEDURE 权限,则需要寻找数据库已有的辅助注入函数,如果用户有 CREATE PROCEDURE 权限,则可以自己创建辅助注入函数

    • 如果没有辅助注入函数

      1. 如果注入点是在 execute immediate 后的 PL/SQL 语句中,那么可以考虑直接注入匿名 PL/SQL 语句块

      2. 如果存在注入的是 insert、delete、update 这三种类型的语句,那么我们就可以利用现有的语句进行增删改操作,特别是 insert 情况下可以通过将当前用户插入到 SYS.SYSAUTH$ 表中,同样可获得 DBA 权限

      3. 如果存在注入的是 select 这种类型的语句,那么我们就只能对数据库进行查询操作,如 UNION SELECT PASSWORD FROM SYS.USER$,当然前提是它有输出

    • 当遇到 Web 层面的 SQL 注入时,需要构造 dbms_xmlquery.newcontext 执行 PL/SQL 的语句来进行命令执行即可

Last updated