Friday, June 27, 2014

WebLogic's SerializedSystemIni.dat

I once encountered a peculiar problem with WebLogic's SerializedSystemIni.dat file. Upon restarting a WebLogic admin or managed server, we would encounter an exception like:
<1/06/2009 02:23:35 PM EST> <Warning> <Security> <BEA-090066> <Problem handling boot identity. The following exception was generated: weblogic.security.internal.SerializedSystemIniException: [Security:090208]Corrupt SerializedSystemIni.dat>
<1/06/2009 02:23:35 PM EST> <Info> <Security> <BEA-090065> <Getting boot identity from user.>
Enter username to boot WebLogic server:

We quickly noticed that the SerializedSystemIni.dat file was 0 bytes in size, the problem occurred again sometime later in a restricted test environment. This time we knew it was a WebLogic quirk of some sort.

SerializedSystemIni.dat Explained: If you've ever looked through config.xml, you may have noticed password values that look like "{3DES}bOH6MEd8S82sxg2Nk=". This is how WebLogic stores passwords encrypted with the "Triple DES" algorithm(3DES).

When WebLogic stores or retrieves one of these passwords, it uses a hash key which is stored in the SerializedSystemIni.dat file.  That's right, the key to all your encrypted admin and DB passwords is right there on your file system. Read access is all that is needed to compromise a WebLogic domain. Perhaps worse, you could be making DB passwords available.

If you're wondering where this file is located, its in the domain directory for WebLogic 8 (or earlier) and in the 'security' directory for WebLogic 9 or later.

Solving the 0-Byte SerializedSystemIni.dat Problem: It wasn't until I understood the purpose of this file that I was able to solve the 0-byte problem. Some time after we noticed SerializedSystemIni.dat was being corrupted, we realized the problem was occurring after the server had run out of disk space.

After a lot of googling and well-intended but limited help from BEA, we discovered that SerializedSystemIni.dat is periodically re-written by the WebLogic Admin server. If the server is unable to write the contents of the file (disk is full, etc), WebLogic will lose the hash key and will no longer be able to decrypt any passwords. I.e. if you're the admin, you'd better have backups or personal indemnity insurance.

So if you are wondering why your WebLogic servers won't start, and SerializedSystemIni.dat is 0 bytes in size, you now know why. The solution? Don't let your server's disk fill up.

I explained that the SerializedSystemIni.dat file in WebLogic contains the key used to encrypt and decrypt passwords. If you're not currently keeping this file secure I suggest you do, as with it someone can (to name a few things):

  • Decrypt the WebLogic admin username and password from boot.properties.
  • Recover database passwords, if JDBC Connection pools are configured, from config.xml.
  • Recover the keystore passwords from config.xml and obtain SSL certificates stored in the jks keystores.
Essentially, they can do whatever they want, so if you don't know who can read your SerializedSystemIni.dat files, look... now.
In this article I will show how easy it is for this file to be used to recover lost passwords via a simple WLST script.
The Script
The script I use to decrypt passwords is incredibly short, and it works with WebLogic 8, 9 and 10 (probably for version 7 too). To use it, just create a new file called decryptpwd.py and paste the following code into it:
 = = = = = = = = = = = = = = = = =

from weblogic.security.internal import *
from weblogic.security.internal.encryption import *

# Remind user about how to use
raw_input("Please ensure SerializedSystemIni.dat is in the current directory now, and press ENTER to continue.")

# Get encryption service
encryptionService = SerializedSystemIni.getEncryptionService(".")
clearOrEncryptService = ClearOrEncryptedService(encryptionService)

# Get user to enter password
pwd = raw_input("Enter encrypted password (Eg. {3DES}Y1fA34S...): ")

# Remove unnecessary escape characters
preppwd = pwd.replace("\\", "")

# Decrypt the password
print "Recovered password is: " + clearOrEncryptService.decrypt(preppwd)
= = = = = = = = = = = = = = = = 
Running the Script:
To run this script, execute the WLST environment and provide it with the script to run. If you're using a version of WebLogic older than 8.1.6 you'll need to install a newer version which has WLST.
Use the following command (replace %WL_HOME% with the correct directory) to run the script.
%WL_HOME%\common\bin\wlst.cmd decryptpwd.py

Once the WLST environment has started up, the script will remind you to copy the SerializedSystemIni.dat file into the current directory. Press enter and paste your encrypted password string. That's it. It will spit out the password in plain-text.
Understanding the Script:
The script is so short and simple it is barely worth explaining, but here are a few things worth mentioning.
You'll notice that the first two lines import weblogic.security packages. These are largely undocumented, so don't expect to find much information on them.
The next significant piece of code instantiates a ClearOrEncryptedService object which will use the SerializedSystemIni.dat file located in the current directory (".").
The final line of code decrypts the password and prints it in plain text.
= = = = = = = = = = = = = = = =

How to decrypt WebLogic passwords with WLST

Sooner or later you will find the situation where you do not remember any of the WebLogic Server password’s stored in the configuration files.

Some examples are:
  1. The WebLogic Server administrator credentials (username and password) stored in the files config.xml and boot.properties
  2. Node Manager password, stored also in the config.xml file (if you still have the default password, don’t wait and change it know!!)
  3. Database password used by the JDBC Data Sources and stored in the file [DOMAIN_HOME]/config/jdbc/[datasource_name].xml
So, how to decrypt this data in 3 easy steps. Just follow this techtapa recipe:
Ingredients:
- 1 WLST script
- The path of the WebLogic Server domain
- The encrypted field, for example, username and password from boot.properties
import os
import weblogic.security.internal.SerializedSystemIni
import weblogic.security.internal.encryption.ClearOrEncryptedService

def decrypt(domainHomeName, encryptedPwd):
    domainHomeAbsolutePath = os.path.abspath(domainHomeName)
    encryptionService = weblogic.security.internal.SerializedSystemIni.getEncryptionService(domainHomeAbsolutePath)
    ces = weblogic.security.internal.encryption.ClearOrEncryptedService(encryptionService)
    clear = ces.decrypt(encryptedPwd)
    print "RESULT:" + clear

try:
    if len(sys.argv) == 3:
        decrypt(sys.argv[1], sys.argv[2])
    else:
  print "INVALID ARGUMENTS"
  print " Usage: java weblogic.WLST decryptPassword.py DOMAIN_HOME ENCRYPTED_PASSWORD"
  print " Example:"
  print " java weblogic.WLST decryptPassword.py D:/Oracle/Middleware/user_projects/domains/base_domain {AES}819R5h3JUS9fAcPmF58p9Wb3syTJxFl0t8NInD/ykkE="
except:
    print "Unexpected error: ", sys.exc_info()[0]
    dumpStack()
    raise

2. Set your environment (CLASSPATH, PATH,..). Open a console, go to [FMW_HOME]/wlserver_10.3/server/bin/ and run the script setWLSEnv.sh:
$ . ./setWLSEnv.sh

3.Run the script. Go to the path where you copied the WLST script ( decryptPassword.py) and run it. You must provide two arguments, the WebLogic Server domain Home full path and the string you want to decrypt, for example:
$ java weblogic.WLST decryptPassword.py /opt/oracle/Middleware/user_projects/domains/base_domain {AES}LU5dLPP0PliNb5Ml1Fo7rD2AbNFwLcyLtYUEDTb+8zY\=



No comments:

Post a Comment