ODAT (Oracle Database Attacking Tool) is “an open source penetration testing tool that tests the security of Oracle Databases remotely” (1). The goal of the tool is to help exploit oracle databases by establishing footholds and identifying privilege escalation paths, ultimately resulting in file retrieval, file upload, or code execution on the database server.
This blog post demonstrates a real-world example of a misconfigured Oracle database which allowed White Oak Security to completely take over the database, all through the use of ODAT.
To attack an Oracle database from an unauthenticated perspective, we need to first identify either the “SID” or “Service Name” of the database. A SID is a unique reference (2) to the name of the Database, and a Service Name is an alias for that database. Without either one of these fields, we won’t be able to successfully connect to the database, even if we had credentials. The ODAT tool provides a way to identify these values through a common word list as well as through a traditional bruteforce. Once the SID has been identified, the connection to the Database can continue. ODAT provides a module to enumerate valid SIDs, using the sidguesser module.
Now that we know what the SID for the database is, we can attempt to authenticate to the Database. Access to the database can be obtained through either traditional password spraying attacks or through TNS poisoning (3). To demonstrate a password spraying attack, we will use the passwordguesser module within ODAT to provide a list of accounts with a password to attempt. In our example below, we were able to gain access to several accounts with a poor password of Welcome1.
Low Privilege Enumeration
Once a foothold has been obtained and credentialed access is granted, we will want to enumerate each user account’s permissions within the database as well as check for common CVE’s and escalation vectors. ODAT comes with many built-in modules to identify these capabilities, as well as an all module which will perform all checks against the database.
In the following example, we have gained access to a low-privileged user account, LOWPRIVS, which should only have minimal read/write access to various database tables.
Exploiting Java – Without Privileges
In this example, initial enumeration has revealed several possibilities for exploitation, specifically around Java and Password hashes. My experience with the Java capability has led to quick exploitation in previous engagements, so it’s good to start with potential quick wins for code execution. We can target Java exploitation using the java module within ODAT. Using the –test-module argument, we can re-run the checks for exploitation. ODAT identifies that the Java Library is enabled and even identifies the potential for an arbitrary file upload exploit using CVE-2018-3004.
The Java Library within Oracle provides the ability to interact with the JVM and create arbitrary PL/SQL that can execute custom Java code. As a malicious actor, we want to leverage custom Java code to execute arbitrary system commands on the underlying server. ODAT has this capability automated for us, so we can use the java module once again but this time providing the exec argument to execute an arbitrary binary, in this example the id command.
Unfortunately, we run into an issue where our LOWPRIVS user does not have permission to execute the command as our user account has not been granted permission. The JVM is locked down to only allow privileged users the ability to modify these permissions.
This is a fairly common limitation in my experience as a pentester, where this is not enabled by default. However, if our user account has permissions to modify the Java permission set we can grant our account access to execute the /bin/sh binary. We can use the ODAT search module to execute arbitrary SQL commands by spawning a SQL shell, using the –sql-shell argument.
Unfortunately, we’ve once again run into a permissions error, as our low-privileged user account does not have access to actually update the policy:
After researching the Oracle documentation (4), our user account needs to be a part of the JAVA_ADMIN role in order to modify the Java policy table. In the screenshot below, we attempt to grant our user account access to this role, however, we’re greeted with a message indicating that our user account does not have permissions to perform GRANTs.
Excessive User Permissions & Cracking Passwords
It looks like we got a bit ahead of ourselves here as we’re trying to perform exploitation without understanding our user account’s capabilities. We skipped a step during our enumeration to actually understand what our accounts privileges are. Let’s correct that by using ODAT’s privesc module with the –get-privs argument to enumerate our accounts privileges. Below, we can see that our user does not have any GRANT permissions, which lines up with why our previous attempt was denied. However, we do see an interesting permission in “SELECT ANY TABLE”.
Trying to identify online specifically what this permission means is a bit hit-and-miss. As far as I can tell, SELECT ANY TABLE allows a user to access any table (5), including privileged SYS tables. Several online forums indicated that this permission would allow access to any table, excluding SYS, so I don’t exactly know if this permission is the root cause of the next section, but this is my best guess since the permission exists within the dba privs the user has access to inside the Oracle table role_sys_privs.
If we return to our initial enumeration of exploits in the Database, we saw that hashed passwords can be retrieved. We can reconfirm this by using the passwordstealer module. Password hashes in Oracle 12c are stored in the sys.users$ table.
By using the passwordstealer module with the –get-passwords argument, we can successfully retrieve user account password hashes. In this specific database, we were able to retrieve S, H, and T type passwords. I had the most success with cracking the S type passwords.
However, these are not dumped in the proper format for hashcat as the hash and salt have no delimiters. I was dealing with several thousand password hashes, so I created a quick python script to format my hashes in the correct padding. For future reference, the first 40 bytes is the hash and the rest is the salt. This can be found on Hashcat as mode 112 (6).
Exploiting Java – With Privileges
Hashcat was able to successfully crack a large number of user password hashes, which I used ODAT’s privesc module with –get-privs for each account to identify the user’s permissions. I used the following crude script to authenticate into the database with every cracked user account and retrieved their permissions:
while IFS=: read -r var1 var2; do echo "[+] TESTING USER: $var1" && ODAT privesc -s <IP> -p 1521 -d <SID> -U $var1 -P $var2 --test-module --get-privs; done < cracked-hashes-with-usernames.txt > cracked-usernames-priv-enumeration.txt
Specifically, I was looking for DBA permissions, especially those related to GRANT permission, as that would help us achieve arbitrary code execution with Java. In the example below, the PRIVS user was identified as having the privilege of “GRANT ANY ROLE”, which is exactly what we were looking for, as this user is effectively a DBA.
Now that we have obtained a higher privileged user account, we can add this PRIVS user to the JAVA_ADMIN role. We will use ODAT’s search module again to spawn a sql-shell to execute SQL statements. This time the request executes successfully since we have the appropriate permissions to perform this action.
Next, we need to grant this PRIVS user the ability to execute arbitrary commands by modifying the Java permissions policy table. This request now succeeds since we are part of the JAVA_ADMIN role.
Finally, we can use ODAT’s java module with the exec argument to execute our arbitrary commands. The id command is successfully executed and the results are returned. From here, we can continue standard post-exploitation activities such as stealing or creating new SSH keys for persistence and attempting to privilege escalate to root on the underlying server. ODAT can also spawn a semi-interactive shell and reverse shell.
ODAT Clean Up
Once exploitation activities are completed and some level of persistence is obtained, it’s important to clean up our activities to leave the Database back in its original state. ODAT should clean up the stored procedure from any command execution activities by default (7), so we don’t need to worry much about that procedure remaining within the database if ODAT fails to clean up if we just disable the capabilities to execute it.
First, we need to remove the entry in the Java policy table for our user account to execute arbitrary commands. This can be achieved by identifying the sequence number for the entry; then disable and delete the entry.
Lastly, remove the user from the JAVA_ADMINS role by revoking access.
In this example, ODAT also identified that the database may be vulnerable to an arbitrary file upload vulnerability, CVE-2018-3004. Methods to achieve a shell or session on the host vary by operating system, in Windows you could potentially write to a startup directory and wait for the server to restart, or in Linux if the server has SSH enabled you could append a key to the authorized_keys file to SSH into the server. I could have exploited this vulnerability instead of cracking database passwords if I only had access to the low-privilege user account.
The source code for ODAT describes the module for exploitation as appending to a file if it exists (8), otherwise it will create a new file. With any arbitrary file upload vulnerabilities, I’m quite cautious as the potential to disrupt a live system could occur. Looking at the exploit code for the vulnerability, we can see that the FileWriter class is being instantiated with an optional ‘true’ argument. This argument appends content to a file, which is confirmed in the Javadocs (9).
Still, I want to validate that this actually works as expected so I created a sample file on the server containing “AAAA BBBB” and then exploited the CVE using ODAT’s java module:
This successfully appended the content to the file, and did not overwrite the existing file.
Now that I’ve proved that the append works as described by the original reporters, I generated a new SSH key and added it to the authorized keys for the executing user on the server.
Finally, I successfully authenticated into the server as the oracle user.
Looking at the source code for this vulnerability and the original proof of concept (10), I did make several attempts to modify the class executed to Runtime or ProcessBuilder, without any luck. My assumption is that only certain classes can be executed, which is why the author of this CVE opted for executing files rather than executing code. There still may be room for interesting reflection or gadget chains that can be encoded using the XMLEncoder, resulting in arbitrary command execution.
More From White Oak Security
White Oak Security is a highly skilled and knowledgeable cyber security and penetration testing company that works hard to get into the minds of opponents to help protect those we serve from malicious threats through expertise, integrity, and passion.
- https://github.com/quentinhardy/ODAT – ODAT GitHub
- https://docs.oracle.com/en/database/oracle/oracle-database/19/ntqrf/oracle-sid.html – Oracle SID
- https://book.hacktricks.xyz/network-services-pentesting/1521-1522-1529-pentesting-oracle-listener/tns-poison – TNS Poisoning
- https://docs.oracle.com/cd/E18283_01/java.112/e10588/chten.htm – Java_admin permissions
- https://docs.oracle.com/database/121/TTSQL/privileges.htm#TTSQL338 – Database permissions
- https://hashcat.net/wiki/doku.php?id=example_hashes – Hashcat Oracle hash type
- https://github.com/quentinhardy/odat/blob/master-python3/Java.py#L123 – Cleaning up stored procedures
- https://github.com/quentinhardy/odat/blob/master-python3/Java.py#L271 – Append file reference
- https://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html#FileWriter(java.io.File,%20boolean) – FileWriter reference
- http://obtruse.syfrtext.com/2018/07/oracle-privilege-escalation-via.html – CVE reference