Wednesday, May 27, 2009

Analysis of Oracle Hyperion Web Analysis Studio 9.3 Logon Security

Before I start I'll point out that Oracle does not make any claims that the Hyperion Logins are secure without SSL. This analysis was performed to clear up misconceptions on the part of others.

Analysis of Oracle Hyperion Web Analysis Studio 9.3 Logon Security
A quick vetting of how Hyperion handles usernames and passwords shows that their controls offer little protection of credentials while crossing the network, in the absence of SSL. While passwords are not sent across the network as clear text, they are only lightly obfuscated and subject to multiple attacks.
Hyperion should not be used unless the login pages are encrypted using SSL derived from a certificate that chains to a trusted Root Certificate Authority. This is most important when using the LDAP connector as it then puts credentials at risk that might grant access to other systems.

There are multiple ways to take a look at Hyperion yielding varying results. Hyperion sends data via Java code to the app server via an unknown application protocol. It uses Java serialized objects, which may be meaningful to some else. At the TCP level, the usernames can be seen on the wire in clear text, along with what appears to be a base64 encoded password.
A message snippet looks like this:
Content-Disposition: form-data; name="param type 1"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit

Content-Disposition: form-data; name="param type 2"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit

Content-Disposition: form-data; name="param value 0"
Content-Type: application/x-java-serialized-object
Content-Transfer-Encoding: binary


The first thing we see is that the protocol breaks up messages with Pi. Who knows… The second thing we see is that the helpful words, Password and UserName can be found. These are followed by DmFVYnsCImM=, presumably my password and then markgamache, my username. By simply trying a few attempts with different usernames and passwords, it becomes clear that we are correct in our assumptions. Third, but for later, we also get a java class name,

Replay Attacks
Before we look at any technical attacks, we’ll look at that messaging format. The TCP data sent along with the username and password contain no sequence numbers, nonces, or timestamps. As you will see in the next section, a username and encrypted password for an account do not change across login sessions. This makes it highly likely that a simple replay would allow access to a session as another user. This does not put the password at risk, only data within the application. If the application data is not encrypted, it is likely that the session could be hijacked as well. This is a smaller concern generally.
The next step is to try and make sense of the password data. The system lets us send as many usernames and passwords as we like.

Chosen Plaintexts
By sending data we select through the password encryptor, we can then analyze the results.

Username: markgamache
Username Hex: 6d 61 72 6b 67 61 6d 61 63 68 65

Password : 1q2w3e4r
Plaintext hex: 31 71 32 77 33 65 34 72
Cyphertext Hex: 0e 61 55 62 7b 02 22 63

Password: 11111111
Plaintext hex : 31 31 31 31 31 31 31 31
Cyphertext Hex : 0e 21 56 24 79 56 27 20

Password: 111111111
Plaintext hex : 31 31 31 31 31 31 31 31 31
Cyphertext Hex 0e 21 56 24 79 56 27 20 e9

Password: 22222222
Password hex: 32 32 32 32 32 32 32 32
Cyphertext Hex : 0d 22 55 27 7a 55 24 23

Password: 33333333
Password hex : 33 33 33 33 33 33 33 33
Cyphertext Hex : 0c 23 54 26 7b 54 25 22

Password: 44444444
Password hex : 34 34 34 34 34 34 34 34
Cyphertext Hex : 0b 24 53 21 7c 53 22 25

Password: 55555555
Password hex : 35 35 35 35 35 35 35 35
Cyphertext Hex : 0a 25 52 20 7d 52 23 24

Password: 12345678
Password hex : 31 32 33 34 35 36 37 38
Cyphertext Hex : 0e 22 54 21 7d 51 21 29

Username: ted
Username Hex: 74 65 64

Password: 11111111
Password hex : 31 31 31 31 31 31 31 31
Cyphertext Hex : ab 28 71 f4 fe cb 1d 46

Username: 1111
Password hex : 31 31 31 31 31 31 31 31
Cyphertext Hex : 51 2b f3 5c a6 76 db 43

Username : 2111
Password hex : 31 31 31 31 31 31 31 31
Cyphertext Hex : af a8 8d c5 48 db 27 7c

