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 '<tr><td>'.$num.'</td><td>'.$row['hostname'].'</td><td>'.$row['address'].'</td><td>'.$row['map'].'</td><td>'.$newMain->showbar($row['players'], $row['maxplayers']).'</td><td>'.$thisdate.'</td><td><center>'.$row['rounds'].'</center></td></tr>';

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->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 '<tr><td>'.$num.'</td><td>'.htmlentities( $row['hostname'] ).'</td><td>'.$row['address'].'</td><td>'.htmlentities( $row['map'] ).'</td><td>'.$newMain->showbar($row['players'], $row['maxplayers']).'</td><td>'.$thisdate.'</td><td><center>'.$row['rounds'].'</center></td></tr>';

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

Pozostaw odpowiedź Blaku Anuluj pisanie odpowiedzi

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