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
[pawn]$data = $newServer->serverInfo($row[’address’]);[/pawn]
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.
[pawn]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;
}[/pawn]
W kolejnej linii wrzucamy dane do mysql
[pawn]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’]}”);[/pawn]
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.
[pawn]echo ’
’.$num.’
’.$row[’hostname’].’
’.$row[’address’].’
’.$row[’map’].’
’.$newMain->showbar($row[’players’], $row[’maxplayers’]).’
’.$thisdate.’
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.
[pawn][/pawn]
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
[pawn]if(isset($_COOKIE[„adminhash”]) AND $_COOKIE[„adminhash”] != $auth[2] OR !isset($_COOKIE[„adminhash”])) {
require_once „include/admin/admin_auth.php”;
}[/pawn]
całość opiera się na pliku cookies z hashem.
Ustawianie cookies odbywa się bardzo prosto
[pawn]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”);
}
}[/pawn]
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.
[pawn]echo ’
’.$num.’
’.htmlentities( $row[’hostname’] ).’
’.$row[’address’].’
’.htmlentities( $row[’map’] ).’
’.$newMain->showbar($row[’players’], $row[’maxplayers’]).’
’.$thisdate.’
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
[pawn]setcookie(„adminhash”, $auth[2], time()+2592000, „/”);[/pawn]
użyć
[pawn]setcookie(„adminhash”, $auth[2], time()+2592000, „/”, null, null, true );[/pawn]
http://serwery.csx-scripts.pl/
Odpada, inny skrypt, logowanie do panelu admina jest możliwe tylko z 1 IP
A co z cssetti.pl, csadv.pl, cs-boost.pl?
I jak sprawdzić czy dana strona ma ten „bug”?
Podobno playboard twierdzi że tego buga nie ma i zamawiane przez nich instalacje są na nowym skrypcie ma ktoś do niego download?
Viva usunąłem link.
Gdzie tak twierdzi 😉 ?
csadv.pl, cs-boost.pl korzystają z tego skryptu cssetti.pl nie
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?
To od samego początku nie działało 🙂 przynajmniej u mnie.
Naturalne jest że po opublikowaniu tego instalka została poprawiona wiadomo też że niektóre serwisy były zabezpieczone wcześniej
jest możliwość przerobienia skryptu master boost pod cs:go ?
Tak oczywiście
a byś był miły i przerobił go ?
Możesz dać cały ten plik z naprawiony bugiem ?
Jet opisane na końcu jak to poprawić 😉