Wednesday, 23 October 2013

Reversible Rovnix passwords

I got my hands on Rovnix recently.
Not the one who got leaked with Carberp but the 'ISFB' package part (Core, Interceptor, ATS, VNC modules, etc...):

And the panel..
Who ask for mod_rewrite for an unknown reason (ok the htaccess, but is it really usefull here?)

I've already took some screenshots of inside Rovnix, so let's skip about the screenshots part.
Just check this article if you want see pics from the Rovnix C&C:

The panel come with a sql dump, and a user/password is already defined inside.
The password look's like a MD5 hash and we know nothing about it.

SQL tables:

By looking the hash on Google we have a correspondence with '21240':

A tool confirm also that the hash is good for '21240'

But.. there is a problem somewhere:

So we have to check the code to see what's going on.

admin/index.php use a function getMyHash()

This small function can be found inside mod/main.php:

We have a salt and they use md5() but we have a huge mistake here:
'+' instead of '.' everywhere.
So if we try to hash a password composed only of numbers, we will have a obvious problem.
Like it's the case for the 'default password' found inside the sql dump.

If you want an example:
310dcbbf4cce62f762a2aaa148d556bd = getMyHash('123')
310dcbbf4cce62f762a2aaa148d556bd = md5('333')
'collision' with 2 algo.

We can obtain the password from the hash easily, PoC:
         * Defeat the weak hash function of Rovnix
         * to get password from a hash.

        $HASH   = 'fbff791ef0770855e599ea6f87d41653';
        $value  = getNumber($HASH);
        $search = search($value, $HASH);
        echo('Hash:   ' . $HASH  . '<br />');
        echo('Value:  ' . $value . '<br />');
        echo('Search: ' . $search);
        // Search an working (number) password
        function search($value, $hash) {
                $i = 0;
                while (true) {
                        if (getHash($i) == $value)
                                return $i;
        // Get the hashed number
        function getNumber($hash) {
                $i = 0;
                while (true) {
                        if (md5($i) == $hash)
                                return $i;
        // Hash function without final MD5 (return only numbers)
        function getHash($hash) {
                $salt = 'LKJFDJLJkkljKJKJKJkjkj$i%&@(%jkjJn@@j$r@!cdh*!@#$djl1J$r!j@o*$@duJxlJLEKJkJFKJEJ2$jkeJFJLEJFE';
                return $hash + $salt + md5($salt) + md5($hash) + $salt[3];

Output for the unknown hash:

So the unknown password for fbff791ef0770855e599ea6f87d41653 is in reality '21173'.
Let's try..
Excellent, we can't log with '21240' because it will be sent to getMyHash() but it's interesting to see this type of bug and how a bad algorithm implementation can cause a security problem.


  1. Xyl, can you explain me a little about what ATS you found?