Protecting Oracle Database Binaries against malicious changes

This post is also available in: Português

Introduction

In the live sessions where I talk about Oracle Database security and vulnerabilities, I do always mention rootkits or malwares that can attack a database from either inside (via SQL injection, PL/SQL poisoning, Java leaks, etc) or externally (by changing oracle user files, such as binaries / libs / crontab / etc).

To explore these two forms of attacks, a hacker often uses what I call the ladder of joy:

Usually an attacker starts the privilege escalation attack from a low-level user, maybe with only the CREATE SESSION permission, and attempts many "ladder-climbing" techniques such as SQL Injection, Java Vulnerabilities, Buffer Overflow, etc. Once as SYSDBA or DBA, it is trivial to reach the oracle account in OS, responsible for the DB binaries.

The purpose of this article is to present how to protect the Oracle Home user files against improper changes and thus prevent the deployment of rootkits or malwares.

P.S: Note that some steps of this article are not documented nor supported by oracle. Needless to say to try this at your own risk.

Getting Started

In Oracle 18c was introduced a new feature called Read-Only Oracle Home (or ROOH) and over this new feature that we will implement this security functionality. For pre-18c databases, there is also a section in this tutorial.

Among the objectives of the ROOH, we have:

• Remove mutable files from Oracle Home.
• Consolidate these files into a separate folder.
• Facilitate the migration / environments cloning.
• Facilitate use of Docker / Oracle Homes sharing via NFS / etc.

However, ROOH only ensures that no process will create or change files in ORACLE_HOME, but it doesn't make it impossible for the oracle user to do any kind of change in his own files. Once as owner, he is obviously able to change them. Therefore, these files are not yet protected against malicious changes.

What we will do, once activated ROOH and ensured that the oracle user does not need to modify any file within Oracle Home root anymore (except in cases of patching), is to protect the binaries with the following steps:

  1. Save the current owners and privileges of all ORACLE_HOME files.
  2. Change the current owner of all ORACLE_HOME files to root.

The purpose of Step 1 is to have a way to return to the original owner and privileges in case you need to apply a patch or do any other type of ORACLE_HOME change.

The goal of Step 2 is to effectively protect ORACLE_HOME from unwanted changes, since the oracle user will no longer own the files (similar to what happens today with GRID_HOME, whose owner is root and not the grid).

Before you begin

Make sure that:

  • ROOH is active for your ORACLE_HOME (see this doc to know how).
  • No process is running as the ORACLE_HOME owner (usually oracle).

1. Saving permissions and current owners

The first step is to backup the privileges and permissions.

This can be done running the command below as oracle:

$ ORACLE_HOME=/u01/app/oracle/product/18.0.0/dbhome_1
$ cd $ORACLE_HOME
$ find -depth -printf '%m:%u:%g:%p\0' |
awk -v RS='\0' -F: '
BEGIN {
    print "#!/bin/sh";
    print "set -e";
    q = "\047";
}
{
    gsub(q, q q "\\" q);
    f = $0;
    sub(/^[^:]*:[^:]*:[^:]*:/, "", f);
    print "chown --", q $2 ":" $3 q, q f q;
    print "chmod", $1, q f q;
}' > original-permissions.sh

The find and awk commands above will generate the original-permissions.sh file inside the ORACLE_HOME. This shellscript has the current chown and chmod commands for all existing files.

$ head original-permissions.sh
#!/bin/sh
set -e
chown -- 'oracle:oinstall' './bin/lxegen'
chmod 755 './bin/lxegen'
chown -- 'oracle:oinstall' './bin/sqlldr'
chmod 751 './bin/sqlldr'
chown -- 'oracle:oinstall' './bin/lsnrctl'
chmod 751 './bin/lsnrctl'
chown -- 'oracle:oinstall' './bin/ore_srcexport.pl'
chmod 644 './bin/ore_srcexport.pl'

2. Change the current owner for all ORACLE_HOME files to root

Before changing the current owner of the files to root, you need to check a few things, since oracle read (r) and execute (x) privileges will now be granted through the file group (usually oinstall):

  1. If the owner of the file had execution privilege (x), then the file group needs to be able to execute.
  2. If the owner of the file had reading privilege (r), the file group needs to be able to be able to read.
  3. Group and others must not have write privileges (w).

This can be done through the commands below. Run as root :

# ORACLE_HOME=/u01/app/oracle/product/18.0.0/dbhome_1
# cd $ORACLE_HOME
# pwd
/u01/app/oracle/product/18.0.0/dbhome_1
# find ./ -perm -u+x ! -perm -g+x -exec chmod g=u-w {} +
# find ./ -perm -u+r ! -perm -g+r -exec chmod g=u-w {} +
# find ./ -perm -g+w ! -type l -exec chmod g-w {} +
# find ./ -perm -o+w ! -type l -exec chmod o-w {} +
# chown -R root ./*

