Atak XSS oraz przejęcie sesji admina – Skrypt Boost Masterservera

Podczas testów korzystałem z wersji ściągniętej z http://playboard.eu/threads/master-server-boost-webstats.141/

Kilka przykładów stron korzystających z tego skryptu
http://playboard.eu/boost/
http://plsetti.pl/boost/

W pliku cron.php skrypt pobiera informacje o serwerach przy pomocy

$data = $newServer->serverInfo($row['address']);

Sama metoda nie jest szczególnie interesująca , jedyne co nas interesuje to to że informacje czyli hostname i mapa są zwracane bez żadnej filtracji.

static function serverInfo($server) {
list($ip,$port) = explode(":", $server);
$fp = @fsockopen('udp://'.$ip, $port);
if($fp) {
stream_set_timeout($fp, 2);
fwrite($fp,"\xFF\xFF\xFF\xFFTSource Engine Query\0\r");
$temp = fread($fp, 4);
$status = socket_get_status($fp);
if($status['unread_bytes']>0) {
$temp = fread($fp, $status['unread_bytes']);
$version = ord(self::getChar($temp));
$array = array();
$array['status'] = "1";
if($version == 109) {
$array['ip'] = self::getString($temp);
$temp = substr($temp, 1);
$array['hostname'] = self::getString($temp);
$temp = substr($temp, 1);
$array['mapname'] = self::getString($temp);
$temp = substr($temp, 1);
self::getString($temp);
$temp = substr($temp, 1);
self::getString($temp);
$temp = substr($temp, 1);
$array['players'] = ord(self::getChar($temp));
$array['maxplayers'] = ord(self::getChar($temp));
} elseif($version == 73) {
self::getChar($temp);
$array['hostname'] = self::getString($temp);
$temp = substr($temp, 1);
$array['mapname'] = self::getString($temp);
$temp = substr($temp, 1);
self::getString($temp);
$temp = substr($temp, 1);
self::getString($temp);
$temp = substr($temp, 3);
$array['players'] = ord(self::getChar($temp));
$array['maxplayers'] = ord(self::getChar($temp));
}
} else {
$array['hostname'] = 'Brak nazwy serwera';
$array['mapname'] = '-';
$array['players'] = '0';
$array['maxplayers'] = '0';
$array['status'] = '0';
}
}
return $array;
}

W kolejnej linii wrzucamy dane do mysql

mysql_query("UPDATE `servers` SET `hostname` = '".mysql_real_escape_string($data['hostname'])."', `players` = '".mysql_real_escape_string($data['players'])."', `maxplayers` = '".mysql_real_escape_string($data['maxplayers'])."', `map` = '".mysql_real_escape_string($data['mapname'])."', `status` = '".intval($data['status'])."' WHERE `id` = {$row['id']}");

dane są filtrowane poprzez mysql_real_escape_string wiec nie możemy używać znaków \x00, \n, \r, \, ’, ” i \x1a.

Przy wyświetlaniu dane ponownie nie są filtrowane.

echo '

'.$num.'
'.$row['hostname'].'
'.$row['address'].'
'.$row['map'].'
'.$newMain->showbar($row['players'], $row['maxplayers']).'
'.$thisdate.'
<center>'.$row['rounds'].'</center>';

Dzięki temu wszystkiemu jeśli w nazwie serwera lub w nazwie mapy wrzucimy odpowiedni kod zostanie on zinterpretowany przez przeglądarke i wykonany.
np.

<script src="file.js"></script>

pomimo pominięcia ” w nazwie pliku ( tego znaku nie możemy używać ) plik zostanie poprawnie wczytany a kod w nim wykonany

Co dalej ?

Warto przyjrzeć się jak jest sprawdzane logowanie do panelu admina

if(isset($_COOKIE["adminhash"]) AND $_COOKIE["adminhash"] != $auth[2] OR !isset($_COOKIE["adminhash"])) {
require_once "include/admin/admin_auth.php";
}

całość opiera się na pliku cookies z hashem.

Ustawianie cookies odbywa się bardzo prosto

if(!empty($_POST['login']) AND !empty($_POST['password'])) {
if($_POST['login'] == $auth[0] AND md5($_POST['password']) == $auth[1]) {
setcookie("adminhash", $auth[2], time()+2592000, "/");
header("Location: admin.php");
} else {
$showmsg = $newMess-&gt;into_msg("2", "Nieprawidłowy login lub hasło!", "2");
}

}

widać tutaj że w cookie adminhash ustawiamy wartość hashu sprawdzaną podczas logowania się do panelu.

W kodzie wyżej jest jeden błąd pozwalający na wykradnięcie hashu i wykorzystanie go do zalogowania się do panelu admina bez znajomości hasła czy loginu.

Jak te błędy poprawić ?

W sumie jest to bardzo proste. Aby załatać 1 błąd wystarczy podczas wyświetlania danych użyć htmlentities
np.

echo '

'.$num.'
'.htmlentities( $row['hostname'] ).'
'.$row['address'].'
'.htmlentities( $row['map'] ).'
'.$newMain-&gt;showbar($row['players'], $row['maxplayers']).'
'.$thisdate.'
<center>'.$row['rounds'].'</center>';

drugi błąd polega na tym że na cookies nie jest ustawiana flaga httponly dzięki czemu javascript ma do nich dostęp
wystarczy zamiast

setcookie("adminhash", $auth[2], time()+2592000, "/");

użyć

setcookie("adminhash", $auth[2], time()+2592000, "/", null, null, true );

12 komentarzy o “Atak XSS oraz przejęcie sesji admina – Skrypt Boost Masterservera

  1. Podobno playboard twierdzi że tego buga nie ma i zamawiane przez nich instalacje są na nowym skrypcie ma ktoś do niego download?

    0
    0
  2. Właściciel plsetti.pl/boost i bodajże csadv twierdzą że nie ma już tego bugu, mógłbyś sprawdzić lub pokazać mniej więcej jak zobaczyć czy to działa?

    0
    0
  3. Naturalne jest że po opublikowaniu tego instalka została poprawiona wiadomo też że niektóre serwisy były zabezpieczone wcześniej

    0
    0

Dodaj komentarz

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.