From the small sample, we can see a few things:
• If the username is unchanged, then the password data seems to be consistent
o For markgamache, as long as the password starts with 1, the cyphertext starts with 0e
o The transform is not s simple substitution, as the 0e only corresponds to 1 as the first character
o Incrementing the value of a character in a particular position produces predictable results. In pos 1, 0e = 1, 0d = 2, 0c = 3
o The pattern is not completely predictable. In Pos 4, 24 = 1, 27 = 2, 26 = 3
o The value of a position is not varied by the character before or after. The encrypted value of Pos 3, when the plaintext is 2, is 55, both when the password is 1q2w3e4r and 2222222
• If the username changes, the cyphertext value no longer match for a position, with the password unchanged. See users 1111 and 1112 above.
• The values at a position do not vary based on the overall password lenghth. See password 11111111 vs 111111111

This tells us that the encrypted version of the password is derived in part from the username. It also shows us that for any username, we can perform a simple position by position chosen plaintext attack to find the corresponding encrypted values. This means in about 100 attempts, a user’s password can be derived. As the application allows unlimited retries, this cannot be stopped. The account would likely be locked out due to password policy, but in 10 – 30 minutes, it is likely to be unlocked by policy.

Code Attacks
As the password is “encrypted” using the client side Java code, we can take a look at that code. While the app runs automatically when you click on a web link, there is nothing stopping us from getting the code to look at. Remember, we can’t execute the code if we can’t get to it.
A simple curl command allows us to get a copy of the jar file, AnalyzerClient.jar. From there, it is a simple task to extract the jar and decompile the classes. There are lots of them, but we are saved time by the data from the wire, remember
Sure enough, there is a class named The class has both encrypt and decrypt methods referencing com.hyperion.atf.utils.encryption.EncryptionManager.
Upon investigation of EncryptionManager, we see that the username is used as the key and RC4 is used to encrypt the password. This is bad, but is validated by the chosen plaintext operations.
Following the bouncing ball and stripping the error handling for prettiness…
1. We get csPassword and a value from the wire.
2. We get csPassword = EncryptionManager.encrypt(asUserName, asPassword); from SimplePasswordToken
3. From EncryptionManager we get
public static String encrypt(String asEncryptionKey, String asClearText)
return encryptRC4(asEncryptionKey, asClearText);

protected static String encryptRC4(String asEncryptionKey, String asClearText)
byte myCypher[];
Rc4Cipher mRc4 = new Rc4Cipher(asEncryptionKey.getBytes("UTF8"));
byte myClear[] = asClearText.getBytes("UTF8");
myCypher = new byte[myClear.length];
mRc4.encrypt(myClear, myCypher);
return Base64Codec.encode(myCypher);

Indeed, the encryption key is the username, which is sent in the same packet as the encrypted password. The key is shipped in the lock.
All of our assumptions are confirmed.
Lastly, even thought the client should never need to decrypt the password, that’s the server’s job, the decrypt code is in the classes. This makes creating your own exploit code extra easy.

Character Positions Explained
Now that we know that RC4 is being used with the username as the key, we can see why there is a predictable shift in the cyphertext at any position if the username does not change. If you recall, for username markgamache, a 1 as the first character always yields 0e as the first byte of cyphertext. This is because RC4 is a stream cipher. It acts on a byte stream, one byte at a time. One byte in the stream had no mathematical effect on the previous or next byte. This is why block ciphers are considered better, as a rule of thumb. As our passwords are made up of characters that are, unluckily, one byte each, each character is essentially encrypted by its self. To defeat this, some sort of bit shift or IV (initialization Vector) should be used. It’s all moot though, as the key is shipped with the lock, as it were.

Hyperion passwords, and any linked SSO directory passwords, are put at considerable risk by simple code inspection or by chosen plain text attacks. While it has not been tested, a session with the application can probably be established via a TCP replay. Without additional controls, it is likely that sessions can also be hijacked. While the last two issues do not put passwords at risk, they do put the application and its data at risk.
Hyperion should not be used without SSL via a certificate that chains to a trusted root certificate authority. This will provide for secure key exchange, secure authentication, stop replay attacks and make the world a better place.

This just reinforces the basic security principal; Trust well vetted cryptosystems (like SSL) over custom solutions.

No comments:

Inputting falsified referrals to this site violates the terms of service of this site and is considered unauthorized access (hacking).