
Analise e rastreie tokens OAuth 2.0, OIDC e Microsoft Entra ID a partir de capturas do Burp, mitmproxy ou Chrome DevTools. Visualize ciclos de vida de tokens, detecte escopos de risco e exporte tokens para replay por meio de um painel interativo.
Rastreia tokens OAuth 2.0, OIDC e Microsoft Entra ID em tráfego de rede capturado. Ingere exportações XML do Burp Suite, arquivos de fluxo do mitmproxy ou streams ao vivo do Chrome DevTools Protocol em um único banco de dados SQLite, e então serve um dashboard web interativo para filtrar tokens, percorrer trocas, identificar escopos de risco, exportar tokens para replay e visualizar ciclos de vida de tokens como grafos Mermaid.
Status: TATS é estável para uso pessoal / em engajamentos. Otimizado para o ecossistema Microsoft 365 / Entra (FOCI, BroCI/NAA, cookies de sessão ESTSAUTH, enriquecimento entrascopes.com) mas funciona contra qualquer tráfego OAuth/OIDC razoavelmente padrão.
Quando você faz proxy de uma longa sessão do Microsoft 365 ou Azure através do Burp / mitmproxy a captura resultante é enorme e a maioria das ferramentas ou:
Esta ferramenta extrai cada access / refresh / id token observado, cria fingerprints para correlacionar o mesmo token entre fontes, decodifica claims JWT, resolve GUIDs de client / resource da Microsoft contra entrascopes.com, e renderiza o quadro completo como um único dashboard — incluindo uma visão de cadeia de refresh-token que segue trocas FOCI entre aplicativos e emissão de tokens de aplicativos aninhados BroCI.
Este projeto destina-se principalmente a fins de pesquisa e educação, mas fornece opções como pré-visualização de comandos e recursos de exportação de tokens que podem apoiar algumas ferramentas ofensivas.
ingest — exportação XML "Save items" do Burp Suitemitm — arquivo de fluxo .mitm do mitmproxy (frames HTTP e WebSocket)cdp — anexação ao vivo ao Chrome / Edge via DevTools Protocol
(em tempo real, captura frames HTTP e WebSocket descriptografados por TLS
sem um proxy CA; rastreia cada aba existente E cada aba aberta
durante a execução via auto-attach em nível de navegador)--append para mesclar em um banco de dados existente; tokens
são upserted (contagem de usos + tempo de vida observado acumulam), eventos e
trocas são anexados, e o source_tag da linha registra cada passagem
que viu o token.pip install mitmproxy).access_token, refresh_token, id_token) e
heurísticas de nome de cookie determinam o tipo de token.ESTSAUTH, ESTSAUTHPERSISTENT,
ESTSAUTHLIGHT, SignInStateCookie) são explicitamente reconhecidos como
tokens equivalentes a refresh (caso contrário seriam mal classificados pela
dica genérica de cookie "auth").foci
nas respostas do token-endpoint.brk_client_id, brk_redirect_uri, e esquemas de redirecionamento brk-<guid>://
no corpo da requisição.--enrich busca firstpartyscopes.json e
resources.json de https://entrascopes.com/ e resolve GUIDs de appid /
azp / aud em nomes amigáveis com links clicáveis.upn / preferred_username /
unique_name / email / name, com fallback para sub@iss ou oid,
e exibindo buckets de identidade app-only e desconhecida separadamente. Cada
linha de identidade mostra um badge de capturas quando o usuário aparece em
≥2 source_tags (sobrevivência entre capturas, o principal sinal de pesquisa
do --append) mais um intervalo first_seen → last_seen e um
botão timeline que destaca cada token daquele usuário na
aba de diagrama de Sequência.appid / azp / client_id no corpo do formulário
/ brk_client_id / brk_nested_id) que apareceu em
trocas, com badges FOCI / brokerable / broker / nested.aud observada, resolvida para nomes de recursos
do entrascopes onde possível.tid distintos com contagens de token / usuário / app.scp / scope /
roles de cada token contra uma watchlist curada de permissões de alto impacto
do Microsoft Graph e escopos de recursos do Azure.(token, host) onde
o token foi usado em um host que discorda de sua claim aud
(sugere vazamento ou uso indevido de credencial).amr) — distribuição de pwd / mfa / pop /
smartcard.xms_cc=CP1),
vinculação proof-of-possession (claim cnf, com detecção de kid compartilhado
entre audiences), requisitos de step-up auth (acrs), e o nível de
contexto de autenticação acr. Cada linha é clicável e filtra a
aba Tokens para apenas os tokens que carregam aquele marcador.⚠ priv — o
sinal de pesquisa de expansão de privilégios no estilo FOCI / BroCI.source_tag para que você veja quantas
linhas vieram de cada passagem de ingestão.roadtx describe,
roadtx auth, curl, Python requests, e PowerShell
Invoke-RestMethod.ws-frame-sent /
ws-frame-received, source ws[body_json[<key>]], e um
ws_session_id que agrupa todos os frames dentro de uma conexão WebSocket.O banco de dados armazena fingerprints SHA-256 (primeiros 12 caracteres hex) e um prefixo de 12 caracteres de cada token observado. Strings completas de token nunca saem do arquivo de entrada.
O conteúdo das claims JWT decodificadas (header + payload, incluindo oid, sub,
upn, email, tid, listas de escopo, etc.) é armazenado literalmente por
padrão porque é exatamente o objetivo da análise. Trate o
banco de dados e qualquer URL de dashboard compartilhada como sensível sempre que JWTs estiverem
presentes.
--redact-claims (disponível em ingest, mitm, e cdp)
substitui valores de claims listados por placeholders de hash estáveis antes que
cheguem ao banco de dados. A lista padrão de campos cobre sub, oid,
upn, email, name, unique_name, preferred_username, emails,
mail, ipaddr, given_name, family_name. Passe uma lista explícita
separada por vírgulas (ex.: --redact-claims sub,upn,oid) para sobrescrever
o padrão. A mesma entrada sempre mapeia para o mesmo placeholder, então o
agrupamento de Usuários / Tenants do dashboard ainda funciona sem revelar o
usuário.
--store-tokens (disponível em ingest, mitm, e cdp,
desativado por padrão) opta por escrever a string completa do token no
banco de dados para que o dashboard possa oferecer:
.roadtools_auth e qualquer subcomando roadtx o reconhece).roadtx describe, roadtx auth, curl,
Python requests, PowerShell Invoke-RestMethod — usando as claims
reais de tid, appid, e do token.dataclasses modernas). Testado em 3.12.python -m tats diretamente.| Necessidade | Instalação |
|---|---|
Subcomando mitm | pip install mitmproxy |
| Captura ao vivo do Chrome / Edge | Nenhuma — usa um cliente WebSocket da stdlib |
--enrich (entrascopes.com) | Nenhuma — usa urllib.request |
Executar a partir de um checkout (sem instalação):```bash git clone tats cd tats python -m tats --help
O HTML / CSS / JS do dashboard ficam em `tats/static/` e são carregados
na primeira importação, portanto nenhuma etapa de build é necessária — basta executar o módulo
diretamente a partir do checkout.
**Instalar como pacote (fornece o script de console `tats`):**```bash
pip install . # core only
pip install .[mitm] # + mitmproxy flow file support
pip install .[test] # + pytest for the test suite
pip install .[all] # everything
Após a instalação, você pode chamar a ferramenta pelo seu nome curto:```bash tats ingest engagement.xml -o tokens.db --enrich tats serve tokens.db
Se você precisa apenas dos caminhos Burp / CDP, o arquivo é totalmente autossuficiente
com a biblioteca padrão do Python — nenhuma instalação ou extras são necessários.
---
## Início rápido
**Analise uma exportação XML do Burp e abra o dashboard:**```bash
tats ingest examples/fixture.xml -o tokens.db --enrich
tats serve tokens.db
Combine uma captura do Burp com um arquivo de fluxo do mitmproxy em um único DB:```bash tats ingest engagement.xml -o tokens.db --enrich tats mitm chat-session.mitm -o tokens.db --enrich --append tats serve tokens.db
**Captura ao vivo de um navegador Chrome (vê HTTP descriptografado por TLS + frames WebSocket, sem necessidade de CA de proxy) — deixando a ferramenta iniciar o navegador:**```bash
# Terminal 1 — auto-launch Chrome / Edge / Chromium / Brave
tats cdp -o tokens.db --enrich --launch-chrome
# Terminal 2 — open the dashboard (auto-refreshes every 5 s)
tats serve tokens.db
O navegador iniciado é encerrado e seu perfil temporário é excluído
quando você pressiona Ctrl-C no comando cdp.
Se você preferir se conectar a um navegador já em execução, inicie-o com
--remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile e execute
cdp sem --launch-chrome.
Sanitize um banco de dados antes de compartilhá-lo (redação de PII):```bash
tats ingest engagement.xml -o tokens.db
--enrich --redact-claims
A redação é estável em termos de conteúdo: valores idênticos mapeiam para
placeholders idênticos, pelo que o agrupamento por utilizador do dashboard
continua a funcionar sem mostrar o utilizador.
O cabeçalho do dashboard mostra `live · updated <time>` assim que os dados
começam a fluir.
---
## Subcomandos
Cada subcomando aceita `--help` para a lista canónica de opções. As notas
abaixo explicam *quando* e *como* recorreria a cada um.
### Flags globais
Estas aplicam-se a todos os subcomandos e vão *antes* do nome do subcomando:
* `-v` / `--verbose` — adiciona linhas de log INFO (estado de enriquecimento,
contagens de redação na ingestão). `-vv` adiciona DEBUG (cada pedido ao
servidor).
* `-q` / `--quiet` — silencia as linhas de log INFO; apenas WARNINGs e ERRORs
aparecem. A linha final de output para o utilizador (por exemplo,
`wrote tokens.db (...)`) e quaisquer diagnósticos `error: …` não são
afetados, pelo que continuará a ver o que importa a partir de um script.
* `--version` — imprime a versão da ferramenta e sai.
### `ingest` — exportação XML do Burp Suite
Lê um XML "Save items" (Proxy → HTTP history → clique com o botão direito →
Save items). Ficheiros de projeto binários `.burp` **não** são suportados — o
formato é proprietário e instável entre versões do Burp; exportar os itens
que lhe interessam é o fluxo de trabalho suportado.```bash
tats [-v|-q] ingest <burp_items.xml> -o tokens.db \
[--enrich] [--enrich-cache-dir DIR] [--no-enrich-cache] \
[--append] [--source-tag TAG] [--no-progress] \
[--redact-claims [CLAIMS]] [--no-serve-hint]
Exemplos:```bash
tats ingest burp.xml -o tokens.db --enrich
tats ingest day2.xml -o tokens.db --append
--source-tag burp:day2
### `mitm` — arquivo de fluxo `.mitm` do mitmproxy
Lê um arquivo de fluxo produzido por `mitmdump`, `mitmproxy` ou `mitmweb`. Este
é o único caminho de ingestão que captura **frames WebSocket** sem uma sessão
de navegador ativa — os arquivos de fluxo preservam cada payload de frame de texto / binário.```bash
tats [-v|-q] mitm <flow_file.mitm> -o tokens.db \
[--enrich] [--enrich-cache-dir DIR] [--no-enrich-cache] \
[--append] [--source-tag TAG] [--no-progress] \
[--redact-claims [CLAIMS]] [--no-serve-hint]
Requer pip install mitmproxy. A ferramenta emitirá um erro claro se o
pacote estiver ausente.
Capture um arquivo de fluxo com mitmproxy:```bash mitmdump -w session.mitm
tats mitm session.mitm -o tokens.db --enrich
### `cdp` — conexão ao vivo com Chrome / Edge
Conecta-se a um navegador da família Chromium em execução através do DevTools Protocol
e transmite eventos `Network.*` para o banco de dados. Captura requisições /
respostas HTTP (com corpos obtidos via `Network.getResponseBody`), upgrades de WebSocket,
e cada frame de WebSocket em ambas as direções. O buffer é descarregado para
o banco de dados a cada N eventos (padrão 25), para que a sondagem de 5 segundos do dashboard
capte novos tokens em segundos após o navegador fazer a
requisição.```bash
tats [-v|-q] cdp [-o tokens.db] \
[--host 127.0.0.1] [--port 9222] [--target ID] \
[--launch-chrome [PATH]] [--flush-every N] \
[--enrich] [--append] [--redact-claims [CLAIMS]]
--launch-chrome)```bashtats cdp -o tokens.db --launch-chrome
tats cdp -o tokens.db
--launch-chrome /opt/google/chrome-canary/chrome
O navegador iniciado é executado com `--remote-debugging-port=<port>` e um
user-data-dir temporário novo. Quando você interrompe o comando `cdp` (Ctrl-C),
o navegador é encerrado e o perfil temporário é excluído.
### Anexando a um navegador já em execução
Inicie o navegador você mesmo, com um perfil novo, e então execute `cdp` sem
`--launch-chrome`:```bash
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" ^
--remote-debugging-port=9222 ^
--user-data-dir="%TEMP%\cdp-profile"
# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile
# Linux
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile
Um user-data-dir separado evita anexar a um perfil pessoal e impede que o navegador em execução recuse a flag de depuração.
Por padrão, o cdp anexa no nível do navegador e rastreia cada aba
que existe quando ele inicia E cada aba aberta durante a execução
(window.open, Ctrl-click, botão de nova aba). Todas as abas compartilham o único
WebSocket através do multiplexador de sessão do protocolo flat do CDP, portanto, abrir ou
fechar abas enquanto a captura está em execução é totalmente suportado. Cada anexação
/ desanexação de aba imprime uma nota de uma linha no stderr no nível INFO.
Se você preferir fixar em uma única aba e ter a anexação encerrada quando essa aba fechar, liste os alvos disponíveis:```bash curl http://127.0.0.1:9222/json/list
…então passe `--target <id>`.
Pressione Ctrl-C para parar. A cauda de qualquer buffer em trânsito é descarregada para a
base de dados antes de o processo terminar.
### `serve` — painel web
Lê uma base de dados existente e serve uma interface web de página única em
`127.0.0.1:8765`. O servidor é apenas de leitura; nunca escreve na
base de dados, por isso é seguro executá-lo em paralelo com uma ingestão
`cdp` ou `mitm` em curso.```bash
tats serve <tokens.db> \
[--host 127.0.0.1] [--port 8765] [--no-browser]
Exemplos:```bash
tats serve tokens.db
tats serve tokens.db --port 9000 --no-browser
tats serve tokens.db --host 0.0.0.0
> **Aviso:** a interface web expõe payloads JWT descodificados (claims), impressões digitais de tokens, a linha temporal de atividade e gráficos Mermaid a qualquer pessoa que consiga alcançar o endereço de bind. Se ingeriu com `--store-tokens`, também expõe os **tokens brutos completos** através de `/api/token/<fp>` e `/api/export?fps=...`. **Não existe autenticação**. Mantenha `--host` em `127.0.0.1` a menos que pretenda especificamente o contrário.
#### Exportação pronta para replay
Quando a base de dados foi construída com `--store-tokens`, cada token expandido no separador Tokens obtém uma linha de ações de um clique:
* **Copy raw** — a string completa do token para a área de transferência.
* **Copy Bearer header** — `Authorization: Bearer <token>`, pronto a colar.
* **Copy curl example** — um one-liner que aponta para o `aud` do token (ou o seu host emissor) com o cabeçalho bearer anexado.
* **Download JSON** — um ficheiro JSON de token único contendo raw, claims, eventos observados e exchanges.
* **Copy as roadtx** — a forma JSON de uma cache de tokens roadtools (`tokenType`, `accessToken` / `refreshToken` / `idToken`, `expiresOn`, `tenantId`, `_clientId`, `resource`, `foci`, `scope`). Cole diretamente num ficheiro `.roadtools_auth`.
* **Download .roadtools_auth** — o mesmo payload, descarregado como ficheiro. Renomeie-o para `.roadtools_auth` (ou passe-o via `roadtx <cmd> --tokens-file`) e qualquer subcomando roadtx irá capturá-lo.
A barra de ferramentas do separador Tokens também tem **Export selected for replay**, que acede a `/api/export?fps=fp1,fp2,...` e descarrega um único documento JSON com até 200 tokens (raw, claims, eventos) num só pacote. Sem `--store-tokens`, os mesmos botões mostram uma dica para re-ingerir antes que a exportação pronta para replay se torne possível.
#### Pré-visualização de comandos
Cada token expandido também tem um bloco recolhível **Command preview** que pré-preenche as invocações de replay / inspeção mais comuns usando os claims reais do token (e o valor bruto completo quando `--store-tokens` está ativo). Cada snippet tem um botão Copy de um clique. A mistura exata depende do tipo de token:
* **Qualquer JWT:** `roadtx describe -t '<token>'` (descodificar sem rede).
* **Refresh tokens:**
* `roadtx auth --refresh-token '...' -c <client_id> -t <tenant_id>` — trocar um refresh token por access tokens novos.
* `curl -X POST .../oauth2/v2.0/token` — o equivalente OAuth para utilizadores que não usam roadtx.
* **Access / id / tokens desconhecidos:**
* `curl -H 'Authorization: Bearer ...' '<aud>'`
* Python `requests.get(...)` com o cabeçalho bearer definido.
* PowerShell `Invoke-RestMethod` com o mesmo cabeçalho.
* **Sempre:** o objeto JSON para colocar em `.roadtools_auth`.
Quando `--store-tokens` está desativado, os snippets são renderizados com `<TOKEN>` como placeholder para que o painel continue a ser útil como referência de documentação.
---
## A interface web em detalhe
### Navegação superior
`Summary | Tokens | Exchanges | FOCI | BroCI | Graph | Sequence`
Cada separador é renderizado independentemente a partir do mesmo snapshot em memória de `/api/data`. Alternar entre separadores é instantâneo; os diagramas de grafo e sequência são re-renderizados a pedido e respeitam a seleção atual no separador Tokens.
### Summary
Blocos de estatísticas no topo (tokens / access / refresh / id / unknown / used / unused / events / exchanges / FOCI exchanges / BroCI exchanges / hosts) seguidos por uma grelha de cartões descritos em [Features → Dashboard cards](#dashboard-cards).
Clique em qualquer linha em qualquer cartão para saltar para um separador Tokens pré-filtrado — por exemplo, clicar numa linha de tenant filtra o inventário para tokens que transportam esse `tid`.
### Tokens
Inventário filtrável e ordenável. A seleção múltipla controla os botões highlight / isolate / sequence. A expansão de linha mostra o JWT descodificado completo (cabeçalho + payload como JSON bruto), todos os eventos que envolvem esse token e todas as exchanges onde foi uma entrada ou saída.
### Exchanges
Lista ordenável de todas as exchanges token-for-token detetadas — rotações de refresh-token, cross-redemptions FOCI e exchanges de aplicações aninhadas BroCI. A coluna BroCI mostra broker + IDs de cliente aninhados lado a lado com a evidência que despoletou a deteção.
### FOCI
Duas tabelas: todos os refresh tokens marcados com uma família FOCI (atualmente a Microsoft só emite `"1"`), e todas as exchanges cuja resposta transportava o campo `foci`.
### BroCI
As exchanges de Nested App Authentication. Para cada uma: a aplicação broker (`brk_client_id`), o cliente aninhado (`client_id`), a evidência que despoletou a deteção (`brk_client_id`, `brk_redirect_uri`, URI de redirecionamento `brk-<guid>://`) e as impressões digitais dos tokens de entrada / saída.
### Graph
Mermaid `flowchart LR` das relações token ↔ serviço. Os refresh tokens são desenhados como cilindros, os access / id tokens como estádios. As arestas mostram emissão, apresentação, exchange e rotação. O realce (a partir do separador Tokens) adiciona um acento amarelo; o isolamento re-renderiza o grafo apenas com os tokens selecionados e os tokens com que estes fazem exchange.
### Sequence
Diagrama de sequência Mermaid de todos os eventos por ordem de captura. Selecionar um único token mostra apenas a sua sequência; selecionar vários mantém a vista completa mas destaca os tokens selecionados. Limite máximo de eventos configurável (predefinição 200; os diagramas de sequência Mermaid tornam-se ilegíveis após algumas centenas de mensagens).
---
## Suporte específico da Microsoft
### Family of Client IDs (FOCI)
A Microsoft permite que um refresh token emitido para uma aplicação numa "família" seja resgatado no endpoint de token por **qualquer outra aplicação** da mesma família. A ferramenta deteta FOCI na rede ao analisar o JSON de resposta do endpoint de token à procura de um campo `foci` (atualmente sempre `"1"` para a única família conhecida). Os refresh tokens emitidos nessa resposta são marcados com o id da família e apresentados no separador dedicado **FOCI**.
Se `--enrich` estiver ativado, a coluna de aplicação do inventário também apresenta a flag `foci: true/false` do `firstpartyscopes.json` — note que esta pode discordar da deteção na rede (o conjunto de dados entrascopes é por vezes conservador). O campo `foci` na rede é sempre o sinal autoritativo.
### Brokered Client Init / Nested App Authentication (BroCI / NAA)
Os suplementos do Office, as aplicações Teams e o Portal Azure usam NAA para adquirir tokens para um cliente aninhado através de uma aplicação broker. A ferramenta deteta isto no lado do pedido através de:
* o parâmetro de formulário `brk_client_id` (GUID da aplicação broker),
* o parâmetro de formulário `brk_redirect_uri` (URI de redirecionamento real do broker),
* um `redirect_uri` da forma `brk-<guid>://...` (onde `<guid>` é o broker).
O claim `appid` / `azp` do access token resultante é o cliente aninhado; o broker só aparece na rede — nunca como claim JWT. O dashboard apresenta ambos os lados claramente.
### Cookies de sessão `ESTSAUTH`
`ESTSAUTH`, `ESTSAUTHPERSISTENT`, `ESTSAUTHLIGHT` e `SignInStateCookie` são cookies de sessão do Microsoft Entra que não viajam em `Authorization: Bearer` mas são usados pelo navegador para emitir novos access tokens através de fluxos de autenticação silenciosa. A ferramenta rotula-os como `refresh` (o seu papel funcional) em vez de deixar a regra genérica da substring `auth` classificá-los incorretamente como `access`.
### Enriquecimento entrascopes.com (`--enrich`)
Obtém e coloca em cache `firstpartyscopes.json` (~2,8 MB; 504 aplicações first-party com a sua flag FOCI, URIs de redirecionamento, scopes e capacidade de broker) e `resources.json` (~170 KB; mais de 1.750 mapeamentos recurso → nome de apresentação) de <https://entrascopes.com/>. A cache reside em:
| Variável | Predefinição |
|---|---|
| `$TATS_CACHE` | (prioridade máxima; `$BURP_TOKEN_TRACKER_CACHE` é aceite como fallback para migração de uma versão) |
| `$XDG_CACHE_HOME/tats` | (Linux/macOS) |
| `%LOCALAPPDATA%\tats\cache` | (Windows) |
| `~/.cache/tats` | (fallback) |
O TTL é de 7 dias. Use `--no-enrich-cache` para forçar uma nova obtenção. A cache é reutilizada como fallback obsoleto quando a ferramenta é executada offline.
Quando `--enrich` está ativado, cada GUID de `appid` / `azp` / `client_id` e cada claim `aud` de GUID-ou-URL é resolvido para um nome amigável com um link clicável `https://entrascopes.com/?appId=<guid>`.
---
## Arquitetura
### One-shot: ficheiro → BD → interface web```
burp.xml ─┐
.mitm ─┼─→ Tracker ─→ ingest_to_db ─→ tokens.db ─→ Store ─→ /api/data ─→ dashboard
CDP WS ─┘ ▲ │
(live, repeated) └───── --append upserts on every flush ─┘
Todo caminho de origem produz o mesmo objeto Tracker. ingest_to_db
transforma-o em linhas na base de dados. Store lê a base de dados para o
servidor HTTP, que expõe JSON em /api/data, /api/meta,
/api/token/<fp>, /api/export, /api/graph e /api/sequence.
tokens (chave primária fp) — fingerprint, prefixo da amostra, tipo,
formato, tempo de vida observado, cabeçalho / payload JWT como JSON, campos
de enriquecimento, campos derivados (user_identity, exp_unix, tenant_id,
scopes_text), source_tag separado por vírgulas, raw (string completa do
token, NULL a menos que ingerido com --store-tokens) e
security_features (JSON compacto que descreve marcadores CAE / PoP /
step-up detetados — ver o cartão Security features).
Bases de dados v2 / v3 mais antigas migram automaticamente quando
reabertas em modo append: v2 → v3 adiciona a coluna raw anulável;
v3 → v4 adiciona a coluna security_features anulável e preenche-a a
partir do jwt_payload_json armazenado de cada token na primeira
abertura. Linhas pré-existentes mantêm ambas as colunas nos seus
valores anteriores.events — cada interação de token observada: pedido /
resposta HTTP ou frame WebSocket. Papéis: issued / returned /
presented / used / exchanged-in / ws-frame-sent /
ws-frame-received. Transporta ws_session_id para agrupar frames
dentro de uma ligação.exchanges — quando um pedido portador de token a um endpoint de
token produziu novos tokens na sua resposta. Regista metadados FOCI / BroCI.exchange_inputs, exchange_outputs — fingerprints de tokens em
cada lado de cada exchange.hosts — etiquetas host:port distintas.meta — versão do esquema, lista de origens, generated_at, last_modified
(usado pelo poll em direto do dashboard), contagens.Cada linha escrita na BD transporta um source_tag — por predefinição
burp:<filename>, mitm:<filename> ou cdp:<host>:<port>, mas
sobreponível via --source-tag. Quando o mesmo fingerprint é visto por
mais do que uma passagem de ingestão, o campo source_tag acumula como
uma lista separada por vírgulas, para que o cartão Sources do dashboard
possa mostrar a proveniência de cada token.
--append mantém uma BD existente e faz merge nela via UPSERT para
tokens (contagens de utilizações + tempo de vida observado acumulam, tipos
desconhecidos são atualizados) e INSERT para events / exchanges (com os seus
números seq deslocados para além do máximo existente, para que a linha
temporal de atividade se mantenha monotónica). Incompatibilidade de versão
do esquema recusa o merge para evitar perda silenciosa de dados.
O endpoint /api/meta do servidor web devolve a tabela meta (~200
bytes). O dashboard faz poll a cada 5 segundos e só volta a obter o
/api/data completo quando last_modified muda. O caminho de ingestão
cdp descarrega o seu tracker em memória para a BD a cada 25 eventos por
predefinição, pelo que a latência de relógio de parede desde um pedido do
browser até uma atualização do dashboard é tipicamente < 10 segundos.
.burp do Burp não são suportados. Use Save items para
produzir o XML que a ferramenta consome.alg=none e ataques de confusão de chaves
estão fora do âmbito. Use um auditor de JWT dedicado para esses casos.unknown e são ocultados por predefinição
a menos que --include-unknown esteja definido na flag mais antiga (apenas Burp).--enrich faz pedidos HTTP de saída para
https://entrascopes.com/. Ignore a flag se o seu ambiente não
o permitir.| Sintoma | Causa provável | Correção |
|---|---|---|
error: could not parse <file> as XML | Tentar ingerir um ficheiro de projeto .burp binário | No Burp: Proxy → HTTP history → selecionar itens → clicar com o botão direito → Save items |
error: no <item> elements found | O XML não foi produzido pelo Save items do Burp | Reexporte do Burp; o elemento raiz deve ser <items> |
error: cannot append to DB with schema_version 1 | A BD foi criada por uma build anterior | Elimine a BD e volte a ingerir as origens originais; a migração de esquema intencionalmente não é automática |
error: the 'mitm' source needs the mitmproxy Python package | mitmproxy não instalado | pip install mitmproxy |
error: cannot reach Chrome at 127.0.0.1:9222 | O Chrome não foi iniciado com --remote-debugging-port | Veja a fórmula de lançamento em cdp subcommand |
| O CDP anexa mas não fluem eventos | A página ainda não fez quaisquer pedidos de rede, ou toda a atividade está num OOPIF / worker (não auto-anexado) | Recarregue a página; confirme que os separadores foram registados (procure linhas de log tab attached: … no stderr) |
no browser-level webSocketDebuggerUrl at /json/version | A versão do Chrome é demasiado antiga para CDP ao nível do browser, ou devolveu a forma errada | Atualize o Chrome, ou passe --target <id> para usar o attach legado de separador único |
target … has no webSocketDebuggerUrl | Outro depurador (por exemplo, janela DevTools) já está anexado | Feche o DevTools, ou anexe a um alvo diferente |
O dashboard mostra Failed to load /api/data | O servidor não consegue ler o ficheiro da base de dados | Verifique se o caminho da BD está correto, se o ficheiro é legível e se a versão do esquema corresponde |
| As atualizações em direto deixam de chegar | O processo cdp terminou ou o flush do buffer de rede ainda não disparou | Verifique o terminal do cdp para erros; reduza para atualizações mais rápidas |
Dois construtores de fixtures residem em examples/:```bash
python examples/make_fixture.py examples/fixture.xml tats ingest examples/fixture.xml -o tokens.db --enrich
python examples/make_mitm_fixture.py examples/fixture.mitm tats mitm examples/fixture.mitm -o tokens.db --enrich --append
Após ambas as execuções, `tokens.db` tem 15 tokens (11 do Burp + 4 do
mitmproxy), 23 eventos, incluindo um evento de frame WebSocket, e 3
trocas.
### Suíte de testes```bash
pip install .[test]
pytest
A suíte cobre extração de token, parsing de JWT, classificação de
session-cookie da Microsoft, detecção de FOCI / BroCI, resumo de claims,
redação de PII, o caminho de ingestão de XML do Burp com semântica de
UPSERT em modo append, e o caminho de ingestão de frames WebSocket do
mitmproxy (ignorado automaticamente quando a dependência opcional
mitmproxy está ausente).```text
$ pytest tests/
============================= test session starts =============================
…
======================== 62 passed in 1.4s =================================
### Executando o servidor em primeiro plano```bash
tats serve tokens.db --no-browser
…e abra http://127.0.0.1:8765 manualmente. O servidor registra cada
requisição e quaisquer erros de handler em stderr.
| Caminho | Finalidade |
|---|---|
tats/__init__.py | A ferramenta inteira — parsers, camada de BD, servidor HTTP, cliente CDP; carrega o dashboard de tats/static/ |
tats/__main__.py | Ponto de entrada para python -m tats; mesma lógica do script de console tats instalado |
tats/static/index.html | Esqueleto HTML do dashboard com placeholders {{CSS}} / {{JS}} |
tats/static/style.css | Estilização do dashboard — edite com suas ferramentas CSS normais |
tats/static/app.js | Lógica do dashboard — edite com suas ferramentas JS normais (LSP / lint / formatter) |
pyproject.toml | Metadados de empacotamento, extras opcionais ([mitm], [test], [all]), ponto de entrada do console |
LICENSE | GNU General Public License v3 |
README.md | Este arquivo |
examples/ | Capturas sintéticas + scripts de construção de fixtures (veja examples/README.md) |
examples/make_fixture.py | Gerador sintético de XML do Burp |
examples/make_mitm_fixture.py | Gerador sintético de arquivo de fluxo do mitmproxy |
examples/fixture.xml | Fixture XML do Burp pré-construída |
examples/fixture.mitm | Fixture de fluxo do mitmproxy pré-construída |
tests/ | Suíte pytest (execute com pytest) |
O layout de arquivo único é intencional: a ferramenta foi feita para ser lida, auditada e inserida em investigações por qualquer pessoa com Python instalado. Não há configuração oculta, nenhuma árvore de dependências para avaliar e nenhuma superfície além do próprio arquivo.
Se você alterar subcomandos, schema, cards do dashboard ou a superfície
pública da API (flags da CLI, endpoints /api/*), atualize as seções relevantes
deste arquivo na mesma alteração. As seções com maior probabilidade de desatualização:
GNU General Public License v3.0 ou posterior — texto completo no
arquivo LICENSE na raiz do repositório. O código-fonte do script carrega o
cabeçalho curto padrão apontando para o mesmo.
Você pode redistribuir e/ou modificar a ferramenta sob os termos da GPL v3 (ou qualquer versão posterior, a seu critério). Ela é distribuída sem qualquer garantia; consulte a LICENSE para os termos completos.
aud/api/export?fps=... retornando até 200 tokens (raw, claims,
eventos, trocas) em um único bundle JSON para ferramentas downstream.Ativar isso transforma o banco de dados em uma credencial completa — cada
byte necessário para reproduzir qualquer sessão capturada está nele. Combine com
--redact-claims para limpar a visão decodificada do JWT, mas esteja ciente de que o
token bruto ainda carrega as claims não redigidas codificadas dentro dele.
Quando a flag está desativada, o bloco de pré-visualização de comando do dashboard ainda
é renderizado, apenas com <TOKEN> como placeholder para funcionar como uma
referência de sintaxe; os botões de exportação renderizam uma dica para re-ingerir.
--flush-every