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

Discussion in 'Статьи' started by Baskin-Robbins, 23 May 2021.

  1. Baskin-Robbins

    Baskin-Robbins Reservists Of Antichat

    Joined:
    15 Sep 2018
    Messages:
    239
    Likes Received:
    807
    Reputations:
    212
    Сайт - 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$num1);
            
    $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$num1);
            
    $pass $pass $tmp;
            
    $n++;
        }
        echo 
    "$pass\n";
     
    }
    Тестанул - 10 из 10, Auth bypas:)
     
    #1 Baskin-Robbins, 23 May 2021
    Last edited: 24 May 2021
    totenkopf, Skofield, Svan and 12 others like this.
  2. crlf

    crlf Green member

    Joined:
    18 Mar 2016
    Messages:
    683
    Likes Received:
    1,513
    Reputations:
    460
    Предлагаю перенести этот пост в статьи, т.к. достойно, а сюда выложить сухую выжимку + приложить эксплоит.
    Мораль сей басни такова, что не нужно плодить свои криптовелосипеды :)
     
    Suicide, erwerr2321, K800 and 2 others like this.
  3. fandor9

    fandor9 Reservists Of Antichat

    Joined:
    16 Nov 2018
    Messages:
    630
    Likes Received:
    1,050
    Reputations:
    47
    небольшая добавка, благодаря $num = rand() % 33; (модуло 33) имеем даже не 57 символов, а "только" 33,
    В этом конкретном случае правда это не играет роли...
     
    V777, Spinus, eminlayer7788 and 5 others like this.
  4. Svan

    Svan Well-Known Member

    Joined:
    24 Sep 2020
    Messages:
    68
    Likes Received:
    363
    Reputations:
    2
    Интересные вещи ты рассказываешь.