
Kali365 - EvilTokens Replica
Сервер фишинга с использованием кода устройства для имитации действий злоумышленника. Захватывает токены OAuth Microsoft 365 через поток Device Authorization Grant. Вдохновлен GraphSpy.
Предупреждение — только для авторизованного использования. Этот инструмент предназначен для тестировщиков на проникновение и участников красных команд, действующих на основании явного письменного разрешения. Неправомерное использование может нарушать законы о компьютерном мошенничестве.
microsoft.com/devicelogin.Python-бэкенд (один порт на кампанию) + nginx-фронтенд + постоянное хранение в SQLite.
main_server.py ← единая точка входа (запускать это)
db.py ← уровень постоянного хранения SQLite
html_enroll.py ← построитель страницы регистрации жертвы
html_search.py ← построитель страницы поиска после аутентификации для жертвы
css_shared.py ← общий CSS для интерфейса оператора
nginx_helper.py ← автоматическая генерация и перезагрузка конфигурации обратного прокси nginx
nginx.conf ← базовая конфигурация nginx (включает /etc/nginx/conf.d/*.conf)
Когда кампания создается с установленным доменом, nginx_helper.py автоматически записывает серверный блок для каждого домена в NGINX_CONF (/etc/nginx/conf.d/easytokens.conf по умолчанию) и перезагружает nginx. Трафик жертвы, поступающий на порт 80 для этого домена, проксируется на правильный экземпляр Python-сервера.
nginx.conf отклоняет любой запрос, заголовок Host которого не соответствует известной кампании (return 444), предотвращая случайное раскрытие Python-бэкенда.NGINX_CONF='' или NGINX_RELOAD_CMD='', чтобы отключить автоматическое управление nginx.docker compose up --build
Порты, открываемые Docker:
| Порт | Назначение |
|---|---|
80 | nginx — доменный трафик жертв |
3000 | Python — интерфейс оператора + прямой доступ жертв |
http://localhost:3000/http://localhost:3000/apphttp://<campaign-domain>/ (маршрутизируется через nginx на порту 80)Захваченные токены и журналы сохраняются в томах Docker:
| Том | Путь в контейнере | Назначение |
|---|---|---|
easytokens-data | /data/easytokens.db | База данных SQLite |
./logs | /logs/ | Файлы журналов для каждого запроса |
Требования: Python 3.12+, без сторонних пакетов.
python main_server.py
Каталог php-relay/ содержит автономный контейнер Apache/PHP, который выступает в качестве распределенного узла для жертв. Он обслуживает ту же страницу регистрации с кодом устройства, что и основной сервер, напрямую опрашивает Microsoft и пересылает захваченные токены на главную панель через POST /webhook.
checkin.php отправляет POST-запрос к POST /relay/checkin на главную панель, аутентифицируясь с помощью RELAY_SECRET. Панель регистрирует узел и возвращает node_id.index.php), которая инициирует новый поток кода устройства.poll.php. Когда токен захвачен, poll.php пересылает его на POST /webhook на главную панель, помеченный node_id.Настройте в php-relay/.env:
Оба контейнера одновременно (рекомендуется):
# из EasyTokens/
docker compose -f docker-compose.yml -f php-relay/docker-compose.yml up --build
Запуск обоих с одним объединённым -f помещает их в одну сеть Docker, поэтому MAIN_SERVER_URL=http://easytokens:3000 разрешается правильно.
Доступ:
| URL | Назначение |
|---|---|
http://localhost:8082/ | Страница регистрации жертвы через ретранслятор |
http://localhost:3000/app/nodes | Представление оператора зарегистрированных узлов-ретрансляторов |
Только ретранслятор (удалённая панель):
cd php-relay
# Установите MAIN_SERVER_URL на публичный URL панели в .env
docker compose up --build
openssl rand -hex 32RELAY_SECRET=<секрет> в EasyTokens/.env (будет подхвачен главной панелью через docker-compose.yml)php-relay/.envДве таблицы в базе данных SQLite:
tokens — каждый захваченный токен доступа/обновления (UPN, токен доступа, токен обновления, ID-токен, область, источник, временная метка захвата)device_codes — кампании, инициированные оператором (код пользователя, код устройства, URL проверки, статус, связанный ID токена, порт, домен)MIT — Copyright (c) 2026 Casey Smith
| Метод | Путь | Аудитория | Описание |
|---|
GET | / | Жертва | Страница регистрации с кодом устройства (тема «Офис») |
POST | /poll | Жертва (JS) | Опрашивает конечную точку токена MS; сохраняет токен в случае успеха |
GET | /search?s=<id> | Жертва | Страница поиска после аутентификации (OneDrive/почта) |
GET | /app | Оператор | Панель управления — статистика + недавние захваты |
GET | /app/device-codes | Оператор | Все кампании с живым статусом опроса |
POST | /app/device-codes/new | Оператор | Создать новую кампанию с кодом устройства |
GET | /app/tokens | Оператор | Все захваченные токены |
GET | /app/search?id=<id> | Оператор | Поиск в OneDrive + почте для конкретного токена |
POST | /webhook | Узел-ретранслятор | Принять токен от аутентифицированного узла-ретранслятора |
POST | /relay/checkin | Узел-ретранслятор | Зарегистрировать узел-ретранслятор; возвращает node_id |
| Переменная | По умолчанию | Описание |
|---|
PORT | 3000 | Порт прослушивания для Python-сервера |
PORT_MAX | 3010 | Верхняя граница диапазона портов, открываемых Docker |
DB_PATH | /data/easytokens.db | Путь к базе данных SQLite |
LOG_DIR | /logs | Каталог журналов для каждого запроса |
NGINX_CONF | /etc/nginx/conf.d/easytokens.conf | Путь, куда nginx_helper записывает сгенерированную конфигурацию; установите '' для отключения |
NGINX_RELOAD_CMD | nginx -s reload | Команда оболочки для перезагрузки nginx после изменений конфигурации; установите '' для отключения |
RELAY_SECRET | (не установлено) | Общий секрет для аутентификации узлов-ретрансляторов. Сгенерируйте с помощью openssl rand -hex 32. Должен совпадать с RELAY_SECRET в php-relay/.env. Оставьте неустановленным для отключения поддержки ретрансляции. |
| Переменная | По умолчанию | Описание |
|---|
MAIN_SERVER_URL | http://easytokens:3000 | URL главной панели, доступный из контейнера ретранслятора |
RELAY_SECRET | (обязательно) | Должен совпадать с RELAY_SECRET на главной панели |
RELAY_PORT | 8082 | Хост-порт для открытия ретранслятора |
RELAY_LABEL | имя хоста | Человекочитаемое имя, отображаемое на панели для этого узла |
CHECKIN_RETRIES | 10 | Количество попыток повторной регистрации до отказа |
CHECKIN_DELAY | 5 | Секунды между попытками повторной регистрации |
NODE_ID_FILE | /tmp/relay_node_id | Путь, где кэшируется node_id после регистрации |
| Поле | Значение |
|---|
| ID клиента | d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office) |
| Ресурс | https://graph.microsoft.com |
| Области | openid profile email offline_access Mail.Read Files.Read |
| URL кода устройства | https://login.microsoftonline.com/common/oauth2/devicecode |
| URL токена | https://login.microsoftonline.com/Common/oauth2/token |