Recover Database Passwords from Weblogic Server

In this post, I am going to explain how to Decrypt or recover the passwords which are encrypted (or hashed) in Weblogic 8.1 especially the database passwords. If you ever forgot the database password which is already configured with Weblogic or the password for the user which is used to start Weblogic, this will be handy. The hashed passwords can be normally found in config.xml and boot.properties inside the application domain. The database passwords will be in config.xml under the JDBC configuration and will look something like below.

$ PasswordEncrypted="{3DES}bDcllidskanDsaIsnaiG=="

To recover the passwords, we need some prerequisites which are listed below.

  1. weblogic.jar & jsafeFIPS.jar from the Weblogic server. (You can find this under WL_HOME/server/lib directory)
  2. SerializedSystemIni.dat from the application domain (You can find this under the application domain root)
  3. The encrypted password from config.xml / boot.properties including {3DES}

SerializedSystemIni.dat has the key to recover the passwords so this is absolutely essential and it should be from the same server since the key depends on the machine. If you are not able to find this file, then probably the server administrator hasn’t given read access to this file to all the users. For Production systems that should be a practice, only the id which will be starting the weblogic server should have read permissions to the SerializedSystemIni.dat file. If not, this will be a security risk, its like leaving the key for your Home on the street. Coming back to the subject, if you got the file then you are all set for the next step.

Assuming you have all the files needed, let’s proceed to the next step. You can copy all the prerequisite files to your workstation or if needed you can run the utility from the server too. As long as the machines have JDK installed it should be fine.

To recover the passwords we will be using a utility from Apache Geronimo 2.0.1 API - Weblogic81Utils.java. Although this file is a part of a package, this can be run as a standalone class with little modification. All you need to do is to remove the package reference and add a main() method to the class. The code for main() method is below.

public static void main(String args[]) {
    try{
        String beaDir = "$Server/lib or the Directory which has the requried JAR files$";
        String appDir = "$App Domain or the Directory which has SerializedSystemIni.dat$";
        String hashedPassword = "{3DES}Vdsds76nGsfdsfKJbg54ss==";
        Weblogic81Utils weblogic81Utils = new Weblogic81Utils(beaDir, appDir);
        String plainTextPassword = weblogic81Utils.decryptString(hashedPassword);
        String configXML = weblogic81Utils.getConfigXML();
        Properties bootProperties = (Properties) weblogic81Utils.getBootProperties();
        System.out.println("-----------------------------------------------------");
        System.out.println("hashedPassword" + " == " + plainTextPassword);
        System.out.println("boot.properties" + " <username> "
            + bootProperties.getProperty("username"));
        System.out.println("boot.properties" + " <password> "
            + bootProperties.getProperty("password"));
        System.out.println("-----------------------------------------------------");
    } catch (Exception e) {
        throw (RuntimeException)new IllegalArgumentException("Unable to initialize"
            + "encryption routines from provided arguments").initCause(e);
    }
}

beaDir - If you are running this on the server, it will be the $WL_HOME/server/lib directory. If you are running elsewhere it will be the path which has weblogic.jar and jsafeFIPS.jar.

appDir - If you are running this on the server, it will be your application domain directory. If you are running elsewhere, it will be the path which contains SerializedSystemIni.dat, config.xml and boot.properties.

hashedPassword – In this example, I am not reading config.xml directly instead I give the encrypted password as a input. So this will be the encrypted database password from your config.xml.

Save the class file and we are all set to run the program. Make sure you removed the package reference since we are running this as a standalone program. No other change is required. Compile the class and run the class. I tested this using JDK 1.6, but any JDK higher than 1.4 should work.

Sample output is given below.

This was tested with Weblogic Server 8.1 and JDK 1.6.

Serial Key Generation and Validation in Java

In this post, I am going to show how to write a very basic serial key generation module for any Java based application - Same algorithms can be used for any programming language. The module consists of three parts.

WARNING: Hash functions used in this article are obsolete and extremely vulnerable to attacks. For real-world implementations, select a more secure hash algorithm.

  1. Algorithm for Serial Generation
  2. Generating the Serial
  3. Validating the Serial
Algorithm for Serial Generation

The following can be used as a simple algorithm for generating serial keys with 18 digits. In this method we are generating the serials based on the input the user gives, which can be the name of the user, company name etc. So most of the times the serial will be unique (based on the input). We get the name of the user as the input and generate the MD2, MD5 & SHA1 hashes for the string and concatenate together. This will generate a total of 104 digits, since we need only 18 of them, we can use a set of pre defined numbers to select the 18 digits.

