ЗАДАНИЕ НА РАЗРАБОТКУ МОДУЛЯ ПОДБОРА ПАРОЛЕЙ К OUTLOOK WEB ACCESS (OWA) Цель модуля - распределенный подбор паролей к OWA * Пометка (отложить) означает, что этот функционал пока не нужно реализовывать. ПРИНЦИП РАБОТЫ Модуль получает с сервера следующую информацию в виде конфигов: - список логин:пароль для подбора - список настроек - список серверов DPOST Модуль состоит из двух частей: - кроулер - сканер Кроулер генерирует url для проверки. Сканер их проверяет. Принцип работы кроулера: случайный обход доменов из топ-50000 списка наподобие Алекса. Точный источник данных для обхода пока неясен - у Алексы платная подписка. Нужно найти альтернативу. s3.amazonaws.com/alexa-static/top-1m.csv.zip Например, https://www.quantcast.com/top-sites/US/3 (отложить) Запасной вариант: работа по жестко заданному списку сайтов, полученному с сервера. Далее, модуль: 1. берет следующий сайт с выхода кроулера 2. проверяет наличие пути /owa 3. проверяет наличие пути mail.domain.com/owa 4. проверяет наличие пути webmail.domain.com/owa 5. если owa не найден ни по одному пути, goto 1 7. берет следующую пару логин:пароль из словаря 8. отправляет HTTP-запрос для логина в owa. 9. при неудаче логина, goto 7 10. при успехе, добавляем найденную комбинацию в список найденных логинов, в виде url|логин|пароль РЕАЛИЗАЦИЯ 0. Название проекта - owa. При реализации, следует сделать следующее (описание алгоритма существенно упрощено): 1. брут-форс должен производиться в несколько потоков. Выбор конкретной схемы многопоточности за разработчиком. Можно предложить следующий вариант: * кроулер работает в один поток, все найденные url складывает в очередь (защищенную мютексом). Потоки сканирования (число ограничено) берут несколько url для сканирования из очереди (это вариация пула потоков). Каждый поток сканирования работает по Н случайно выбранным сайтам из списка. При неудаче логина берется следующий сайт, а текущий ставится в конец очереди. То есть, брут производится циклически по Н сайтам, чтобы не давать пик нагрузки на один и тот же сайт. Если для сайта был найден пароль, он убирается из очереди. - число потоков задается константой компиляции и настройкой из конфига - модуль минимизирует число вызовов connect() для открытия TCP-соединений. Между итерациями, соединение следует держать открытым до тех пор, пока сервер его не закроет. В этом случае, соединение следует переоткрыть. Если попытка переоткрытия соединения не удалась дважды подряд, прекращаются попытки соединиться с данным сайтом на полчаса (константа задается во время компиляции). 2. нужно предусмотреть задержку в секундах между итерациями подбора (также константа компиляции и настройка из конфига) 3. нужно предусмотреть настройку User-Agent. Он должен конфигурироваться как константа компиляции, и как настройка модуля. 4. нужно предусмотреть, что сайт может реагировать на куки. К примеру, отказаться работать, если не получит куки, отданные на изначальный GET / HTTP/1.1 5. Модуль отправляет список найденных паролей раз в Н минут (задается константой компиляции и настройкой из конфига), при условии что с предыдущей отправки были найдены новые пароли. Логика отправки и протокол описаны в документе "ТЗ граб паролей DPOST.txt" 6. (отложить) если брут не дал результатов, следует начать проверку по словарю. URL словарей для скачивания берется из конфига "список настроек". 7. Модуль оформляется в соответствии с правилами разработки модулей (см. modules_HOWTO.txt) 8. Модуль отправляет следующие события с тегом owa: - "Version build %DATE% %TIME%" (один раз при старте) - "OWA passwords sent to DPOST server" при успешной отправке собранных паролей - "OWA passwords send failure: servers unavailable" при отсутствии доступных серверов DPOST - "No OWA passwords in range; trying dictionaries", если закончена отработка по всему списку, ничего не найдено, и начата отработка по словарям - "No OWA passwords; give up", есди закончена отработка по словарям, и ничего не найдено. В таком случае, модуль должен выдать событие WantRelease (см "module_HOWTO") для выгрузки из памяти 9. В данном модуле можно ограниченно использовать C++ STL (std::string, контейнеры). Запрещено использовать std::mutex и примитивы синхронизации - для этого можно использовать только примитивы синхронизации WinAPI (CRITICAL_SECTION итд). 10. Строки обфусцировать библиотекой Andrivet (приложена, см.макрос _STR()) 11. Системные вызовы обфусцировать библиотекой GetApi.h. Быть внимательным, обфускация сисвызовов может давать падения. 12. Модуль должен иметь две версии - x32- и x64-разрядную. 13. В боевой сборке должны быть обфусцированы по максимуму строки, отключен всяческий отладочный вывод. 14. Модуль должен иметь отладочную версию. Отладочный вывод должен выводиться в c:/temp/owa.log (путь к логу настраивается в макросе). 15. В проекте должен быть файл настроек config.h (название неважно, важна суть - здесь все глобальные настройки - пути, макросы-переключатели условной компиляции итд). 16. Модуль должен работать на всех современных версиях Windows. Минимальная поддерживаемая версия Windows - Windows XP (если невозможно - Windows Vista). 17. Проект должен быть оформлен для сборки в Microsoft Visual Studio не ниже 2015. 18. Проект Visual Studio должен быть настроен следующим образом: * Для ВСЕХ профилей сборки: - выходной каталог: $(SolutionDir)Bin\$(PlatformTarget)\$(Configuration)\ - Промежуточный каталог: $(SolutionDir)\obj\$(Platform)\$(Configuration)\$(ProjectName)\ - Многопроцессорная компиляция: да * Профиль Release: - Формат отладочной информации (С/С++ создание кода): нет - Создавать отладочную информацию (компоновщик/отладка): нет КОНФИГИ Имя конфига - это аргумент Ctl функции Control, содержимое конфига - это аргумент CtlArg (см. modules_HOWTO.txt) Весь текст в конфигах регистрозависимый; теги и служебные значения должны быть в нижнем регистре. Конфиги должны быть в любой однобайтной кодировке (предпочтительно ASCII). XML-комментарии запрещены. * settings Конфиг представляет из себя простой xml в следующем формате: задержка между итерациями подбора, в миллисекундах число потоков подбора число url, проверяемых одним потоком (циклически) user agent (отложить)URL дополнительного словаря 1 (отложить)URL дополнительного словаря 2 (отложить)URL дополнительного словаря 3 ... URL дополнительного словаря N Все параметры из этого конфига опциональные. Если параметр не указан, используется константа времени компиляции. * dpost Конфиг представляет из себя простой xml в следующем формате: http://11.22.33.44:8082 127.0.0.1:8083 Префикс http/https к обработчику опционален. Если он указан, следует работать по указанному протоколу. Если он не указан: - если значение порта чётное, то работа идёт без шифрования (HTTP), если порт нечётный, то работа идёт поверх SSL/TLS (HTTPS). Конфиг содержит список серверов, на которые следует отправлять результаты по протоколу DPOST. Формат отправки: простой текст; разделитель строк - \r\n, разделитель полей - символ '|' (вертикальная черта). Формат записи: url|user|password\r\n * pw Список пар "имя пользователя" "пароль". Текст в упаковке gzip. формат строки username|password\r\n (отложить) * sites Конфиг представляет из себя простой текстовый список, разделитель строк - символы \r\n Каждая строка - одно доменное имя. Может как содержать префикс протокола http(s)://, так и не содержать. В этом случае, при брут-форсе следует пробовать оба префикса. (отложить) * dict Конфиг представляет из себя простой текстовый список, разделитель строк - символы \r\n Каждая строка - пара логин|пароль. Разделитель полей - символ '|' (вертикальная черта). (отложить) * ignore Конфиг представляет из себя простой текстовый список, разделитель строк - символы \r\n Каждая строка - URL. Сюда будут включены адреса топ-сайтов вроде gmail. Адреса из этого списка следует игнорировать при переборе. Имеется в виду адрес текущего сканируемого домена, а не доменная часть текущего перебираемого email-адреса. ВТОРАЯ ВЕРСИЯ Основные изменения второй версии: - новый режим проверки - работа с командным сервером РЕЖИМ ПРОВЕРКИ В этом режиме модуль не ищет новые пароли, а проверяет имеющуюся базу на актуальность. Соответственно, в этом режиме: - сканер работает не по списку Alexa, а берет на вход очередной email из словаря email:password - алгоритм поиска URL OWA сохраняется (угадываем url'ы вида webmail.domain.com/owa) - по одному домену (точнее, по угаданному URL OWA этого домена) мы проверяем одну конкретную пару email:password - добавляется настройка mode=check|brute, где check - режим проверки, brute - режим поиска и брутфорса (логика первой версии). По поводу конфигов и словарей см.дальше. КОМАНДНЫЙ СЕРВЕР И КОНФИГИ Ранее мы получали все исходные данные в виде конфигов от бекенда ботов. Это довольно неудобно по разным причинам - ограничения бекенда на размеры конфигов, ограничения на управление конфигами оператором, отсутствие общего статуса сети, отсутствие специализированного хранилища для результатов. Вместо этого будет использоваться командный сервер, у которого мы просим настройки и входные списки, и которому отдаем добычу. В связи с этим, упраздняются все конфиги из первой версии. Появляется новый конфиг srv, содержащий список адресов управляющего сервера, разделенных \r\n или \n, в формате адрес:порт. Если порт четный, работа идет по HTTP, если нечетный - HTTPS. Если указан префикс протокола (http/https), префикс имеет приоритет над указанным портом. Модуль работает с тем управляющим сервером, до которого удалось достучаться первым, по каждому запросу. Получить режим работы можно HTTP-запросом на сервер GET ///owa/mode HTTP/1.1 Значения group и clientid - это поля struct ParentInfo CHAR ParentID[256]; CHAR ParentGroup[64]; (см. module_HOWTO) В теле HTTP-ответа модуль ожидает строку brute или check. Любое другое значение некорректно - в таком случае модуль делает повторные запросы каждые 5 минут; до получения корректного ответа работа модуля не начинается. Сканер получает список доменов для проверки HTTP-запросом на сервер Число потоков сканирования: GET ///owa/th HTTP/1.1 В ответ - неотрицательное число. Если atoi(ответ) == 0, то число потоков по умолчанию = std::thread_concurrency() - 1. GET ///owa/domains HTTP/1.1 Формат ответа: адрес1[\r]\n домен2[\r]\n ... (одна или множество записей) При завершении перебора по выданному списку мы даем знать об этом серверу: GET ///owa/over HTTP/1.1 Ответ сервера - такой же, как на запрос /domains - новый список доменов для работы. При неожиданном ответе (пустой список, код ошибки итд) модуль переходит на холостой ход (сканирование остановлено) и делает тот же самый запрос раз в 10 минут (время - в константу). Словарь для перебора получаем HTTP-запросом к управляющему серверу: GET ///owa/dict HTTP/1.1 В ответ нам приходит словарь либо как text/plain, либо application/gzip (смотрим на заголовок ответа Content-Type) Если упаковка в gzip, то после распаковки мы ожидаем такой же формат словаря, как для простого текста. Формат: email:password[\r]\n Отправка делается по протоколу DPOST (см. "ТЗ граб паролей DPOST" для описания протокола) запросом POST ///owa/81 HTTP/1.1 Собранные данные отправляются в контейнере multipart/form-data с полями source и data. Значение поля source - "OWA Passwords" Значение поля data: простой текст, разделитель строк \r\n Формат записи: owa|url||\r\n ... (одна или множество записей) Частоту отправки намайненных данных можно получить с управляющего сервера HTTP-запросом GET ///owa/freq HTTP/1.1 В теле ответа мы ожидаем число - это число секунд, не чаще которого следует отправлять данные. Если это 0 - отправка сразу по готовности нового результата. Если это положительное число - мы накапливаем записи в буфере и отправляем раз в X секунд, очищая буфер при успешной отправке. При завершении перебора по выданному списку мы даем знать об этом серверу: GET ///owa/over HTTP/1.1 Ответ сервера - такой же, как на запрос /domains - новый список доменов для работы. При неожиданном ответе (пустой список, код ошибки итд) модуль переходит на холостой ход (сканирование остановлено) и делает тот же самый запрос раз в 10 минут (время - в константу).