
Анализируйте и отслеживайте токены OAuth 2.0, OIDC и Microsoft Entra ID из перехватов Burp, mitmproxy или Chrome DevTools. Визуализируйте жизненные циклы токенов, обнаруживайте рискованные области доступа и экспортируйте токены для повторного воспроизведения через интерактивную панель управления.
Отслеживание токенов OAuth 2.0, OIDC и Microsoft Entra ID в перехваченном сетевом трафике. Принимает XML-экспорты Burp Suite, файлы потоков mitmproxy или живые потоки Chrome DevTools Protocol в единую базу данных SQLite, а затем предоставляет интерактивную веб-панель для фильтрации токенов, просмотра обменов, выявления рискованных областей действия (scopes), экспорта токенов для воспроизведения и визуализации жизненных циклов токенов в виде графов Mermaid.
Статус: TATS стабилен для персонального использования / использования в рамках проектов. Оптимизирован для экосистемы Microsoft 365 / Entra (FOCI, BroCI/NAA, сессионные cookie ESTSAUTH, обогащение через entrascopes.com), но работает с любым более-менее стандартным трафиком OAuth/OIDC.
Когда вы проксируете длительную сессию Microsoft 365 или Azure через Burp / mitmproxy, полученный перехват оказывается огромным, и большинство инструментов либо:
Этот инструмент извлекает каждый обнаруженный access / refresh / id токен, вычисляет их отпечатки для сопоставления одного и того же токена из разных источников, декодирует утверждения (claims) JWT, сопоставляет GUID клиентов / ресурсов Microsoft с entrascopes.com и отображает всю картину в виде единой панели — включая представление цепочек refresh-токенов, которое отслеживает кросс-приложенческие обмены FOCI и выдачу вложенных токенов BroCI.
Этот проект предназначен в первую очередь для исследований и обучения, но предоставляет такие возможности, как предпросмотр команд и экспорт токенов, которые могут поддержать некоторые наступательные инструменты.
ingest — XML-экспорт «Save items» из Burp Suitemitm — файл потоков .mitm из mitmproxy (HTTP и кадры WebSocket)cdp — живое подключение к Chrome / Edge через DevTools Protocol
(в реальном времени перехватывает расшифрованный TLS HTTP и кадры WebSocket
без проксирующего CA; отслеживает каждую существующую вкладку И каждую вкладку,
открытую во время запуска, через авто-подключение на уровне браузера)--append для слияния с существующей базой данных;
токены обновляются (upsert — счётчик использований + наблюдаемое время жизни
накапливаются), события и обмены добавляются, а source_tag строки фиксирует каждый
проход, в котором встречался токен.pip install mitmproxy).access_token, refresh_token, id_token) и
эвристики по именам cookie определяют тип токена.ESTSAUTH, ESTSAUTHPERSISTENT,
ESTSAUTHLIGHT, SignInStateCookie) явно распознаются как
refresh-эквивалентные токены (иначе они были бы неверно классифицированы
общей подсказкой cookie «auth»).foci
в ответах token-endpoint.brk_client_id, brk_redirect_uri и схемам перенаправления brk-<guid>://
в теле запроса.--enrich загружает firstpartyscopes.json и
resources.json с https://entrascopes.com/ и сопоставляет GUID appid /
azp / aud с понятными именами и кликабельными ссылками.upn / preferred_username /
unique_name / email / name с откатом к sub@iss или oid
и отдельным отображением групп только-приложений и неизвестных идентичностей. Каждая
строка идентичности показывает значок captures, когда пользователь встречается
в ≥2 source_tag (выживание между захватами — главный исследовательский сигнал
--append), а также диапазон first_seen → last_seen и кнопку
timeline, которая подсвечивает все токены этого пользователя на
вкладке диаграммы последовательности.appid / azp / client_id из тела формы
/ brk_client_id / brk_nested_id), встречающееся в
обменах, со значками FOCI / brokerable / broker / nested.aud, сопоставленное с именами
ресурсов entrascopes, где это возможно.tid с количеством токенов / пользователей / приложений.scp / scope /
roles каждого токена по курируемому списку наблюдения высокозначимых разрешений
Microsoft Graph и областей действия ресурсов Azure.(token, host), где
токен использовался на хосте, не соответствующем его утверждению aud
(указывает на утечку или неправомерное использование учётных данных).amr) — распределение pwd / mfa / pop /
smartcard.xms_cc=CP1),
привязку proof-of-possession (утверждение cnf, с обнаружением общего kid
между аудиториями), требования step-up аутентификации (acrs) и уровень
контекста аутентификации acr. Каждая строка кликабельна и фильтрует
вкладку Tokens, оставляя только токены с этим маркером.⚠ priv — исследовательский сигнал расширения привилегий
в стиле FOCI / BroCI.source_tag, чтобы видеть, сколько
строк пришло из каждого прохода приёма данных.roadtx describe,
roadtx auth, curl, Python requests и PowerShell
Invoke-RestMethod.ws-frame-sent /
ws-frame-received, источником ws[body_json[<key>]] и
ws_session_id, который группирует все кадры в одном соединении WebSocket.База данных хранит отпечатки SHA-256 (первые 12 шестнадцатеричных символов) и 12-символьный префикс каждого наблюдаемого токена. Полные строки токенов никогда не покидают входной файл.
Декодированное содержимое утверждений JWT (заголовок + полезная нагрузка, включая
oid, sub, upn, email, tid, списки областей действия и т. д.) по умолчанию
сохраняется дословно, поскольку в этом весь смысл анализа. Относитесь к базе данных
и любому публикуемому URL панели как к конфиденциальным, когда присутствуют JWT.
--redact-claims (доступен для ingest, mitm и cdp)
заменяет перечисленные значения утверждений на стабильные хэш-заполнители, прежде чем
они вообще попадут в базу данных. Список полей по умолчанию охватывает sub, oid,
upn, email, name, unique_name, preferred_username, emails,
mail, ipaddr, given_name, family_name. Передайте явный
список через запятую (например, --redact-claims sub,upn,oid), чтобы переопределить
значение по умолчанию. Один и тот же ввод всегда сопоставляется с одним и тем же
заполнителем, поэтому группировка Users / Tenants на панели по-прежнему работает,
не раскрывая пользователя.
--store-tokens (доступен для ingest, mitm и cdp,
по умолчанию выключен) включает запись полной строки токена в
базу данных, чтобы панель могла предложить:
.roadtools_auth, и любая подкоманда roadtx его подхватит).roadtx describe, roadtx auth, curl,
Python requests, PowerShell Invoke-RestMethod — используя
фактические утверждения tid, appid и токена.dataclasses). Протестировано на 3.12.python -m tats напрямую.| Нужно | Установка |
|---|---|
Подкоманда mitm | pip install mitmproxy |
| Живой захват из Chrome / Edge | Нет — использует клиент WebSocket из стандартной библиотеки |
--enrich (entrascopes.com) | Нет — использует urllib.request |
Запуск из клонированного репозитория (без установки):```bash git clone tats cd tats python -m tats --help
HTML / CSS / JS дашборда находятся в `tats/static/` и загружаются
при первом импорте, поэтому шаг сборки не требуется — просто запустите модуль
напрямую из рабочей копии.
**Установка в качестве пакета (даёт вам консольный скрипт `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
После установки вы можете вызвать инструмент по его короткому имени:```bash tats ingest engagement.xml -o tokens.db --enrich tats serve tokens.db
Если вам нужны только пути Burp / CDP, файл полностью самодостаточен
со стандартной библиотекой Python — установка или дополнительные компоненты не требуются.
---
## Быстрый старт
**Проанализируйте экспорт Burp XML и откройте панель управления:**```bash
tats ingest examples/fixture.xml -o tokens.db --enrich
tats serve tokens.db
Объедините захват Burp с файлом потока mitmproxy в одной БД:```bash tats ingest engagement.xml -o tokens.db --enrich tats mitm chat-session.mitm -o tokens.db --enrich --append tats serve tokens.db
**Захват в реальном времени из браузера Chrome (видит HTTP + кадры WebSocket после расшифровки TLS, прокси-CA не требуется) — с запуском браузера инструментом:**```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
Запущенный браузер завершается, и его временный профиль удаляется,
когда вы нажимаете Ctrl-C для команды cdp.
Если вы предпочитаете подключиться к уже запущенному браузеру, запустите его с
--remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile и выполните
cdp без --launch-chrome.
Очистка базы данных перед её передачей (редактирование PII):```bash
tats ingest engagement.xml -o tokens.db
--enrich --redact-claims
Редактирование является стабильным по содержимому: идентичные значения сопоставляются с идентичными
заполнителями, поэтому группировка по пользователям на панели мониторинга по-прежнему работает без
отображения пользователя.
В заголовке панели мониторинга отображается `live · updated <time>`, как только данные начинают
поступать.
---
## Подкоманды
Каждая подкоманда принимает `--help` для получения канонического списка опций. Приведённые ниже
заметки объясняют, *когда* и *как* вы будете обращаться к каждой из них.
### Глобальные флаги
Они применяются к каждой подкоманде и указываются *перед* именем подкоманды:
* `-v` / `--verbose` — добавляет строки логов уровня INFO (статус обогащения, счётчики
редактирования при приёме данных). `-vv` добавляет DEBUG (каждый запрос к серверу).
* `-q` / `--quiet` — заглушает строки логов уровня INFO; отображаются только WARNING и ERROR.
Финальная строка вывода для пользователя (например, `wrote tokens.db (...)`) и
любые диагностические сообщения `error: …` не затрагиваются, так что вы всё равно увидите то, что
важно, из скрипта.
* `--version` — вывести версию инструмента и завершить работу.
### `ingest` — экспорт XML из Burp Suite
Читает XML-файл "Save items" (Proxy → HTTP history → правый клик → Save items).
Бинарные файлы проектов `.burp` **не** поддерживаются — формат является
проприетарным и нестабильным между версиями Burp; экспорт нужных вам элементов — это поддерживаемый рабочий процесс.```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]
Примеры:```bash
tats ingest burp.xml -o tokens.db --enrich
tats ingest day2.xml -o tokens.db --append
--source-tag burp:day2
### `mitm` — файл потоков `.mitm` от mitmproxy
Читает файл потоков, созданный `mitmdump`, `mitmproxy` или `mitmweb`. Это
единственный путь приёма, который захватывает **кадры WebSocket** без живой
сессии браузера — файлы потоков сохраняют полезную нагрузку каждого текстового / бинарного кадра.```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]
Требуется pip install mitmproxy. Инструмент выдаст понятную ошибку, если
пакет отсутствует.
Захватите файл потока с помощью mitmproxy:```bash mitmdump -w session.mitm
tats mitm session.mitm -o tokens.db --enrich
### `cdp` — живое подключение к Chrome / Edge
Подключается к запущенному браузеру семейства Chromium через DevTools Protocol
и передаёт события `Network.*` в базу данных. Захватывает HTTP-запросы /
ответы (с телами, получаемыми через `Network.getResponseBody`), апгрейды
WebSocket и каждый кадр WebSocket в обоих направлениях. Буфер сбрасывается в
базу данных каждые N событий (по умолчанию 25), поэтому 5-секундный
опрос дашборда подхватывает новые токены в течение нескольких секунд после того,
как браузер выполнит запрос.```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
Запущенный браузер работает с `--remote-debugging-port=<port>` и
свежим временным каталогом пользовательских данных. Когда вы останавливаете команду `cdp` (Ctrl-C),
браузер завершается, а временный профиль удаляется.
### Подключение к уже запущенному браузеру
Запустите браузер самостоятельно со свежим профилем, затем выполните `cdp` без
`--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
Отдельный user-data-dir позволяет избежать привязки к личному профилю и не даёт запущенному браузеру отклонить флаг отладки.
По умолчанию cdp подключается на уровне браузера и отслеживает каждую вкладку,
существующую на момент запуска, А ТАКЖЕ каждую вкладку, открытую во время работы
(window.open, Ctrl-click, кнопка новой вкладки). Все вкладки используют единый
WebSocket через мультиплексор сессий CDP flat-protocol, поэтому открытие или
закрытие вкладок во время захвата полностью поддерживается. Каждое подключение
/ отключение вкладки выводит однострочное уведомление в stderr на уровне INFO.
Если вы предпочитаете закрепиться за одной вкладкой и завершать подключение, когда эта вкладка закрывается, выведите список доступных целей:```bash curl http://127.0.0.1:9222/json/list
…затем передайте `--target <id>`.
Нажмите Ctrl-C, чтобы остановить. Хвост любого буфера в обработке сбрасывается в
базу данных перед завершением процесса.
### `serve` — веб-панель
Читает существующую базу данных и обслуживает одностраничный веб-интерфейс на
`127.0.0.1:8765`. Сервер работает только для чтения; он никогда не записывает в
базу данных, поэтому его безопасно запускать параллельно с активным приёмом данных
`cdp` или `mitm`.```bash
tats serve <tokens.db> \
[--host 127.0.0.1] [--port 8765] [--no-browser]
Примеры:```bash
tats serve tokens.db
tats serve tokens.db --port 9000 --no-browser
tats serve tokens.db --host 0.0.0.0
> **Внимание:** веб-интерфейс раскрывает декодированные полезные нагрузки JWT (утверждения), отпечатки токенов, временную шкалу активности и графики Mermaid любому, кто может достичь адреса привязки. Если вы выполнили импорт с `--store-tokens`, он также раскрывает **полные необработанные токены** через `/api/token/<fp>` и `/api/export?fps=...`. Здесь **нет аутентификации**. Оставляйте `--host` на `127.0.0.1`, если вы специально не намереваетесь иного.
#### Экспорт, готовый к воспроизведению
Когда база данных была построена с `--store-tokens`, каждый развёрнутый токен на вкладке Tokens получает строку действий в один клик:
* **Copy raw** — полная строка токена в буфер обмена.
* **Copy Bearer header** — `Authorization: Bearer <token>`, готово к вставке.
* **Copy curl example** — однострочник, нацеленный на `aud` токена (или его хост-издатель) с прикреплённым заголовком bearer.
* **Download JSON** — JSON-файл одного токена, содержащий raw, claims, наблюдаемые события и обмены.
* **Copy as roadtx** — JSON-форма кэша токенов roadtools (`tokenType`, `accessToken` / `refreshToken` / `idToken`, `expiresOn`, `tenantId`, `_clientId`, `resource`, `foci`, `scope`). Вставляйте прямо в файл `.roadtools_auth`.
* **Download .roadtools_auth** — та же полезная нагрузка, скачанная как файл. Переименуйте его в `.roadtools_auth` (или передайте через `roadtx <cmd> --tokens-file`), и любая подкоманда roadtx его подхватит.
Панель инструментов вкладки Tokens также имеет **Export selected for replay**, которая обращается к `/api/export?fps=fp1,fp2,...` и скачивает единый JSON-документ с до 200 токенами (raw, claims, events) в одном пакете. Без `--store-tokens` те же кнопки отображают подсказку о необходимости повторного импорта, прежде чем экспорт, готовый к воспроизведению, станет возможным.
#### Предпросмотр команд
Каждый развёрнутый токен также имеет сворачиваемый блок **Command preview**, который предварительно заполняет наиболее распространённые вызовы для воспроизведения / инспекции, используя фактические утверждения токена (и полное необработанное значение, когда `--store-tokens` включён). Каждый фрагмент имеет кнопку Copy в один клик. Точный набор зависит от типа токена:
* **Любой JWT:** `roadtx describe -t '<token>'` (декодирование без сети).
* **Refresh-токены:**
* `roadtx auth --refresh-token '...' -c <client_id> -t <tenant_id>` — обмен refresh-токена на свежие access-токены.
* `curl -X POST .../oauth2/v2.0/token` — OAuth-эквивалент для пользователей, не использующих roadtx.
* **Access / id / неизвестные токены:**
* `curl -H 'Authorization: Bearer ...' '<aud>'`
* Python `requests.get(...)` с установленным заголовком bearer.
* PowerShell `Invoke-RestMethod` с тем же заголовком.
* **Всегда:** JSON-объект для вставки в `.roadtools_auth`.
Когда `--store-tokens` выключен, фрагменты отображаются с `<TOKEN>` в качестве заполнителя, так что панель всё ещё полезна как справочник по документации.
---
## Веб-интерфейс подробно
### Верхняя навигация
`Summary | Tokens | Exchanges | FOCI | BroCI | Graph | Sequence`
Каждая вкладка отображается независимо из одного и того же снимка в памяти `/api/data`. Переключение вкладок мгновенно; граф и диаграммы последовательностей перерисовываются по требованию и учитывают текущий выбор на вкладке Tokens.
### Summary
Плитки статистики в верхней части (tokens / access / refresh / id / unknown / used / unused / events / exchanges / FOCI exchanges / BroCI exchanges / hosts), за которыми следует сетка карточек, описанных в
[Features → Dashboard cards](#dashboard-cards).
Щёлкните любую строку в любой карточке, чтобы перейти к предварительно отфильтрованной вкладке Tokens — например, щелчок по строке тенанта фильтрует инвентарь до токенов, несущих этот `tid`.
### Tokens
Фильтруемый, сортируемый инвентарь. Множественный выбор управляет кнопками highlight / isolate / sequence. Развёртывание строки показывает полный декодированный JWT (заголовок + полезная нагрузка как необработанный JSON), каждое событие, связанное с этим токеном, и каждый обмен, где он был входом или выходом.
### Exchanges
Сортируемый список каждого обнаруженного обмена токен-на-токен — ротации refresh-токенов, кросс-погашения FOCI и вложенные обмены приложений BroCI. Столбец BroCI показывает broker + вложенные client ID рядом с доказательством, вызвавшим обнаружение.
### FOCI
Две таблицы: каждый refresh-токен, помеченный семейством FOCI (в настоящее время Microsoft выдаёт только `"1"`), и каждый обмен, ответ которого нёс поле `foci`.
### BroCI
Обмены Nested App Authentication. Для каждого: приложение-брокер (`brk_client_id`), вложенный клиент (`client_id`), доказательство, вызвавшее обнаружение (`brk_client_id`, `brk_redirect_uri`, redirect URI `brk-<guid>://`), и отпечатки входного / выходного токена.
### Graph
Mermaid `flowchart LR` отношений токен ↔ сервис. Refresh-токены рисуются как цилиндры, access / id токены как стадионы. Рёбра показывают выдачу, представление, обмен и ротацию. Подсветка (со вкладки Tokens) добавляет жёлтый акцент; изоляция перерисовывает граф только с выбранными токенами и токенами, с которыми они обмениваются.
### Sequence
Диаграмма последовательности Mermaid каждого события в порядке захвата. Выбор одного токена показывает только его последовательность; выбор нескольких сохраняет полный вид, но отмечает выбранные токены звёздочкой. Настраиваемый лимит максимального числа событий (по умолчанию 200; диаграммы последовательностей Mermaid становятся нечитаемыми после нескольких сотен сообщений).
---
## Поддержка, специфичная для Microsoft
### Family of Client IDs (FOCI)
Microsoft разрешает refresh-токен, выданный одному приложению в «семействе», погашать в token endpoint **любым другим приложением** того же семейства. Инструмент обнаруживает FOCI на проводе, разбирая JSON ответа token endpoint на наличие поля `foci` (в настоящее время всегда `"1"` для единственного известного семейства). Refresh-токены, выданные в таком ответе, помечаются идентификатором семейства и отображаются на выделенной вкладке **FOCI**.
Если включён `--enrich`, столбец приложения в инвентаре также показывает флаг `foci: true/false` из `firstpartyscopes.json` — обратите внимание, что это может расходиться с обнаружением на проводе (набор данных entrascopes иногда консервативен). Поле `foci` на проводе всегда является авторитетным сигналом.
### Brokered Client Init / Nested App Authentication (BroCI / NAA)
Надстройки Office, приложения Teams и Azure Portal используют NAA для получения токенов для вложенного клиента через приложение-брокер. Инструмент обнаруживает это на стороне запроса через:
* параметр формы `brk_client_id` (GUID приложения-брокера),
* параметр формы `brk_redirect_uri` (фактический redirect URI брокера),
* `redirect_uri` вида `brk-<guid>://...` (где `<guid>` — брокер).
Утверждение `appid` / `azp` результирующего access-токена — это вложенный клиент; брокер появляется только на проводе — никогда как утверждение JWT. Дашборд чётко отображает обе стороны.
### Сессионные cookie `ESTSAUTH`
`ESTSAUTH`, `ESTSAUTHPERSISTENT`, `ESTSAUTHLIGHT` и `SignInStateCookie` — это сессионные cookie Microsoft Entra, которые не передаются в `Authorization: Bearer`, но используются браузером для создания новых access-токенов через потоки silent-auth. Инструмент помечает их как `refresh` (их функциональная роль) вместо того, чтобы позволить общему правилу подстроки `auth` ошибочно классифицировать их как `access`.
### Обогащение entrascopes.com (`--enrich`)
Извлекает и кэширует `firstpartyscopes.json` (~2,8 МБ; 504 приложения первой стороны с их флагом FOCI, redirect URI, scope и возможностью брокера) и `resources.json` (~170 КБ; 1 750+ сопоставлений ресурс → отображаемое имя) с <https://entrascopes.com/>. Кэш находится в:
| Переменная | По умолчанию |
|---|---|
| `$TATS_CACHE` | (наивысший приоритет; `$BURP_TOKEN_TRACKER_CACHE` поддерживается как запасной вариант для миграции одного релиза) |
| `$XDG_CACHE_HOME/tats` | (Linux/macOS) |
| `%LOCALAPPDATA%\tats\cache` | (Windows) |
| `~/.cache/tats` | (запасной вариант) |
TTL составляет 7 дней. Используйте `--no-enrich-cache`, чтобы принудительно выполнить повторную выборку. Кэш повторно используется как устаревший запасной вариант, когда инструмент запускается офлайн.
Когда `--enrich` включён, каждый GUID `appid` / `azp` / `client_id` и каждое утверждение `aud` в виде GUID-или-URL разрешается в понятное имя с кликабельной ссылкой `https://entrascopes.com/?appId=<guid>`.
---
## Архитектура
### One-shot: файл → БД → веб-интерфейс```
burp.xml ─┐
.mitm ─┼─→ Tracker ─→ ingest_to_db ─→ tokens.db ─→ Store ─→ /api/data ─→ dashboard
CDP WS ─┘ ▲ │
(live, repeated) └───── --append upserts on every flush ─┘
Каждый исходный путь создаёт один и тот же объект Tracker. ingest_to_db
превращает его в строки в базе данных. Store читает базу данных для
HTTP-сервера, который предоставляет JSON через /api/data, /api/meta,
/api/token/<fp>, /api/export, /api/graph и /api/sequence.
tokens (первичный ключ fp) — отпечаток, префикс образца, тип,
формат, наблюдаемое время жизни, заголовок / полезная нагрузка JWT в формате JSON, поля обогащения,
производные поля (user_identity, exp_unix, tenant_id,
scopes_text), source_tag в виде списка через запятую, raw (полная строка токена,
NULL, если не был выполнен ingest с --store-tokens), и
security_features (компактный JSON, описывающий обнаруженные маркеры CAE / PoP /
step-up — см. карточку Security features).
Более старые базы данных v2 / v3 автоматически мигрируют при повторном открытии в режиме append:
v2 → v3 добавляет nullable-столбец raw; v3 → v4 добавляет nullable-столбец
security_features и заполняет его из сохранённого для каждого токена
jwt_payload_json при первом открытии. Существующие строки сохраняют оба
столбца с их предыдущими значениями.events — каждое наблюдаемое взаимодействие с токеном: HTTP-запрос /
ответ или WebSocket-фрейм. Роли: issued / returned /
presented / used / exchanged-in / ws-frame-sent /
ws-frame-received. Содержит ws_session_id для группировки фреймов
в рамках соединения.exchanges — когда запрос с токеном к token endpoint
породил новые токены в своём ответе. Записывает метаданные FOCI / BroCI.exchange_inputs, exchange_outputs — отпечатки токенов на
каждой стороне каждого обмена.hosts — различные метки host:port.meta — версия схемы, список источников, generated_at, last_modified
(используется живым опросом дашборда), счётчики.Каждая строка, записанная в БД, несёт source_tag — по умолчанию
burp:<filename>, mitm:<filename> или cdp:<host>:<port>, но
переопределяемый через --source-tag. Когда один и тот же отпечаток встречается
в более чем одном проходе ingest, поле source_tag накапливается как
список через запятую, так что карточка Sources дашборда может показать
происхождение для каждого токена.
--append сохраняет существующую БД и выполняет слияние в неё через UPSERT для
токенов (счётчик использований + наблюдаемое время жизни накапливаются, неизвестные типы
повышаются) и INSERT для событий / обменов (с их номерами seq, смещёнными за
существующий максимум, так что временная шкала активности остаётся
монотонной). Несовпадение версии схемы отклоняет слияние, чтобы предотвратить молчаливую
потерю данных.
Эндпоинт /api/meta веб-сервера возвращает таблицу meta (~200
байт). Дашборд опрашивает его каждые 5 секунд и повторно запрашивает полный
/api/data только когда last_modified изменяется. Путь ingest cdp сбрасывает
свой трекер в памяти в БД каждые 25 событий по умолчанию, так что
задержка по настенным часам от запроса браузера до обновления дашборда
обычно < 10 секунд.
.burp не поддерживаются. Используйте Save items, чтобы
получить XML, который потребляет инструмент.alg=none и атаки key-confusion
вне области охвата. Используйте для этого специализированный аудитор JWT.unknown и скрыты по умолчанию,
если не установлен --include-unknown на (только для Burp) старом флаге.--enrich выполняет исходящие HTTP-запросы к
https://entrascopes.com/. Пропустите флаг, если ваша среда не
допускает этого.| Симптом | Вероятная причина | Исправление |
|---|---|---|
error: could not parse <file> as XML | Попытка выполнить ingest бинарного файла проекта .burp | В Burp: Proxy → HTTP history → выберите элементы → правый клик → Save items |
error: no <item> elements found | XML не был создан функцией Save items в Burp | Повторно экспортируйте из Burp; корневой элемент должен быть <items> |
error: cannot append to DB with schema_version 1 | БД была создана более ранней сборкой | Удалите БД и повторно выполните ingest исходных источников; миграция схемы намеренно не автоматическая |
error: the 'mitm' source needs the mitmproxy Python package | mitmproxy не установлен | pip install mitmproxy |
error: cannot reach Chrome at 127.0.0.1:9222 | Chrome не был запущен с --remote-debugging-port | См. заклинание запуска в cdp subcommand |
| CDP присоединяется, но события не идут | Страница ещё не сделала никаких сетевых запросов, или вся активность в OOPIF / worker (не присоединяется автоматически) | Перезагрузите страницу; убедитесь, что вкладки были зарегистрированы (ищите строки лога tab attached: … в stderr) |
no browser-level webSocketDebuggerUrl at /json/version | Версия Chrome слишком стара для browser-level CDP, или он вернул неверную форму | Обновите Chrome или передайте --target <id>, чтобы использовать legacy-присоединение к одной вкладке |
target … has no webSocketDebuggerUrl | Другой отладчик (например, окно DevTools) уже присоединён | Закройте DevTools или присоединитесь к другой цели |
Дашборд показывает Failed to load /api/data | Сервер не может прочитать файл базы данных | Проверьте, что путь к БД правильный, файл читаемый и версия схемы совпадает |
| Живые обновления перестали приходить | Процесс cdp завершился или сброс сетевого буфера ещё не сработал | Проверьте терминал cdp на ошибки; уменьшите --flush-every для более быстрых обновлений |
Два построителя фикстур находятся в 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
После обоих запусков `tokens.db` содержит 15 токенов (11 из Burp + 4 из
mitmproxy), 23 события, включая событие WebSocket-фрейма, и 3
обмена.
### Набор тестов```bash
pip install .[test]
pytest
Набор тестов охватывает извлечение токенов, разбор JWT, классификацию сессионных cookie Microsoft, обнаружение FOCI / BroCI, сводку утверждений, редактирование PII, путь приёма Burp XML с семантикой UPSERT в режиме добавления и путь приёма кадров WebSocket mitmproxy (автоматически пропускается, когда отсутствует опциональная зависимость mitmproxy).```text
$ pytest tests/
============================= test session starts =============================
…
======================== 62 passed in 1.4s =================================
### Запуск сервера в foreground-режиме```bash
tats serve tokens.db --no-browser
…и вручную откройте http://127.0.0.1:8765. Сервер записывает каждый
запрос и любые ошибки обработчиков в stderr.
| Путь | Назначение |
|---|---|
tats/__init__.py | Весь инструмент — парсеры, слой БД, HTTP-сервер, CDP-клиент; загружает дашборд из tats/static/ |
tats/__main__.py | Точка входа для python -m tats; та же логика, что и у установленного консольного скрипта tats |
tats/static/index.html | Каркас HTML дашборда с плейсхолдерами {{CSS}} / {{JS}} |
tats/static/style.css | Стили дашборда — редактируйте обычными инструментами для CSS |
tats/static/app.js | Логика дашборда — редактируйте обычными инструментами для JS (LSP / линтер / форматтер) |
pyproject.toml | Метаданные упаковки, опциональные дополнения ([mitm], [test], [all]), точка входа консольного скрипта |
LICENSE | GNU General Public License v3 |
README.md | Этот файл |
examples/ | Синтетические захваты + скрипты сборки фикстур (см. examples/README.md) |
examples/make_fixture.py | Генератор синтетического Burp XML |
examples/make_mitm_fixture.py | Генератор синтетического файла потоков mitmproxy |
examples/fixture.xml | Готовая фикстура Burp XML |
examples/fixture.mitm | Готовая фикстура потоков mitmproxy |
tests/ | Набор тестов pytest (запуск через pytest) |
Однофайловая структура выбрана намеренно: инструмент задуман так, чтобы его мог прочитать, проверить и использовать в расследованиях любой, у кого установлен Python. Здесь нет скрытой настройки, нет дерева зависимостей для оценки и нет ничего, кроме самого файла.
Если вы меняете подкоманды, схему, карточки дашборда или публичный API
(флаги CLI, эндпоинты /api/*), обновите соответствующие разделы
этого файла в том же изменении. Разделы, которые чаще всего устаревают:
GNU General Public License v3.0 или более поздняя — полный текст в
файле LICENSE в корне репозитория. Исходный код скрипта содержит
стандартный короткий заголовок, указывающий на то же самое.
Вы можете распространять и/или изменять инструмент на условиях GPL v3 (или любой более поздней версии, на ваш выбор). Он распространяется без каких-либо гарантий; полные условия см. в LICENSE.
aud/api/export?fps=..., возвращающий до 200 токенов (raw, claims,
events, exchanges) в одном пакете JSON для последующих инструментов.Включение этого превращает базу данных в полноценные учётные данные — в ней
каждый байт, необходимый для воспроизведения любой перехваченной сессии. Сочетайте с
--redact-claims, чтобы очистить декодированное представление JWT, но учитывайте, что
сырой токен всё ещё несёт неотредактированные утверждения, закодированные внутри него.
Когда флаг выключен, блок предпросмотра команд на панели всё равно
отображается, просто с <TOKEN> в качестве заполнителя, так что он работает как
справочник по синтаксису; кнопки экспорта показывают подсказку о повторном приёме данных.