The below figure explains the algorithm. I have selected some random numbers to pick the 18 digits from 104 character hash, you can use any number you like which makes the serial unique.

Generating the Serial

To generate the serial, we need a input string and based on the input string we will be generating MD2, MD5 and SHA1 hashes. The method calculateSecurityHash takes the input string and the hashing method as input and generates the hash based on the method.

String serialNumberEncoded = calculateSecurityHash(fullNameString,"MD2") +
    calculateSecurityHash(fullNameString,"MD5") +
        calculateSecurityHash(fullNameString,"SHA1");

Generating the Hash for the input string based on the type.

private String calculateSecurityHash(String stringInput, String algorithmName)
    throws java.security.NoSuchAlgorithmException {
        String hexMessageEncode = "";
        byte[] buffer = stringInput.getBytes();
        java.security.MessageDigest messageDigest =
            java.security.MessageDigest.getInstance(algorithmName);
        messageDigest.update(buffer);
        byte[] messageDigestBytes = messageDigest.digest();
        for (int index=0; index < messageDigestBytes.length ; index ++) {
            int countEncode = messageDigestBytes[index] & 0xff;
            if (Integer.toHexString(countEncode).length() == 1)
                hexMessageEncode = hexMessageEncode + "0";
            hexMessageEncode = hexMessageEncode + Integer.toHexString(countEncode);
        }
        return hexMessageEncode;
    }

Once all the three types of hashes are combined, we will have a total of 104 characters. Since we need only 18 for our serial key we can pick any random 18 digits from the combined hash. We cannot use random number generation to pick up the 18 digits since we need a valid exit strategy for validating the key.

String serialNumber = ""
    + serialNumberEncoded.charAt(32)  + serialNumberEncoded.charAt(76)
    + serialNumberEncoded.charAt(100) + serialNumberEncoded.charAt(50) + "-"
    + serialNumberEncoded.charAt(2)   + serialNumberEncoded.charAt(91)
    + serialNumberEncoded.charAt(73)  + serialNumberEncoded.charAt(72)
    + serialNumberEncoded.charAt(98)  + "-"
    + serialNumberEncoded.charAt(47)  + serialNumberEncoded.charAt(65)
    + serialNumberEncoded.charAt(18)  + serialNumberEncoded.charAt(85) + "-"
    + serialNumberEncoded.charAt(27)  + serialNumberEncoded.charAt(53)
    + serialNumberEncoded.charAt(102) + serialNumberEncoded.charAt(15)
    + serialNumberEncoded.charAt(99);

You can replace the numbers with anything between 0 and 103 so that the key is unique and based on the input string.

Validating the Serial

Now, whenever we get a user name and serial combination, we should be able to validate that. Since we already know the algorithm used to generate the serial, the validation part is pretty easier. We cannot follow the steps which we did while generating the serial in opposite direction because we will end up with a bunch of characters without any valid lead. Since we have the serial and user name to validate, we take the user name and generate the serial for the user name as per our algorithm. Once we have the serial number, we compare this against the serial which we got for validation, if both matches then we have a valid key.

String serialNumberEncoded =
    registrationAppSerialGenerationReversal.calculateSecurityHash(fullNameString,"MD2")
    + registrationAppSerialGenerationReversal.calculateSecurityHash(fullNameString,"MD5")
    + registrationAppSerialGenerationReversal.calculateSecurityHash(fullNameString,"SHA1");

String serialNumberCalc = ""
    + serialNumberEncoded.charAt(32)  + serialNumberEncoded.charAt(76)
    + serialNumberEncoded.charAt(100) + serialNumberEncoded.charAt(50) + "-"
    + serialNumberEncoded.charAt(2)   + serialNumberEncoded.charAt(91)
    + serialNumberEncoded.charAt(73)  + serialNumberEncoded.charAt(72)
    + serialNumberEncoded.charAt(98)  + "-" + serialNumberEncoded.charAt(47)
    + serialNumberEncoded.charAt(65)  + serialNumberEncoded.charAt(18)
    + serialNumberEncoded.charAt(85)  + "-" + serialNumberEncoded.charAt(27)
    + serialNumberEncoded.charAt(53)  + serialNumberEncoded.charAt(102)
    + serialNumberEncoded.charAt(15)  + serialNumberEncoded.charAt(99);

if (serialNumber.equals(serialNumberCalc))
    System.out.println("Serial MATCH");
else
    System.out.println("Serial MIS-MATCH");

Sample output from this program is demonstrated below.