Nice! You can now start your instance with assurance that an attack will not be able to affect the DB binaries.

PS: Keep in mind that there is no use for this type of protection if oracle user is able to execute su or sudo as root.

Rollback

Always before applying a patch or if you want to undo the owner and permissions changes, execute the original-permissions.sh file (generated in step 1) as root:

# ORACLE_HOME=/u01/app/oracle/product/18.0.0/dbhome_1
# cd $ORACLE_HOME
# sh original-permissions.sh

NOTE: Remember to re-run Step 1 after running changes to Oracle Home to ensure that permissions and owners for new files are included in a new shellscript.

Is my Oracle Home really protected now?

As oracle user, I can now check if oracle database home folder is really secured. How?

Let me try to remove all the files from ORACLE_HOME recursively as oracle.

DON'T EVER TRY THIS IN YOUR SERVER.

$ cd $ORACLE_HOME
$ pwd
/u01/app/oracle/product/18.0.0/dbhome_1
$ find ./ | wc -l
42098
$ rm -rf ./* ./.* 2>&-
$ find ./ | wc -l
42098

As you can see from the output above, oracle user is not able to remove anything.

Pre-18c Databases

In environments running DB 12c or earlier, this type of protection approach would also work with some limitations. However, to avoid problems it is necessary to map ALL the files that are changeable within ORACLE_HOME (something non-existent in 18c with ROOH) and keep them with the original oracle user permissions.

As it's impossible to control the directories where a pre-18c DB version generates files, to avoid any impacts I recommend an "inclusive approach", protecting only the files in the following folders:

  • ./bin/
  • ./ctx/lib/
  • ./hs/lib/
  • ./javavm/admin/
  • ./ldap/lib/
  • ./lib/
  • ./network/lib/
  • ./odbc/lib/
  • ./owb/wf/lib/
  • ./plsql/lib/
  • ./precomp/lib/
  • ./racg/lib/
  • ./rdbms/admin/
  • ./rdbms/lib/
  • ./sqlplus/lib/
  • ./srvm/lib/
  • ./sysman/lib/
  • ./xdk/lib/

This can be done through the commands below as root (remember to save the current owner and permissions before, as described in step 1):

# ORACLE_HOME=/u01/app/oracle/product/12.1.0/dbhome_1
# cd $ORACLE_HOME
# pwd
/u01/app/oracle/product/12.1.0/dbhome_1
# cat protected_folders.txt
./bin/
./ctx/lib/
./hs/lib/
./javavm/admin/
./ldap/lib/
./lib/
./network/lib/
./odbc/lib/
./owb/wf/lib/
./plsql/lib/
./precomp/lib/
./racg/lib/
./rdbms/admin/
./rdbms/lib/
./sqlplus/lib/
./srvm/lib/
./sysman/lib/
./xdk/lib/
# find $(cat protected_folders.txt) -perm -u+x ! -perm -g+x -exec chmod g=u-w {} +
# find $(cat protected_folders.txt) -perm -u+r ! -perm -g+r -exec chmod g=u-w {} +
# find $(cat protected_folders.txt) -perm -g+w ! -type l -exec chmod g-w {} +
# find $(cat protected_folders.txt) -perm -o+w ! -type l -exec chmod o-w {} +
# chown -R root $(cat protected_folders.txt)

NOTE: You may also include or exclude folders from this list at your own risk, to shrink or extend protection.

Conclusion

Privileges Escalation (DBA user on DB -> oracle user on OS), although not presented here because it is outside the scope of this article, is something really trivial and the main end goal of the invaders. Therefore, making it harder to deploy any kind of malicious code in binaries is a real concern that must be raised in all types of environments, especially in Production.

Have you enjoyed? Please leave a comment or give a 👍!

2 comments

    • Josh on February 7, 2019 at 19:00
    • Reply

    Although the post title is not misleading (it mentions the database binaries on OS level) I got fooled hard by the "ladder of joy".
    Could you explain how the heck a single database user can escalate to OS root?
    Yeah, I know some technics to become DBA through exploiting unusual high privileges permissions (CREATE ANY INDEX and creating functional indexes in the SYS schema), but I'm still failing to see how a database user can gain OS root access.
    Care to explain?

  1. Hi Josh, sorry for not developing that further as this was not the intention of this article.
    With DBA you can use external jobs, external table preprocessor, java, etc to run things in OS as oracle. So it's easy to get connect to OS as oracle from that point.
    The last step of the ladder (oracle -> root) you would require to explore some OS vulnerability, which is not hard to find depending on the version of your OS and latest applied OS patches. Maybe oracle has sudo access also, which would make it much easier.
    Regards,
    RJ

Leave a Reply

Your email address will not be published.