
Analiza y rastrea tokens de OAuth 2.0, OIDC y Microsoft Entra ID desde capturas de Burp, mitmproxy o Chrome DevTools. Visualiza los ciclos de vida de los tokens, detecta scopes riesgosos y exporta tokens para su repetición mediante un panel interactivo.
Rastrea tokens de OAuth 2.0, OIDC y Microsoft Entra ID a través del tráfico de red capturado. Ingiere exportaciones XML de Burp Suite, archivos de flujo de mitmproxy o transmisiones en vivo del Protocolo Chrome DevTools en una única base de datos SQLite, y luego sirve un panel web interactivo para filtrar tokens, recorrer intercambios, detectar ámbitos riesgosos, exportar tokens para replay y visualizar ciclos de vida de tokens como gráficos Mermaid.
Estado: TATS es estable para uso personal / de engagement. Optimizado para el ecosistema Microsoft 365 / Entra (FOCI, BroCI/NAA, cookies de sesión ESTSAUTH, enriquecimiento de entrascopes.com) pero funciona contra cualquier tráfico OAuth/OIDC más o menos estándar.
Cuando proxeas una sesión larga de Microsoft 365 o Azure a través de Burp / mitmproxy, la captura resultante es enorme y la mayoría de las herramientas:
Esta herramienta extrae cada token de acceso / refresco / id observado, les asigna huellas para poder correlacionar el mismo token entre fuentes, decodifica las claims JWT, resuelve los GUID de cliente / recurso de Microsoft contra entrascopes.com, y renderiza todo el panorama como un único panel — incluyendo una vista de cadenas de refresh-token que sigue los intercambios entre aplicaciones de FOCI y la emisión de tokens de aplicaciones anidadas de BroCI.
Este proyecto está destinado principalmente a fines de investigación y educación, pero proporciona opciones como la vista previa de comandos y funciones de exportación de tokens que pueden servir de apoyo a algunas herramientas ofensivas.
ingest — exportación XML "Save items" de Burp Suitemitm — archivo de flujo .mitm de mitmproxy (tramas HTTP y WebSocket)cdp — conexión en vivo a Chrome / Edge mediante el Protocolo DevTools
(en tiempo real, captura tramas HTTP y WebSocket descifradas por TLS
sin una CA de proxy; rastrea cada pestaña existente Y cada pestaña abierta
durante la ejecución mediante auto-attach a nivel de navegador)--append para fusionarse en una base de datos existente; los tokens
se hacen upsert (el conteo de usos + el tiempo de vida observado se acumulan), los eventos y
los intercambios se añaden, y el source_tag de la fila registra cada pasada
que ha visto el token.pip install mitmproxy).access_token, refresh_token, id_token) y
heurísticas de nombres de cookies determinan el tipo de token.ESTSAUTH, ESTSAUTHPERSISTENT,
ESTSAUTHLIGHT, SignInStateCookie) se reconocen explícitamente como
tokens equivalentes a refresh (de lo contrario serían mal clasificados por
la pista genérica de cookie "auth").foci
en las respuestas del endpoint de token.brk_client_id, brk_redirect_uri y esquemas de redirección brk-<guid>://
en el cuerpo de la solicitud.--enrich obtiene firstpartyscopes.json y
resources.json de https://entrascopes.com/ y resuelve los GUID de appid /
azp / aud en nombres amigables con enlaces clicables.upn / preferred_username /
unique_name / email / name, con fallback a sub@iss o oid,
y mostrando por separado los grupos de solo aplicación e identidad desconocida. Cada
fila de identidad muestra una insignia de capturas cuando el usuario aparece en
≥2 source_tags (supervivencia entre capturas, la señal de investigación
principal de --append) más un lapso first_seen → last_seen y un
botón de timeline que resalta cada token de ese usuario en
la pestaña de diagrama de secuencia.appid / azp / client_id del cuerpo
del formulario / brk_client_id / brk_nested_id) que ha aparecido en
intercambios, con insignias de FOCI / brokerable / broker / anidada.aud observada, resuelta a nombres de recursos
de entrascopes donde sea posible.tid distintos con conteos de tokens / usuarios / aplicaciones.scp / scope /
roles de cada token contra una lista de vigilancia curada de permisos de
Microsoft Graph de alto impacto y ámbitos de recursos de Azure.(token, host) donde
el token se usó en un host que no concuerda con su claim aud
(sugiere fuga o mal uso de credenciales).amr) — distribución de pwd / mfa / pop /
smartcard.xms_cc=CP1),
vinculación proof-of-possession (claim cnf, con detección de kid
compartido entre audiencias), requisitos de step-up auth (acrs) y el nivel
de contexto de autenticación acr. Cada fila es clicable y filtra la
pestaña Tokens para mostrar solo los tokens que llevan ese marcador.⚠ priv — la
señal de investigación de expansión de privilegios al estilo FOCI / BroCI.source_tag para que puedas ver cuántas
filas provinieron de cada pasada de ingesta.roadtx describe,
roadtx auth, curl, requests de Python y Invoke-RestMethod de PowerShell.ws-frame-sent /
ws-frame-received, origen ws[body_json[<key>]] y un
ws_session_id que agrupa todas las tramas dentro de una conexión WebSocket.La base de datos almacena huellas SHA-256 (primeros 12 caracteres hex) y un prefijo de 12 caracteres de cada token observado. Las cadenas de token completas nunca salen del archivo de entrada.
El contenido de las claims JWT decodificadas (cabecera + payload, incluyendo oid, sub,
upn, email, tid, listas de ámbitos, etc.) se almacena textualmente por
defecto porque es el objetivo central del análisis. Trata la
base de datos y cualquier URL de panel compartida como sensibles siempre que haya JWTs
presentes.
--redact-claims (disponible en ingest, mitm y cdp)
reemplaza los valores de claims listados con marcadores de posición hash estables antes de que
lleguen a la base de datos. La lista de campos predeterminada cubre sub, oid,
upn, email, name, unique_name, preferred_username, emails,
mail, ipaddr, given_name, family_name. Pasa una lista explícita
separada por comas (p. ej. --redact-claims sub,upn,oid) para sobrescribir
la predeterminada. La misma entrada siempre se asigna al mismo marcador de posición, por lo que la
agrupación de Usuarios / Inquilinos del panel sigue funcionando sin revelar el
usuario.
--store-tokens (disponible en ingest, mitm y cdp,
desactivado por defecto) opta por escribir la cadena de token completa en la
base de datos para que el panel pueda ofrecer:
.roadtools_auth y cualquier subcomando de roadtx lo tomará).roadtx describe, roadtx auth, curl,
requests de Python, Invoke-RestMethod de PowerShell — usando las
claims reales de tid, y del token.dataclasses modernos). Probado en 3.12.python -m tats directamente.| Necesidad | Instalación |
|---|---|
Subcomando mitm | pip install mitmproxy |
| Captura en vivo desde Chrome / Edge | Ninguna — usa un cliente WebSocket de la stdlib |
--enrich (entrascopes.com) | Ninguna — usa urllib.request |
Ejecutar desde un checkout (sin instalación):```bash git clone tats cd tats python -m tats --help
El HTML / CSS / JS del panel se encuentran en `tats/static/` y se cargan
en la primera importación, por lo que no se requiere un paso de compilación — simplemente ejecuta el módulo
directamente desde el checkout.
**Instalar como paquete (te proporciona el script de consola `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
Después de instalar, puedes llamar a la herramienta por su nombre corto:```bash tats ingest engagement.xml -o tokens.db --enrich tats serve tokens.db
Si solo necesitas las rutas de Burp / CDP, el archivo es completamente autónomo
con la biblioteca estándar de Python — no se requiere instalación ni extras.
---
## Inicio rápido
**Analizar una exportación XML de Burp y abrir el panel:**```bash
tats ingest examples/fixture.xml -o tokens.db --enrich
tats serve tokens.db
Combinar una captura de Burp con un archivo de flujo de mitmproxy en una sola base de datos:```bash tats ingest engagement.xml -o tokens.db --enrich tats mitm chat-session.mitm -o tokens.db --enrich --append tats serve tokens.db
**Captura en vivo desde un navegador Chrome (ve HTTP descifrado por TLS + tramas WebSocket, no se necesita CA de proxy) — dejando que la herramienta lance el 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
El navegador lanzado se termina y su perfil temporal se elimina
cuando pulsas Ctrl-C en el comando cdp.
Si prefieres conectarte a un navegador que ya está en ejecución, inícialo con
--remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile y ejecuta
cdp sin --launch-chrome.
Sanitizar una base de datos antes de compartirla (redacción de PII):```bash
tats ingest engagement.xml -o tokens.db
--enrich --redact-claims
La redacción es estable en cuanto al contenido: valores idénticos se asignan a marcadores de posición idénticos, por lo que la agrupación por usuario del panel sigue funcionando sin mostrar el usuario.
La cabecera del panel muestra `live · updated <time>` una vez que los datos empiezan a fluir.
---
## Subcomandos
Cada subcomando acepta `--help` para obtener la lista canónica de opciones. Las notas a continuación explican *cuándo* y *cómo* recurrirías a cada uno.
### Flags globales
Estos se aplican a todos los subcomandos y van *antes* del nombre del subcomando:
* `-v` / `--verbose` — añade líneas de log INFO (estado del enriquecimiento, recuentos de redacción de la ingesta). `-vv` añade DEBUG (cada petición al servidor).
* `-q` / `--quiet` — silencia las líneas de log INFO; solo aparecen WARNINGs y ERRORs. La línea final de salida al usuario (p. ej. `wrote tokens.db (...)`) y cualquier diagnóstico `error: …` no se ven afectados, así que seguirás viendo lo importante desde un script.
* `--version` — imprime la versión de la herramienta y sale.
### `ingest` — Exportación XML de Burp Suite
Lee un XML de "Save items" (Proxy → HTTP history → clic derecho → Save items). Los archivos de proyecto binarios `.burp` **no** son compatibles — el formato es propietario e inestable entre versiones de Burp; exportar los elementos que te interesan es el flujo de trabajo soportado.```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]
Ejemplos:```bash
tats ingest burp.xml -o tokens.db --enrich
tats ingest day2.xml -o tokens.db --append
--source-tag burp:day2
### `mitm` — archivo de flujo `.mitm` de mitmproxy
Lee un archivo de flujo producido por `mitmdump`, `mitmproxy` o `mitmweb`. Esta
es la única ruta de ingesta que captura **tramas WebSocket** sin una sesión
de navegador en vivo — los archivos de flujo preservan cada payload de trama de texto / binaria.```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]
Requiere pip install mitmproxy. La herramienta emitirá un error claro si
falta el paquete.
Captura un archivo de flujo con mitmproxy:```bash mitmdump -w session.mitm
tats mitm session.mitm -o tokens.db --enrich
### `cdp` — conexión en vivo a Chrome / Edge
Se conecta a un navegador de la familia Chromium en ejecución a través del DevTools Protocol
y transmite eventos `Network.*` a la base de datos. Captura solicitudes /
respuestas HTTP (con cuerpos obtenidos mediante `Network.getResponseBody`), actualizaciones
de WebSocket y cada frame de WebSocket en ambas direcciones. El búfer se vacía a
la base de datos cada N eventos (por defecto 25), por lo que el sondeo de 5 segundos del
dashboard detecta nuevos tokens en cuestión de segundos desde que el navegador realiza la
solicitud.```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
El navegador lanzado se ejecuta con `--remote-debugging-port=<port>` y un
user-data-dir temporal nuevo. Cuando detienes el comando `cdp` (Ctrl-C),
el navegador se termina y el perfil temporal se elimina.
### Adjuntarse a un navegador ya en ejecución
Inicia el navegador tú mismo, con un perfil nuevo, y luego ejecuta `cdp` sin
`--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
Un user-data-dir separado evita adjuntarse a un perfil personal y
evita que el navegador en ejecución rechace el flag de depuración.
Por defecto, cdp se adjunta a nivel del navegador y rastrea cada pestaña
que existe cuando se inicia Y cada pestaña abierta durante la ejecución
(window.open, Ctrl-click, botón de nueva pestaña). Todas las pestañas comparten el único
WebSocket a través del multiplexor de sesiones del protocolo plano de CDP, por lo que abrir o
cerrar pestañas mientras la captura está en ejecución es totalmente compatible. Cada adjuntar
/ desadjuntar de pestaña imprime una nota de una línea en stderr a nivel INFO.
Si prefieres fijarte a una sola pestaña y que la conexión termine cuando esa pestaña se cierre, lista los objetivos disponibles:```bash curl http://127.0.0.1:9222/json/list
…luego pasa `--target <id>`.
Pulsa Ctrl-C para detener. La cola de cualquier búfer en vuelo se vuelca a la
base de datos antes de que el proceso finalice.
### `serve` — panel web
Lee una base de datos existente y sirve una interfaz web de página única en
`127.0.0.1:8765`. El servidor es de solo lectura; nunca escribe en la
base de datos, por lo que es seguro ejecutarlo junto a una ingesta `cdp` o `mitm`
en curso.```bash
tats serve <tokens.db> \
[--host 127.0.0.1] [--port 8765] [--no-browser]
Ejemplos:```bash
tats serve tokens.db
tats serve tokens.db --port 9000 --no-browser
tats serve tokens.db --host 0.0.0.0
> **Advertencia:** la interfaz web expone payloads JWT decodificados (claims), huellas de tokens, la línea de tiempo de actividad y gráficos Mermaid a cualquiera que pueda alcanzar la dirección de bind. Si se ingirió con `--store-tokens`, también expone los **tokens en bruto completos** a través de `/api/token/<fp>` y `/api/export?fps=...`. **No hay autenticación**. Mantenga `--host` en `127.0.0.1` a menos que se pretenda lo contrario específicamente.
#### Exportación lista para replay
Cuando la base de datos se construyó con `--store-tokens`, cada token expandido en la pestaña Tokens obtiene una fila de acciones de un clic:
* **Copy raw** — la cadena completa del token al portapapeles.
* **Copy Bearer header** — `Authorization: Bearer <token>`, listo para pegar.
* **Copy curl example** — un one-liner que apunta al `aud` del token (o su host emisor) con la cabecera bearer adjunta.
* **Download JSON** — un archivo JSON de un solo token que contiene raw, claims, eventos observados e intercambios.
* **Copy as roadtx** — la forma JSON de una caché de tokens de roadtools (`tokenType`, `accessToken` / `refreshToken` / `idToken`, `expiresOn`, `tenantId`, `_clientId`, `resource`, `foci`, `scope`). Pegue directamente en un archivo `.roadtools_auth`.
* **Download .roadtools_auth** — el mismo payload, descargado como archivo. Renómbrelo a `.roadtools_auth` (o páselo vía `roadtx <cmd> --tokens-file`) y cualquier subcomando de roadtx lo recogerá.
La barra de herramientas de la pestaña Tokens también tiene **Export selected for replay**, que llama a `/api/export?fps=fp1,fp2,...` y descarga un único documento JSON con hasta 200 tokens (raw, claims, eventos) en un solo paquete. Sin `--store-tokens`, los mismos botones muestran una sugerencia para re-ingerir antes de que la exportación lista para replay sea posible.
#### Vista previa de comandos
Cada token expandido también tiene un bloque colapsable **Command preview** que pre-rellena las invocaciones más comunes de replay / inspección usando los claims reales del token (y el valor en bruto completo cuando `--store-tokens` está activado). Cada fragmento tiene un botón Copy de un clic. La mezcla exacta depende del tipo de token:
* **Cualquier JWT:** `roadtx describe -t '<token>'` (decodificar sin red).
* **Refresh tokens:**
* `roadtx auth --refresh-token '...' -c <client_id> -t <tenant_id>` — intercambiar un refresh token por access tokens nuevos.
* `curl -X POST .../oauth2/v2.0/token` — el equivalente OAuth para usuarios que no ejecutan roadtx.
* **Access / id / tokens desconocidos:**
* `curl -H 'Authorization: Bearer ...' '<aud>'`
* Python `requests.get(...)` con la cabecera bearer establecida.
* PowerShell `Invoke-RestMethod` con la misma cabecera.
* **Siempre:** el objeto JSON para colocar en `.roadtools_auth`.
Cuando `--store-tokens` está desactivado, los fragmentos se renderizan con `<TOKEN>` como marcador de posición para que el panel siga siendo útil como referencia de documentación.
---
## La interfaz web en detalle
### Navegación superior
`Summary | Tokens | Exchanges | FOCI | BroCI | Graph | Sequence`
Cada pestaña se renderiza de forma independiente a partir de la misma instantánea en memoria de `/api/data`. Cambiar de pestaña es instantáneo; los diagramas de grafo y secuencia se re-renderizan bajo demanda y respetan la selección actual en la pestaña Tokens.
### Summary
Mosaicos de estadísticas en la parte superior (tokens / access / refresh / id / unknown / used / unused / events / exchanges / FOCI exchanges / BroCI exchanges / hosts) seguidos de una cuadrícula de tarjetas descritas en [Features → Dashboard cards](#dashboard-cards).
Haga clic en cualquier fila de cualquier tarjeta para saltar a una pestaña Tokens pre-filtrada — por ejemplo, hacer clic en una fila de tenant filtra el inventario a los tokens que llevan ese `tid`.
### Tokens
Inventario filtrable y ordenable. La selección múltiple controla los botones de highlight / isolate / sequence. La expansión de fila muestra el JWT decodificado completo (header + payload como JSON en bruto), cada evento que involucra ese token, y cada intercambio donde fue una entrada o salida.
### Exchanges
Lista ordenable de cada intercambio token-por-token detectado — rotaciones de refresh-token, cross-redemptions de FOCI, e intercambios de apps anidadas de BroCI. La columna BroCI muestra el broker + los client IDs anidados lado a lado con la evidencia que desencadenó la detección.
### FOCI
Dos tablas: cada refresh token etiquetado con una familia FOCI (actualmente Microsoft solo emite `"1"`), y cada intercambio cuya respuesta llevaba el campo `foci`.
### BroCI
Los intercambios de Nested App Authentication. Para cada uno: la app broker (`brk_client_id`), el cliente anidado (`client_id`), la evidencia que desencadenó la detección (`brk_client_id`, `brk_redirect_uri`, URI de redirección `brk-<guid>://`), y las huellas de los tokens de entrada / salida.
### Graph
`flowchart LR` de Mermaid de las relaciones token ↔ servicio. Los refresh tokens se dibujan como cilindros, los access / id tokens como estadios. Las aristas muestran emisión, presentación, intercambio y rotación. El resaltado (desde la pestaña Tokens) añade un acento amarillo; el aislamiento re-renderiza el grafo con solo los tokens seleccionados y los tokens con los que intercambian.
### Sequence
Diagrama de secuencia Mermaid de cada evento en orden de captura. Seleccionar un solo token muestra solo su secuencia; seleccionar varios mantiene la vista completa pero marca con estrella los tokens seleccionados. Límite máximo de eventos configurable (por defecto 200; los diagramas de secuencia Mermaid se vuelven ilegibles pasados unos cientos de mensajes).
---
## Soporte específico de Microsoft
### Family of Client IDs (FOCI)
Microsoft permite que un refresh token emitido para una app de una "familia" sea canjeado en el endpoint de token por **cualquier otra app** de la misma familia. La herramienta detecta FOCI en el tráfico analizando el JSON de respuesta del endpoint de token en busca de un campo `foci` (actualmente siempre `"1"` para la única familia conocida). Los refresh tokens emitidos en dicha respuesta se etiquetan con el id de familia y se muestran en la pestaña dedicada **FOCI**.
Si `--enrich` está habilitado, la columna de app del inventario también muestra el flag `foci: true/false` de `firstpartyscopes.json` — tenga en cuenta que esto puede discrepar con la detección en el tráfico (el dataset de entrascopes a veces es conservador). El campo `foci` en el tráfico es siempre la señal autoritativa.
### Brokered Client Init / Nested App Authentication (BroCI / NAA)
Los complementos de Office, las apps de Teams y el Azure Portal usan NAA para adquirir tokens para un cliente anidado a través de una app broker. La herramienta detecta esto en el lado de la petición mediante:
* el parámetro de formulario `brk_client_id` (GUID de la app broker),
* el parámetro de formulario `brk_redirect_uri` (URI de redirección real del broker),
* un `redirect_uri` de la forma `brk-<guid>://...` (donde `<guid>` es el broker).
El claim `appid` / `azp` del access token resultante es el cliente anidado; el broker solo aparece en el tráfico — nunca como claim JWT. El dashboard muestra ambos lados claramente.
### Cookies de sesión `ESTSAUTH`
`ESTSAUTH`, `ESTSAUTHPERSISTENT`, `ESTSAUTHLIGHT` y `SignInStateCookie` son cookies de sesión de Microsoft Entra que no viajan en `Authorization: Bearer` pero son usadas por el navegador para acuñar nuevos access tokens mediante flujos de autenticación silenciosa. La herramienta las etiqueta como `refresh` (su rol funcional) en lugar de dejar que la regla genérica de subcadena `auth` las clasifique erróneamente como `access`.
### Enriquecimiento de entrascopes.com (`--enrich`)
Obtiene y cachea `firstpartyscopes.json` (~2.8 MB; 504 apps first-party con su flag FOCI, URIs de redirección, scopes y capacidad de broker) y `resources.json` (~170 KB; más de 1,750 mapeos de recurso → nombre para mostrar) desde <https://entrascopes.com/>. La caché vive en:
| Variable | Por defecto |
|---|---|
| `$TATS_CACHE` | (máxima prioridad; `$BURP_TOKEN_TRACKER_CACHE` se acepta como fallback para migración de una release) |
| `$XDG_CACHE_HOME/tats` | (Linux/macOS) |
| `%LOCALAPPDATA%\tats\cache` | (Windows) |
| `~/.cache/tats` | (fallback) |
El TTL es de 7 días. Use `--no-enrich-cache` para forzar un re-fetch. La caché se reutiliza como fallback obsoleto cuando la herramienta se ejecuta sin conexión.
Cuando `--enrich` está activado, cada GUID de `appid` / `azp` / `client_id` y cada claim `aud` que sea GUID o URL se resuelve a un nombre amigable con un enlace clicable `https://entrascopes.com/?appId=<guid>`.
---
## Arquitectura
### One-shot: archivo → DB → interfaz web```
burp.xml ─┐
.mitm ─┼─→ Tracker ─→ ingest_to_db ─→ tokens.db ─→ Store ─→ /api/data ─→ dashboard
CDP WS ─┘ ▲ │
(live, repeated) └───── --append upserts on every flush ─┘
Cada ruta de origen produce el mismo objeto Tracker. ingest_to_db
lo convierte en filas de la base de datos. Store lee la base de datos para el
servidor HTTP, que expone JSON a través de /api/data, /api/meta,
/api/token/<fp>, /api/export, /api/graph y /api/sequence.
tokens (clave primaria fp) — huella, prefijo de muestra, tipo,
formato, tiempo de vida observado, cabecera / payload JWT como JSON, campos
de enriquecimiento, campos derivados (user_identity, exp_unix, tenant_id,
scopes_text), source_tag separado por comas, raw (cadena de token
completa, NULL a menos que se ingiera con --store-tokens) y
security_features (JSON compacto que describe los marcadores CAE / PoP /
step-up detectados — véase la tarjeta Security features).
Las bases de datos v2 / v3 más antiguas se migran automáticamente al reabrirse en modo append:
v2 → v3 añade la columna raw anulable; v3 → v4 añade la columna
security_features anulable y la rellena desde el jwt_payload_json almacenado de cada token
en la primera apertura. Las filas preexistentes mantienen ambas
columnas con sus valores anteriores.events — cada interacción de token observada: petición /
respuesta HTTP o frame WebSocket. Roles: issued / returned /
presented / used / exchanged-in / ws-frame-sent /
ws-frame-received. Lleva ws_session_id para agrupar frames
dentro de una conexión.exchanges — cuando una petición con token a un endpoint de token
produjo nuevos tokens en su respuesta. Registra metadatos FOCI / BroCI.exchange_inputs, exchange_outputs — huellas de token en
cada lado de cada intercambio.hosts — etiquetas host:port distintas.meta — versión del esquema, lista de fuentes, generated_at, last_modified
(usado por el sondeo en vivo del dashboard), recuentos.Cada fila escrita en la BD lleva un source_tag — por defecto
burp:<filename>, mitm:<filename> o cdp:<host>:<port>, pero
sobrescribible mediante --source-tag. Cuando la misma huella es vista por
más de una pasada de ingesta, el campo source_tag se acumula como una
lista separada por comas, de modo que la tarjeta Sources del dashboard puede mostrar
la procedencia de cada token.
--append conserva una BD existente y fusiona en ella mediante UPSERT para
tokens (el recuento de usos + el tiempo de vida observado se acumulan, los tipos desconocidos
se actualizan) e INSERT para eventos / exchanges (con sus números seq
desplazados más allá del máximo existente, para que la línea temporal de actividad se mantenga
monótona). La discrepancia de versión del esquema rechaza la fusión para prevenir la pérdida
silenciosa de datos.
El endpoint /api/meta del servidor web devuelve la tabla meta (~200
bytes). El dashboard lo sondea cada 5 segundos y solo vuelve a obtener el
/api/data completo cuando last_modified cambia. La ruta de ingesta cdp
vuelca su tracker en memoria a la BD cada 25 eventos por defecto, por lo que
la latencia de reloj de pared desde una petición del navegador hasta una actualización del dashboard es
típicamente < 10 segundos.
.burp de Burp no son compatibles. Use Save items para
producir el XML que consume la herramienta.alg=none y los ataques de confusión de claves
quedan fuera del alcance. Use un auditor de JWT dedicado para eso.unknown y se ocultan por defecto
a menos que se establezca --include-unknown en el flag más antiguo (solo para Burp).--enrich realiza peticiones HTTP salientes a
https://entrascopes.com/. Omita el flag si su entorno no
lo permite.| Síntoma | Causa probable | Solución |
|---|---|---|
error: could not parse <file> as XML | Intentar ingerir un archivo de proyecto .burp binario | En Burp: Proxy → HTTP history → seleccionar elementos → clic derecho → Save items |
error: no <item> elements found | El XML no fue producido por Save items de Burp | Reexportar desde Burp; el elemento raíz debería ser <items> |
error: cannot append to DB with schema_version 1 | La BD fue creada por una compilación anterior | Eliminar la BD y volver a ingerir las fuentes originales; la migración de esquema intencionadamente no es automática |
error: the 'mitm' source needs the mitmproxy Python package | mitmproxy no está instalado | pip install mitmproxy |
error: cannot reach Chrome at 127.0.0.1:9222 | Chrome no se inició con --remote-debugging-port | Véase el conjuro de lanzamiento en cdp subcommand |
| CDP se conecta pero no fluyen eventos | La página aún no ha realizado ninguna petición de red, o toda la actividad está en un OOPIF / worker (no conectado automáticamente) | Recargue la página; confirme que las pestañas se registraron (busque líneas de log tab attached: … en stderr) |
no browser-level webSocketDebuggerUrl at /json/version | La versión de Chrome es demasiado antigua para CDP a nivel de navegador, o devolvió la forma incorrecta | Actualice Chrome, o pase --target <id> para usar la conexión heredada de una sola pestaña |
target … has no webSocketDebuggerUrl | Otro depurador (p. ej. la ventana de DevTools) ya está conectado | Cierre DevTools, o conéctese a un target diferente |
El dashboard muestra Failed to load /api/data | El servidor no puede leer el archivo de base de datos | Compruebe que la ruta de la BD es correcta, que el archivo es legible y que la versión del esquema coincide |
| Las actualizaciones en vivo dejan de llegar | El proceso cdp terminó o el volcado del búfer de red aún no se ha disparado | Compruebe la terminal de en busca de errores; reduzca para actualizaciones más ágiles |
Hay dos constructores de fixtures en 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
Después de ambas ejecuciones, `tokens.db` tiene 15 tokens (11 de Burp + 4 de
mitmproxy), 23 eventos incluyendo un evento de trama WebSocket, y 3
intercambios.
### Suite de pruebas```bash
pip install .[test]
pytest
La suite cubre la extracción de tokens, el análisis de JWT, la
clasificación de cookies de sesión de Microsoft, la detección de FOCI / BroCI, el resumen de claims, la redacción de PII,
la ruta de ingesta de XML de Burp con semántica UPSERT en modo append, y la
ruta de ingesta de frames WebSocket de mitmproxy (omitida automáticamente cuando la dependencia opcional
mitmproxy no está presente).```text
$ pytest tests/
============================= test session starts =============================
…
======================== 62 passed in 1.4s =================================
### Ejecutar el servidor en primer plano```bash
tats serve tokens.db --no-browser
…y abre http://127.0.0.1:8765 manualmente. El servidor registra cada
petición y cualquier error del manejador en stderr.
| Ruta | Propósito |
|---|---|
tats/__init__.py | La herramienta completa — parsers, capa de BD, servidor HTTP, cliente CDP; carga el dashboard desde tats/static/ |
tats/__main__.py | Punto de entrada para python -m tats; misma lógica que el script de consola tats instalado |
tats/static/index.html | Esqueleto HTML del dashboard con marcadores {{CSS}} / {{JS}} |
tats/static/style.css | Estilos del dashboard — edítalos con tus herramientas CSS habituales |
tats/static/app.js | Lógica del dashboard — edítala con tus herramientas JS habituales (LSP / lint / formatter) |
pyproject.toml | Metadatos de empaquetado, extras opcionales ([mitm], [test], [all]), punto de entrada de consola |
LICENSE | GNU General Public License v3 |
README.md | Este archivo |
examples/ | Capturas sintéticas + scripts generadores de fixtures (ver examples/README.md) |
examples/make_fixture.py | Generador sintético de XML de Burp |
examples/make_mitm_fixture.py | Generador sintético de archivos de flujo de mitmproxy |
examples/fixture.xml | Fixture XML de Burp preconstruido |
examples/fixture.mitm | Fixture de flujo de mitmproxy preconstruido |
tests/ | Suite de pytest (ejecutar con pytest) |
La estructura de archivo único es deliberada: la herramienta está pensada para ser leída, auditada y usada en investigaciones por cualquiera que tenga Python instalado. No hay configuración oculta, ni árbol de dependencias que evaluar, ni ninguna superficie más allá del propio archivo.
Si cambias subcomandos, esquema, tarjetas del dashboard o la superficie
de API pública (flags de CLI, endpoints /api/*), actualiza las secciones relevantes
de este archivo en el mismo cambio. Las secciones con más probabilidad de quedar desactualizadas:
GNU General Public License v3.0 o posterior — texto completo en el
archivo LICENSE en la raíz del repositorio. El código fuente del script incluye el
encabezado corto estándar que apunta al mismo.
Puedes redistribuir y/o modificar la herramienta bajo los términos de la GPL v3 (o cualquier versión posterior, a tu elección). Se distribuye sin ninguna garantía; consulta la LICENSE para los términos completos.
appidaud/api/export?fps=... devolviendo hasta 200 tokens (raw, claims,
eventos, intercambios) en un único paquete JSON para herramientas posteriores.Activar esto convierte la base de datos en una credencial al por mayor — cada
byte necesario para reproducir cualquier sesión capturada está en ella. Combínalo con
--redact-claims para limpiar la vista JWT decodificada, pero ten en cuenta que el
token sin procesar aún lleva las claims sin redactar codificadas dentro de él.
Cuando el flag está desactivado, el bloque de vista previa de comandos del panel aún
se renderiza, solo que con <TOKEN> como marcador de posición para que funcione como
referencia de sintaxis; los botones de exportación muestran una pista para re-ingerir.
cdp--flush-every