Natas Level 17 → Level 18

The page contain a username for you to check if the user exist but after you enter anything, it return a blank page. Looking at the source code, we can see there is a very similar attack to use from our sql injection from Level 15 → 16 but comments out all responses.

<? 
/* 
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 { 
?>

Notice that beside the comments out echo, the code is exactly the same as Level 15 → 16. This mean we can still do sql injection but we need some other way to let us know our username/password guess is correct. Luckily, there is a query command call SLEEP that causes the process to sleep for a number of seconds. We try using this by guessing our next username natas18 with the following input.

natas18" and SLEEP(10); #
The blank page comes back unusually long indicate that natas18 is one of the username exist in the database. We verify it by putting anything else in place of natas18 and the blank page comes back immediately. This tells us that it is using short circuit evaluation for the “and” predicate. This time, let’s use REGEXP instead of LIKE to show the same attack. We can search a range instead of one character at a time using [a-z] for a to z. Manually doing a binary search of all characters gives us the first character of the next password.
natas18" AND password COLLATE latin1_general_cs REGEXP "^x" AND SLEEP(3); #
We are ready to modify our previous program to include a timing attack by detecting when the server response, we can tell which of our guess is correct. After playing with the code to include a time different check between each request and response time (> 2.0 sec), we got the next password.
xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP

Using a binary search algorithm in our script and choosing a short enough sleep time really shorten the overall execution time by a lot.

Additional resources:

Advertisements