
Kali365 - Réplica do EvilTokens
Um servidor de phishing de código de dispositivo para emulação de adversários. Captura tokens OAuth do Microsoft 365 através do fluxo Device Authorization Grant. Inspirado no GraphSpy.
Aviso — Uso Autorizado Apenas. Esta ferramenta destina-se a testadores de penetração e red teams que operam sob autorização escrita explícita. O uso indevido pode violar leis de fraude informática.
microsoft.com/devicelogin.Backend Python (uma porta por campanha) + nginx front-end + persistência SQLite.
main_server.py ← unified entry point (run this)
db.py ← SQLite persistence layer
html_enroll.py ← victim enrollment page builder
html_search.py ← victim post-auth search page builder
css_shared.py ← shared CSS for operator UI
nginx_helper.py ← auto-generates and reloads nginx reverse-proxy config
nginx.conf ← base nginx config (includes /etc/nginx/conf.d/*.conf)
| Método | Caminho | Público | Descrição |
|---|---|---|---|
GET | / | Vítima | Página de inscrição de código de dispositivo (tema Dunder Mifflin) |
POST | /poll | Vítima (JS) | Consulta o endpoint de token da MS; armazena token em caso de sucesso |
GET | /search?s=<id> | Vítima | Página de pesquisa do OneDrive/e-mail pós-autenticação |
GET | /app | Operador | Painel — estatísticas + capturas recentes |
GET | /app/device-codes | Operador | Todas as campanhas com status de consulta ao vivo |
POST | /app/device-codes/new | Operador | Criar uma nova campanha de código de dispositivo |
GET | /app/tokens | Operador | Todos os tokens capturados |
GET | /app/search?id=<id> | Operador | Pesquisa no OneDrive + e-mail para um token específico |
POST | /webhook | Nó relay | Ingerir um token de um nó relay autenticado |
POST | /relay/checkin | Nó relay | Registrar um nó relay; retorna node_id |
Quando uma campanha é criada com um domínio definido, nginx_helper.py escreve automaticamente um bloco de servidor por domínio em NGINX_CONF (/etc/nginx/conf.d/easytokens.conf por padrão) e recarrega o nginx. O tráfego da vítima que chega na porta 80 para aquele domínio é redirecionado para a instância correta do servidor Python.
nginx.conf base descarta qualquer requisição cujo cabeçalho Host não corresponda a uma campanha conhecida (return 444), evitando exposição acidental do backend Python.NGINX_CONF='' ou NGINX_RELOAD_CMD='' para desabilitar o gerenciamento automático do nginx.docker compose up --build
Portas expostas pelo Docker:
| Porta | Propósito |
|---|---|
80 | nginx — tráfego de vítima baseado em domínio |
3000 | Python — interface do operador + acesso direto da vítima |
http://localhost:3000/http://localhost:3000/apphttp://<campaign-domain>/ (roteadas através do nginx na porta 80)Tokens capturados e logs são persistidos em volumes Docker:
| Volume | Caminho no container | Propósito |
|---|---|---|
easytokens-data | /data/easytokens.db | Banco de dados SQLite |
./logs | /logs/ | Arquivos de log por requisição |
Requisitos: Python 3.12+, sem pacotes de terceiros.
python main_server.py
| Variável | Padrão | Descrição |
|---|---|---|
PORT | 3000 | Porta de escuta do servidor Python |
PORT_MAX | 3010 | Limite superior da faixa de portas expostas pelo Docker |
DB_PATH | /data/easytokens.db | Caminho do banco de dados SQLite |
LOG_DIR | /logs | Diretório de logs por requisição |
NGINX_CONF | /etc/nginx/conf.d/easytokens.conf | Caminho onde o nginx_helper escreve a configuração gerada; defina como '' para desabilitar |
NGINX_RELOAD_CMD | nginx -s reload | Comando shell para recarregar o nginx após alterações de configuração; defina como '' para desabilitar |
RELAY_SECRET | (não definido) | Segredo compartilhado para autenticação do nó relay. Gere com openssl rand -hex 32. Deve corresponder ao RELAY_SECRET em php-relay/.env. Deixe não definido para desabilitar suporte a relay. |
O diretório php-relay/ contém um container Apache/PHP autônomo que atua como um nó distribuído voltado para a vítima. Ele serve a mesma página de inscrição de código de dispositivo que o servidor principal, consulta diretamente a Microsoft e encaminha os tokens capturados para o painel principal via POST /webhook.
checkin.php faz POST para POST /relay/checkin no painel principal, autenticando com RELAY_SECRET. O painel registra o nó e retorna um node_id.index.php), que inicia um novo fluxo de código de dispositivo.poll.php. Quando um token é capturado, poll.php o encaminha para POST /webhook no painel principal, marcado com o node_id.Configure em php-relay/.env:
| Variável | Padrão | Descrição |
|---|---|---|
MAIN_SERVER_URL | http://easytokens:3000 | URL do painel principal acessível de dentro do container relay |
RELAY_SECRET | (obrigatório) | Deve corresponder ao RELAY_SECRET no painel principal |
RELAY_PORT | 8082 | Porta do host para expor o relay |
RELAY_LABEL | hostname | Nome legível mostrado no painel para este nó |
CHECKIN_RETRIES | 10 | Tentativas de check-in antes de desistir |
CHECKIN_DELAY | 5 | Segundos entre tentativas de check-in |
NODE_ID_FILE | /tmp/relay_node_id | Caminho onde o node_id é armazenado em cache após o check-in |
Ambos os containers simultaneamente (recomendado):
# from EasyTokens/
docker compose -f docker-compose.yml -f php-relay/docker-compose.yml up --build
Executar ambos com um único merge -f coloca-os na mesma rede Docker, para que MAIN_SERVER_URL=http://easytokens:3000 seja resolvido corretamente.
Acesso:
| URL | Propósito |
|---|---|
http://localhost:8082/ | Página de inscrição da vítima do relay |
http://localhost:3000/app/nodes | Visualização do operador dos nós relay registrados |
Apenas relay (painel remoto):
cd php-relay
# Defina MAIN_SERVER_URL para a URL pública do painel no .env
docker compose up --build
openssl rand -hex 32RELAY_SECRET=<segredo> em EasyTokens/.env (captado pelo painel principal via docker-compose.yml)php-relay/.envDuas tabelas no banco de dados SQLite: