案例:ora-00600[16703]比特币攻击

近期大量的客户数据库软件被注入恶意代码,导致数据库无法启动,报错ORA-00600: internal error code, arguments: [16703], [1403], [20],大致的原因和预防措施可参考下面文章:http://www.eygle.com/archives/2018/07/recover_ora-600_16703.html

大致的意思是由于恶意攻击,$ORACLE_HOME/rdbms/admin/prvtsupp.plb被注入恶意代码。这些恶意代码会被注入到使用这个oracle软件dbca创建的数据库中,核心部分为一个触发器一个存储过程,清空了tab$,导致数据库启动时,bootstrap阶段无法完成。

触发器如下:

触发器用于启动数据库后调用DBMS_SUPPORT_DBMONITORP这个存储过程,存储过程代码如下:

该存储过程逻辑为:判断数据库的创建时间是否大于 300 天,如果大于300天则ctas备份tab$之后,delete tab$。

如果有备份的话,那么很简单就不展开了,本文主要介绍没备份的方法。
首先手工构造场景:
模拟DBMS_SUPPORT_DBMONITORP里的内容

此时启动数据库报错ORA-00600: internal error code, arguments: [16703], [1403], [20]

恢复思路:

由于有且仅有tab$被delete,所以如果能恢复tab$的数据则数据库将得以恢复,这里我想到的大致恢复方法如下(欢迎大家提供更多的恢复思路):

  • 写成脚本逐一还原被delete的行,目前我的同事编写了python和shell两个版本,经过实战验证都可以完美恢复。
  • 由于恶意代码中,delete tab$前,ctas了一份tab$的备份,可以尝试先open数据库,再根据备份的tab$ insert到tab$中。
  • odu抽取数据,重建库

本文只模拟第二种方法,恢复步骤大致如下:

  • open数据库
  • 根据备份的tab$ insert到tab$中

在恢复之前首先简单介绍一下tab$,tab$是cluster C_OBJ#中的一个table,CLUSTER KEY为OBJ#,C_OBJ#中还包括有ICOL$、IND$、COL$、CLU$、I_OBJ#、COLTYPE$等等bootstrap核心对象,tab$在数据库中是非常核心的一个基表,它记录了table的段头地址以及统计信息。在数据库open过程中,需要访问到的基表对象如果在tab$中不存在,则数据库将无法open,报错即为ORA-00600: internal error code, arguments: [16703], [1403], [xxx]。

灵魂拷问1:那如何open数据库呢?

在数据库open过程中,需要访问到的基表对象如果在tab$中不存在将报错ORA-00600: internal error code, arguments: [16703], [1403], [xxx],那么将这些对象的信息还原回tab$,则数据库将open成功。

灵魂拷问2:如何确定数据库open需要访问哪些核心基表呢?

找一个正常的数据库做open时的10046,过程如下:

简单的对10046 trace文件进行筛选则可以找到这些基表的obj#,并在一台同平台同版本的数据库上查询这些对象的rdba地址以及其他信息

这些对象在同版本同平台的数据库上的rdba地址一般都是一致的,所以找一台正常运行的同版本同平台的数据库(最好是比较干净的库,否则后续处理会比较麻烦),使用bbed进行替换,用sql拼接出bbed的命令

可以看到这里需要替换38个数据块,替换后可以成功open数据库,注意如果是实战环境open数据库之前需要禁用系统触发器。

灵魂拷问3:如何将备份的tab$ insert回tab$?

由于tab$的备份表在tab$中并没有恢复所以无法查询,下面需要根据redodump去确定tab$的备份表t_bak的rdba

可以看到t_bak在tab$的rdba地址为0x00407b2c(file 1 block 31532),cki为0即cluster key为kdbr[0]

与redo dump一致,下面开始恢复tab$中t_bak的记录,由于是cluster block所以过程有点繁琐

t_bak已经恢复完成,下面insert回tab$

至此数据库基本恢复完成。

但是通过hcheck脚本检查数据字典一致性发现还是有一些问题存在:

发现了11处问题,都是HCKE-0002: Object type column with missing OID$。 这是什么意思呢?
分析hcheck脚本的MissingOIDOnObjCol存储过程:

仔细对脚本进行分析,推测是当表的字段类型为type类型的对象时,coltype$的toid和oid$的oid$不匹配导致的,应该是之前为了open数据库替换块的时候造成的。
以OBJ#=12946 Name=SYS.AQ$SCHEDULER$_EVENT_QTAB IntCol#=20=USER_DATA为例继续分析:
由于数据字典不一致,该表是不可以正常访问:

对正常的数据库查询可以看的SYS.AQ$SCHEDULER$_EVENT_QTAB的字段名为USER_DATA的字段类型为SCHEDULER$_EVENT_INFO,通过下面的查询可以发现确实不匹配(以oid$的为准,因为之前替换的是C_OBJ#,而coltype$是C_OBJ#中的一个表):

修改coltype$后恢复正常:

逐一修改后,再次执行hcheck:

至此整个数据库比较完整的恢复完毕。

此条目发表在Oracle, Oracle Recover分类目录,贴了, 标签。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注