Starting on version 11.70, Informix allows DBSA to create internal users and to manage their authentication locally, and not with the OS. This feature is called USERMAPPING. We will try to understand how Informix does to store the passwords for that users. For some reason, until now, nobody took some time to analyze this.
On the other hand, we will use JBrute as a support tool to help us in the cryptoanalysis, and this is a new different (and interesting) use for it.
The mapped users can be found in the table sysintauthusers, inside the SYSUSER database. This table has several columns, but we are interested in only 4: username, salt, hashed_password and hash_type.
The IBM documentation says this about the content of the sysintauthusers table:
username: Name for the user.
salt: 64-bit salt that the server uses to morph the password before applying the hashing algorithm. The server can use salt to change a password so that two users with the same password do not have the same hashed password in the database. Salt improves security because it prevents password guessing.
hashed_password: A sha-256 hashed and base-64 encoded password.
hash_type: Type of hashing algorithm used. Currently the SHA-256 algorithm is used.
Ok, so, it seems that we will have to deal with a salted sha-256 hash (not really complicated), with a particularity: it is base64 encoded.
Before starting the cryptoanalysis, we must to collect some information. We know some things by the documentation, but we must get some hashes to do the job. So, we need an Informix's installation to create some users. This is not an important section, so I will just put the command to create one:
create user batman with password "batman" properties UID 501 group(501) home "/home/userinf";
create user robin with password "robin" properties UID 501 group(501) home "/home/userinf";
Please ignore the properties section, it is irrelevant at this point. Ok, we have our testing users "batman" and "robin". We just need to get the hashed password and the generated salt for both. For this, I execute this sql query over the "SYSUSER" database:
select username,salt,hashed_password,hash_type from sysintauthusers;
username batman
salt 3561468224442120539
hashed_password MUz_GO.idl2RwWkB3ChUIhecxmzLDWMwm2hcSl37YHMEß
hash_type SHA-256username robin
salt 3478653688976053352
hashed_password r4gUfQaWC3nciILif0gG06DUfJtbx66AmOCsAoKuPIME§
hash_type SHA-256
And that is all the information that we need. An important thing: note that if could have only the "robin" user hash, we will not be able to note that there are some strange thing with the base64 encode, as we can see on the "batman" hash. For this reason, it is important to generate several hashes to get different scenarios.
I will put some points clear:
What we know:
_ It is a sha-256 hash
_ It is salted
_ It is not the rfc3548 implementation of base64 encoding
What we don't know:
_ What kind of salt is in use? pre-salt or post-salt?
_ How is the base64 Informix's proprietary implementation?
First, I really suggest you taking a look to the rfc3548 if you are not acquainted about base64. You can read the definition here:
http://www.faqs.org/rfcs/rfc3548.html
I have to say that the pad character of the base64 encoded used by Informix is really strange: we should have only 1 padding character, but we've got more: "Eß".
I suspect that it is a language conversion issue, we will see...
Ok, we have all points clear at this moment. So, we start discovering if the salt is pre or post salt. We need to generate hashes for both scenarios. I developed 2 new optional parameters in JBrute for the "--encrypt" main parameter to do this job: "--salt_type" and "--base64". This parameters will be included in the next version of JBrute (0.97). At this moment, you can check out the source and use it, actually the DEV version is the 0.97 DEV-2. It's better to choose the hash of batman user, because it has 2 strange characters that are not part of the rfc3548 base64 encode.
After the checkout, now we can use JBrute to try the encryption :)
[root@localhost ~]# ./jbrute.sh --encrypt --presalt=3561468224442120539 --salt_type=int64 --word=batman --base64 --algorithm=5
Word to hash: batman
Pre-salt used: 3561468224442120539
Salt type: int64
Hash SHA-256() : 314cff18efa2765d91c16901dc285422179cc66ccb0d63309b685c4a5dfb6073
Base64 SHA-256() : MUz/GO+idl2RwWkB3ChUIhecxmzLDWMwm2hcSl37YHM=[root@localhost ~]# ./jbrute.sh --encrypt --postsalt=3561468224442120539 --salt_type=int64 --word=batman --base64 --algorithm=5
Word to hash: batman
Post-salt used: 3561468224442120539
Salt type: int64
Hash SHA-256() : 804ee5d2ef79403ef38553c7cbc67bee114e7a35169dff7421598b0b86a90da8
Base64 SHA-256() : gE7l0u95QD7zhVPHy8Z77hFOejUWnf90IVmLC4apDag=[root@localhost ~]#
BINGO!!! We are very luck! As we can see, the presalt hash is really similar to the Informix's hash, we are very close!
We should compare the two hashes:
Informix's one: MUz_GO.idl2RwWkB3ChUIhecxmzLDWMwm2hcSl37YHMEß
JBrute's one : MUz/GO+idl2RwWkB3ChUIhecxmzLDWMwm2hcSl37YHM=
The only difference that we can find on this hashes are the characters "/" and "+" of rfc3548 base64. As we said before, there is a strange thing about the pad character, that should be just one. If we take the first 43 character of the Informix's hash, and if we replace then the "_" character with the "/" character, and the "." character with the "+" character, and if we add to the result the pad character "=", then we have a base64 encoded sha-256 hash, as JBrute shows. I have to confess something: I thought that the base64 encode would be more difficult to discover...
Thats all, the algorithm is not complex. In fact, it is easy to understand and to implement.
One more thing: the password length can't be less than 6 or grater than 32. (I discover that altering the password of some users).
Finally, after a couple of hours, I added support for the Informix's algorithm in JBrute, it will be abailable on the next version of JBrute (0.97). So, we can check the final result:
[root@localhost ~]# ./jbrute.sh --decrypt --algorithm=L --hash=3561468224442120539/MUz_GO.idl2RwWkB3ChUIhecxmzLDWMwm2hcSl37YHM=
Algorithm: INFORMIX-1170()
Number of cores detected: 2
Number of threads: 1
Number of hash/es to decrypt: 1
Using brute force decryption method.
Using loweralpha as charset (default).
Combinations of 1 characters min (default)
Combinations of 7 characters max (default)Starting with combinations of 1 characters...
Done. (Time elapsed (sec): 0)
Starting with combinations of 2 characters...
Done. (Time elapsed (sec): 0)
Starting with combinations of 3 characters...
Done. (Time elapsed (sec): 0)
Starting with combinations of 4 characters...
Done. (Time elapsed (sec): 0)
Starting with combinations of 5 characters...
Done. (Time elapsed (sec): 21)
Starting with combinations of 6 characters...
Founded: 3561468224442120539/MUz_GO.idl2RwWkB3ChUIhecxmzLDWMwm2hcSl37YHM=:batmanAll hashes decrypted!!!
Results:
3561468224442120539/MUz_GO.idl2RwWkB3ChUIhecxmzLDWMwm2hcSl37YHM= --> batmanTotal Seconds Elapsed: 43
[root@localhost ~]#
As you can see, JBrute needs a special format for the hash (a related concept to ORACLE-10G or POSTGRESQL hashes). To get the correct format, you should get the hash with this sql query on Informix:
select salt || '/' || substring(hashed_password from 1 for 43) || '='
from sysintauthusers;
The steps:
1) append the password to the salt
2) hash the result of 1) with sha-256
3) encode the digest of 2) with base64
4) replace the "/" character with the "_" character
5) replace the "+" character with the "." character
Thats all for today, if you have any doubts I'm here :)