
OAuth 2.0, OIDC 및 Microsoft Entra ID 토큰을 Burp, mitmproxy 또는 Chrome DevTools 캡처에서 분석하고 추적합니다. 대화형 대시보드를 통해 토큰 수명 주기를 시각화하고, 위험한 범위를 탐지하며, 재생을 위해 토큰을 내보냅니다.
캡처된 네트워크 트래픽에서 OAuth 2.0, OIDC 및 Microsoft Entra ID 토큰을 추적합니다. Burp Suite XML 내보내기, mitmproxy 플로우 파일 또는 실시간 Chrome DevTools Protocol 스트림을 단일 SQLite 데이터베이스로 수집한 다음, 토큰 필터링, 교환 흐름 추적, 위험한 범위 식별, 재생을 위한 토큰 내보내기, 그리고 토큰 수명 주기를 Mermaid 그래프로 시각화하는 대화형 웹 대시보드를 제공합니다.
상태: TATS는 개인/엔지니어링 사용에 안정적입니다. Microsoft 365 / Entra 에코시스템(FOCI, BroCI/NAA, ESTSAUTH 세션 쿠키, entrascopes.com 강화)에 최적화되어 있지만 표준적인 OAuth/OIDC 트래픽에서도 작동합니다.
Burp / mitmproxy를 통해 긴 Microsoft 365 또는 Azure 세션을 프록시하면 결과 캡처가 방대해지며 대부분의 도구는 다음 중 하나에 해당합니다:
이 도구는 관찰된 모든 액세스 / 리프레시 / ID 토큰을 추출하고, 소스 간에 동일한 토큰을 상호 연관시킬 수 있도록 지문을 생성하며, JWT 클레임을 디코딩하고, entrascopes.com에 대해 Microsoft 클라이언트 / 리소스 GUID를 확인하며, 전체 그림을 단일 대시보드로 렌더링합니다 — FOCI 교차 앱 교환과 BroCI 중첩 앱 토큰 발급을 추적하는 리프레시 토큰 체인 보기를 포함합니다.
이 프로젝트는 주로 연구 및 교육 목적으로 설계되었지만 일부 공격적 도구를 지원할 수 있는 명령 미리보기 및 토큰 내보내기 기능과 같은 옵션을 제공합니다.
ingest — Burp Suite "Save items" XML 내보내기mitm — mitmproxy 플로우 파일(HTTP WebSocket 프레임).mitmcdp — DevTools Protocol을 통한 Chrome / Edge 실시간 연결
(실시간, 프록시 CA 없이 TLS 복호화된 HTTP 및 WebSocket 프레임
캡처; 브라우저 수준 자동 연결을 통해 실행 중 열린 모든 기존 탭과
모든 새 탭을 추적)--append로 실행하여 기존 데이터베이스에 병합할 수 있습니다;
토큰은 업서트되고(사용 횟수 + 관찰된 수명 누적), 이벤트와
교환은 추가되며, 행의 source_tag는 토큰을 본 모든 패스를 기록합니다.pip install mitmproxy).access_token, refresh_token, id_token) 및
쿠키 이름 휴리스틱이 토큰 유형을 결정합니다.ESTSAUTH, ESTSAUTHPERSISTENT,
ESTSAUTHLIGHT, SignInStateCookie)는 리프레시와 동등한 토큰으로
명시적으로 인식됩니다(그렇지 않으면 일반 "auth" 쿠키 힌트로 잘못 분류됨).foci
필드를 통해 감지됩니다.brk_client_id,
brk_redirect_uri 및 brk-<guid>:// 리디렉션 체계를 통해 감지됩니다.--enrich 플래그는 https://entrascopes.com/에서
firstpartyscopes.json 및 resources.json을 가져와 appid /
azp / aud GUID를 클릭 가능한 링크가 있는 친숙한 이름으로 확인합니다.upn / preferred_username / unique_name / email /
name별 토큰 버킷팅, sub@iss 또는 oid로 폴백하며 앱 전용 및
알 수 없는 ID 버킷을 별도로 표시합니다. 각 ID 행은 사용자가
≥2개의 source_tag에 나타날 때 캡처 배지를 표시하고(교차 캡처 생존,
핵심 --append 연구 신호) first_seen → last_seen 범위와
해당 사용자의 모든 토큰을 시퀀스 다이어그램 탭에서 강조하는
타임라인 버튼을 표시합니다.appid / azp / 폼 본문
client_id / brk_client_id / brk_nested_id)에 FOCI / 브로커 가능 /
브로커 / 중첩 배지 표시.aud 클레임을 가능한 경우 entrascopes
리소스 이름으로 확인.tid 값.scp / scope / roles를
선별된 고영향 Microsoft Graph 권한 및 Azure 리소스 범위 목록과 대조.aud 클레임과 일치하지 않는 호스트에서
사용된 모든 (토큰, 호스트) 쌍을 플래그(자격 증명 유출 또는 오용 시사).amr) — pwd / mfa / pop / smartcard 분포.xms_cc=CP1), 소유 증명 바인딩
(cnf 클레임, 대상 간 공유 kid 감지 포함), 단계 상승 인증 요구 사항
(acrs) 및 acr 인증 컨텍스트 수준을 플래그합니다. 각 행은 클릭 가능하며
해당 마커를 가진 토큰만 표시하도록 토큰 탭을 필터링합니다.⚠ 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>]] 및 하나의 WebSocket 연결 내의 모든 프레임을
그룹화하는 ws_session_id로 이벤트를 생성합니다.데이터베이스는 SHA-256 지문(처음 12자리 16진수)과 관찰된 모든 토큰의 12자리 접두사를 저장합니다. 전체 토큰 문자열은 입력 파일을 벗어나지 않습니다.
디코딩된 JWT 클레임 내용(헤더 + 페이로드, oid, sub, upn, email,
tid, 범위 목록 등 포함)은 분석의 핵심이므로 기본적으로 그대로 저장됩니다.
JWT가 있을 때마다 데이터베이스와 공유된 대시보드 URL을 민감한 것으로 취급하세요.
--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)을 전달하세요.
동일한 입력은 항상 동일한 자리 표시자로 매핑되므로 사용자를 공개하지 않고도
대시보드의 사용자 / 테넌트 그룹화가 계속 작동합니다.
--store-tokens(ingest, mitm, cdp에서 사용 가능, 기본적으로
꺼짐)은 전체 토큰 문자열을 데이터베이스에 기록하여 대시보드가 다음을
제공할 수 있게 합니다:
.roadtools_auth에
넣으면 모든 roadtx 하위 명령이 이를 인식).tid, appid 및 aud 클레임을 사용하여 가장 일반적인
재생 호출 — roadtx describe, roadtx auth, curl, Python requests,
PowerShell Invoke-RestMethod —을 미리 채우는 토큰별 블록.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/`에 있으며
첫 번째 import 시 로드되므로 빌드 단계가 필요하지 않습니다. 체크아웃 디렉토리에서 모듈을 직접 실행하기만 하면 됩니다.
**패키지로 설치(`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
하나의 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 브라우저에서의 실시간 캡처(TLS 복호화된 HTTP + WebSocket 프레임을 볼 수 있으며, 프록시 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
실행된 브라우저는 cdp 명령에서 Ctrl-C를 누르면 종료되고 임시 프로필이 삭제됩니다.
이미 실행 중인 브라우저에 연결하려면 --remote-debugging-port=9222 --user-data-dir=/tmp/cdp-profile로 시작한 다음 --launch-chrome 없이 cdp를 실행하세요.
공유 전 데이터베이스 정리(PII(개인 식별 정보) 삭제):```bash
tats ingest engagement.xml -o tokens.db
--enrich --redact-claims
The redaction is content-stable: identical values map to identical
placeholders, so the dashboard's per-user grouping still works without
showing the user.
The header of the dashboard shows `live · updated <time>` once data starts
flowing in.
---
## 하위 명령어
모든 하위 명령어는 표준 옵션 목록을 위해 `--help`를 지원합니다. 아래
참고 사항은 각 명령어를 *언제*, *어떻게* 사용하는지 설명합니다.
### 전역 플래그
이 플래그들은 모든 하위 명령어에 적용되며 하위 명령어 이름 *앞에* 위치합니다:
* `-v` / `--verbose` — INFO 로그 줄을 추가합니다(강화 상태, 수집
편집 횟수). `-vv`는 DEBUG를 추가합니다(모든 서버 요청).
* `-q` / `--quiet` — INFO 로그 줄을 숨깁니다. WARNING과 ERROR만
표시됩니다. 최종 사용자 출력 줄(예: `wrote tokens.db (...)`)과
`error: …` 진단 메시지는 영향을 받지 않으므로 스크립트에서
중요한 내용을 계속 확인할 수 있습니다.
* `--version` — 도구 버전을 출력하고 종료합니다.
### `ingest` — Burp Suite XML 내보내기
"Save items" XML(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` — mitmproxy `.mitm` 플로우 파일
`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에 실시간 연결
DevTools 프로토콜을 통해 실행 중인 Chromium 계열 브라우저에 연결하여
`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)
브라우저가 종료되고 임시 프로필이 삭제됩니다.
### 이미 실행 중인 브라우저에 연결
브라우저를 새 프로필로 직접 시작한 다음, `--launch-chrome` 없이 `cdp`를 실행하세요:```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-클릭, 새 탭 버튼)을 추적합니다.
모든 탭은 CDP 플랫 프로토콜 세션 멀티플렉서를 통해 단일 WebSocket을 공유하므로,
캡처 실행 중 탭을 열거나 닫는 것이 완전히 지원됩니다. 각 탭의 연결
/ 해제는 INFO 수준에서 stderr에 한 줄 메모로 출력됩니다.
단일 탭에 고정하고 해당 탭이 닫힐 때 연결이 종료되도록 하려면, 사용 가능한 대상을 나열하세요:```bash curl http://127.0.0.1:9222/json/list
…그런 다음 `--target <id>`를 전달합니다.
Ctrl-C를 눌러 중지합니다. 프로세스가 종료되기 전에 처리 중인 버퍼의 나머지 부분이 데이터베이스로 플러시됩니다.
### `serve` — 웹 대시보드
기존 데이터베이스를 읽어 `127.0.0.1:8765`에서 단일 페이지 웹 UI를 제공합니다. 서버는 읽기 전용이며 데이터베이스에 쓰지 않으므로 실행 중인 `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
> **경고:** 웹 UI는 바인드 주소에 접근할 수 있는 모든 사용자에게 디코딩된 JWT 페이로드(클레임), 토큰
> 지문, 활동 타임라인 및 Mermaid 그래프를 노출합니다. `--store-tokens`로 수집한 경우
> `/api/token/<fp>` 및 `/api/export?fps=...`를 통해 **전체 원시 토큰**도 노출됩니다.
> **인증이 없습니다.** 특별히 의도하지 않는 한 `--host`를 `127.0.0.1`로 유지하세요.
#### 재생 준비 완료 내보내기
데이터베이스가 `--store-tokens`로 구축된 경우, Tokens 탭의 각 확장 토큰에는 원클릭 작업 행이 표시됩니다:
* **원시 복사** — 전체 토큰 문자열을 클립보드에 복사합니다.
* **Bearer 헤더 복사** — `Authorization: Bearer <token>`, 붙여넣기 준비 완료.
* **curl 예제 복사** — 토큰의 `aud`(또는 발급자 호스트)를 대상으로 Bearer 헤더가 첨부된 한 줄 명령.
* **JSON 다운로드** — 원시, 클레임, 관찰된 이벤트 및 교환을 포함하는 단일 토큰 JSON 파일.
* **roadtx로 복사** — roadtools 토큰 캐시의 JSON 형태(`tokenType`, `accessToken` / `refreshToken` / `idToken`, `expiresOn`,
`tenantId`, `_clientId`, `resource`, `foci`, `scope`). `.roadtools_auth` 파일에 바로 붙여넣습니다.
* **.roadtools_auth 다운로드** — 동일한 페이로드를 파일로 다운로드합니다.
`.roadtools_auth`로 이름을 바꾸거나(또는 `roadtx <cmd> --tokens-file`로 전달) 모든 roadtx 하위 명령이 이를 인식합니다.
Tokens 탭 도구 모음에는 **재생을 위해 선택 항목 내보내기**도 있으며, 이는 `/api/export?fps=fp1,fp2,...`를 호출하고 최대 200개의 토큰(원시, 클레임, 이벤트)을 포함하는 단일 JSON 문서를 하나의 번들로 다운로드합니다. `--store-tokens`가 없으면 동일한 버튼이 재생 준비 완료 내보내기가 가능해지기 전에 재수집하라는 힌트를 렌더링합니다.
#### 명령 미리보기
각 확장 토큰에는 토큰의 실제 클레임(`--store-tokens`가 켜져 있을 때 전체 원시 값 포함)을 사용하여 가장 일반적인 재생/검사 호출을 미리 채우는 접이식 **명령 미리보기** 블록도 있습니다. 각 스니펫에는 원클릭 복사 버튼이 있습니다. 정확한 구성은 토큰 유형에 따라 다릅니다:
* **모든 JWT:** `roadtx describe -t '<token>'` (네트워크 없이 디코딩).
* **새로 고침 토큰:**
* `roadtx auth --refresh-token '...' -c <client_id> -t <tenant_id>` — 새로 고침 토큰을 새 액세스 토큰으로 교환.
* `curl -X POST .../oauth2/v2.0/token` — roadtx를 실행하지 않는 사용자를 위한 OAuth 동등 명령.
* **액세스 / id / 알 수 없는 토큰:**
* `curl -H 'Authorization: Bearer ...' '<aud>'`
* Bearer 헤더가 설정된 Python `requests.get(...)`.
* 동일한 헤더를 사용하는 PowerShell `Invoke-RestMethod`.
* **항상:** `.roadtools_auth`에 넣을 JSON 객체.
`--store-tokens`가 꺼져 있으면 스니펫은 `<TOKEN>`을 자리 표시자로 렌더링하므로 패널이 여전히 문서 참조로 유용합니다.
---
## 웹 UI 상세
### 상단 탐색
`Summary | Tokens | Exchanges | FOCI | BroCI | Graph | Sequence`
각 탭은 `/api/data`의 동일한 메모리 내 스냅샷에서 독립적으로 렌더링됩니다. 탭 전환은 즉각적이며, 그래프 및 시퀀스 다이어그램은 요청 시 다시 렌더링되고 Tokens 탭의 현재 선택을 존중합니다.
### Summary
상단의 통계 타일(토큰 / 액세스 / 새로 고침 / id / 알 수 없음 / 사용됨 / 사용되지 않음 / 이벤트 / 교환 / FOCI 교환 / BroCI 교환 / 호스트) 다음에 [Features → Dashboard cards](#dashboard-cards)에 설명된 카드 그리드가 이어집니다.
카드의 아무 행이나 클릭하면 사전 필터링된 Tokens 탭으로 이동합니다 — 예를 들어 테넌트 행을 클릭하면 해당 `tid`를 가진 토큰으로 인벤토리가 필터링됩니다.
### Tokens
필터링 및 정렬 가능한 인벤토리. 다중 선택은 강조 표시 / 격리 / 시퀀스 버튼을 구동합니다. 행 확장은 전체 디코딩된 JWT(헤더 + 페이로드를 원시 JSON으로), 해당 토큰과 관련된 모든 이벤트, 그리고 입력 또는 출력이었던 모든 교환을 표시합니다.
### Exchanges
감지된 모든 토큰 간 교환의 정렬 가능한 목록 — 새로 고침 토큰 회전, FOCI 교차 상환 및 BroCI 중첩 앱 교환. BroCI 열은 브로커 + 중첩 클라이언트 ID를 감지를 트리거한 증거와 함께 나란히 표시합니다.
### FOCI
두 개의 테이블: FOCI 패밀리로 태그된 모든 새로 고침 토큰(현재 Microsoft는 `"1"`만 발행) 및 응답에 `foci` 필드를 전달한 모든 교환.
### BroCI
중첩 앱 인증 교환. 각각에 대해: 브로커 앱(`brk_client_id`), 중첩 클라이언트(`client_id`), 감지를 트리거한 증거(`brk_client_id`, `brk_redirect_uri`, `brk-<guid>://` 리디렉션 URI) 및 입력/출력 토큰 지문.
### Graph
토큰 ↔ 서비스 관계의 Mermaid `flowchart LR`. 새로 고침 토큰은 원통으로, 액세스/id 토큰은 경기장 모양으로 그려집니다. 가장자리는 발급, 제시, 교환 및 회전을 표시합니다. (Tokens 탭의) 강조 표시는 노란색 악센트를 추가하고, 격리는 선택된 토큰과 교환하는 토큰만으로 그래프를 다시 렌더링합니다.
### Sequence
캡처 순서대로 모든 이벤트의 Mermaid 시퀀스 다이어그램. 단일 토큰을 선택하면 해당 시퀀스만 표시되고, 여러 개를 선택하면 전체 보기를 유지하지만 선택된 토큰에 별표를 표시합니다. 구성 가능한 최대 이벤트 상한(기본값 200, Mermaid 시퀀스 다이어그램은 수백 개의 메시지를 넘어가면 읽을 수 없게 됩니다).
---
## Microsoft 특정 지원
### 클라이언트 ID 패밀리(FOCI)
Microsoft는 "패밀리"의 한 앱에 발급된 새로 고침 토큰이 동일한 패밀리의 **다른 앱**에 의해 토큰 엔드포인트에서 상환될 수 있도록 허용합니다. 이 도구는 토큰 엔드포인트 응답 JSON에서 `foci` 필드(현재 알려진 유일한 패밀리에 대해 항상 `"1"`)를 파싱하여 온라인상에서 FOCI를 감지합니다. 이러한 응답에서 발급된 새로 고침 토큰은 패밀리 ID로 태그되고 전용 **FOCI** 탭에 표시됩니다.
`--enrich`가 활성화되면 인벤토리의 앱 열에도 `firstpartyscopes.json`의 `foci: true/false` 플래그가 표시됩니다 — 이는 온라인 감지와 다를 수 있습니다(entrascopes 데이터 세트는 때때로 보수적입니다). 온라인 `foci` 필드가 항상 권위 있는 신호입니다.
### 브로커 클라이언트 시작 / 중첩 앱 인증(BroCI / NAA)
Office 추가 기능, Teams 앱 및 Azure Portal은 NAA를 사용하여 브로커 앱을 통해 중첩 클라이언트에 대한 토큰을 획득합니다. 이 도구는 요청 측에서 다음을 통해 이를 감지합니다:
* `brk_client_id` 양식 매개변수(브로커 앱의 GUID),
* `brk_redirect_uri` 양식 매개변수(브로커의 실제 리디렉션 URI),
* `brk-<guid>://...` 형식의 `redirect_uri`(`<guid>`는 브로커).
결과 액세스 토큰의 `appid` / `azp` 클레임은 중첩 클라이언트입니다. 브로커는 온라인에만 나타나며 JWT 클레임으로는 절대 나타나지 않습니다. 대시보드는 양쪽을 명확하게 표시합니다.
### `ESTSAUTH` 세션 쿠키
`ESTSAUTH`, `ESTSAUTHPERSISTENT`, `ESTSAUTHLIGHT` 및 `SignInStateCookie`는 `Authorization: Bearer`로 전송되지 않지만 브라우저가 자동 인증 흐름을 통해 새 액세스 토큰을 생성하는 데 사용하는 Microsoft Entra 세션 쿠키입니다. 이 도구는 일반적인 `auth` 하위 문자열 규칙이 이를 `access`로 잘못 분류하도록 두지 않고 `refresh`(기능적 역할)로 레이블을 지정합니다.
### entrascopes.com 강화(`--enrich`)
<https://entrascopes.com/>에서 `firstpartyscopes.json`(~2.8MB, FOCI 플래그, 리디렉션 URI, 범위 및 브로커 기능이 있는 504개의 자사 앱) 및 `resources.json`(~170KB, 1,750개 이상의 리소스 → 표시 이름 매핑)을 가져와 캐시합니다. 캐시 위치:
| 변수 | 기본값 |
|---|---|
| `$TATS_CACHE` | (최우선 순위, `$BURP_TOKEN_TRACKER_CACHE`는 한 릴리스 마이그레이션을 위한 대체로 인정됨) |
| `$XDG_CACHE_HOME/tats` | (Linux/macOS) |
| `%LOCALAPPDATA%\tats\cache` | (Windows) |
| `~/.cache/tats` | (대체) |
TTL은 7일입니다. 강제로 다시 가져오려면 `--no-enrich-cache`를 사용하세요. 도구가 오프라인으로 실행될 때 캐시는 오래된 대체로 재사용됩니다.
`--enrich`가 켜져 있으면 모든 `appid` / `azp` / `client_id` GUID 및 모든 GUID 또는 URL `aud` 클레임이 클릭 가능한 `https://entrascopes.com/?appId=<guid>` 링크와 함께 친숙한 이름으로 확인됩니다.
---
## 아키텍처
### 일회성: 파일 → DB → 웹 UI```
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 서버를 위해 데이터베이스를 읽으며, 서버는 /api/data, /api/meta, /api/token/<fp>, /api/export, /api/graph, /api/sequence를 통해 JSON을 노출합니다.
tokens (기본 키 fp) — 지문, 샘플 접두사, 유형, 형식, 관찰된 수명, JWT 헤더/페이로드(JSON), 보강 필드, 파생 필드(user_identity, exp_unix, tenant_id, scopes_text), 쉼표로 구분된 source_tag, raw(전체 토큰 문자열, --store-tokens로 수집하지 않으면 NULL), 그리고 security_features(감지된 CAE / PoP / step-up 마커를 설명하는 압축 JSON — 보안 기능 카드 참조).
이전 v2 / v3 데이터베이스는 추가 모드로 다시 열면 자동 마이그레이션됩니다: 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 — 토큰 엔드포인트에 대한 토큰 포함 요청이 응답에서 새 토큰을 생성한 경우. FOCI / BroCI 메타데이터를 기록합니다.exchange_inputs, exchange_outputs — 각 교환의 양쪽에 있는 토큰 지문.hosts — 고유한 host:port 레이블.meta — 스키마 버전, 소스 목록, generated_at, last_modified(대시보드의 실시간 폴링에 사용), 카운트.DB에 기록되는 모든 행은 source_tag를 포함합니다 — 기본적으로 burp:<filename>, mitm:<filename>, 또는 cdp:<host>:<port>이며, --source-tag로 재정의할 수 있습니다. 동일한 지문이 둘 이상의 수집 패스에서 관찰되면 source_tag 필드는 쉼표로 구분된 목록으로 누적되므로, 대시보드의 소스 카드가 모든 토큰의 출처를 표시할 수 있습니다.
--append는 기존 DB를 유지하고 토큰에 대해 UPSERT(사용 횟수 + 관찰된 수명 누적, 알 수 없는 유형 업그레이드)로 병합하며, 이벤트/교환에 대해 INSERT(기존 최대값을 넘어 seq 번호를 오프셋하여 활동 타임라인이 단조롭게 유지됨)로 병합합니다. 스키마 버전 불일치는 자동 병합을 거부하여 조용한 데이터 손실을 방지합니다.
웹 서버의 /api/meta 엔드포인트는 meta 테이블(약 200바이트)을 반환합니다. 대시보드는 5초마다 이를 폴링하고 last_modified가 변경된 경우에만 전체 /api/data를 다시 가져옵니다. cdp 수집 경로는 기본적으로 25개 이벤트마다 인메모리 트래커를 DB로 플러시하므로, 브라우저 요청에서 대시보드 업데이트까지의 실제 경과 시간은 일반적으로 10초 미만입니다.
.burp 프로젝트 파일은 지원되지 않습니다. 도구가 사용하는 XML을 생성하려면 Save items를 사용하세요.alg=none, 키 혼동 공격은 범위 밖입니다. 이러한 경우 전용 JWT 감사 도구를 사용하세요.unknown으로 끝나며, (Burp 전용) 이전 플래그에 --include-unknown이 설정되지 않는 한 기본적으로 숨겨집니다.--enrich는 아웃바운드 HTTP 요청을 수행합니다 https://entrascopes.com/로. 환경이 이를 허용하지 않으면 플래그를 건너뛰세요.| 증상 | 가능한 원인 | 해결 방법 |
|---|---|---|
error: could not parse <file> as XML | 바이너리 .burp 프로젝트 파일을 수집하려고 함 | Burp에서: Proxy → HTTP history → 항목 선택 → 마우스 오른쪽 클릭 → Save items |
error: no <item> elements found | XML이 Burp의 Save items로 생성되지 않음 | Burp에서 다시 내보내기; 루트 요소는 <items>여야 함 |
error: cannot append to DB with schema_version 1 | DB가 이전 빌드로 생성됨 | DB를 삭제하고 원본 소스를 다시 수집; 스키마 마이그레이션은 의도적으로 자동이 아님 |
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 하위 명령의 실행 명령 참조 |
| CDP가 연결되지만 이벤트가 흐르지 않음 | 페이지가 아직 네트워크 요청을 하지 않았거나, 모든 활동이 OOPIF / 워커에 있음(자동 연결되지 않음) | 페이지를 새로고침; 탭이 등록되었는지 확인(stderr에서 tab attached: … 로그 줄 확인) |
no browser-level webSocketDebuggerUrl at /json/version | Chrome 버전이 브라우저 수준 CDP에 너무 오래되었거나 잘못된 형태를 반환함 | Chrome을 업데이트하거나, 레거시 단일 탭 연결을 위해 --target <id> 전달 |
target … has no webSocketDebuggerUrl | 다른 디버거(예: DevTools 창)가 이미 연결됨 | DevTools를 닫거나 다른 대상에 연결 |
대시보드에 Failed to load /api/data 표시 | 서버가 데이터베이스 파일을 읽을 수 없음 | DB 경로가 올바른지, 파일을 읽을 수 있는지, 스키마 버전이 일치하는지 확인 |
| 실시간 업데이트가 중단됨 | 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개의 토큰(Burp에서 11개 + mitmproxy에서 4개), WebSocket 프레임 이벤트를 포함한 23개의 이벤트, 그리고 3개의 교환이 있습니다.
### 테스트 스위트```bash
pip install .[test]
pytest
이 스위트는 토큰 추출, JWT 파싱, Microsoft 세션 쿠키 분류, FOCI / BroCI 탐지, 클레임 요약, PII(개인 식별 정보) 마스킹, 추가 모드 UPSERT 의미론을 갖춘 Burp XML 수집 경로, 그리고 mitmproxy WebSocket 프레임 수집 경로(선택적 mitmproxy 의존성이 없을 때 자동으로 건너뜀)를 포함합니다.```text
$ pytest tests/
============================= test session starts =============================
…
======================== 62 passed in 1.4s =================================
### 서버를 포그라운드에서 실행하기```bash
tats serve tokens.db --no-browser
…그리고 http://127.0.0.1:8765를 수동으로 엽니다. 서버는 모든 요청과 핸들러 오류를 stderr에 기록합니다.
| 경로 | 용도 |
|---|---|
tats/__init__.py | 전체 도구 — 파서, DB 계층, HTTP 서버, CDP 클라이언트; tats/static/에서 대시보드를 로드합니다 |
tats/__main__.py | python -m tats의 진입점; 설치된 tats 콘솔 스크립트와 동일한 로직 |
tats/static/index.html | {{CSS}} / {{JS}} 자리표시자가 있는 대시보드 HTML 골격 |
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를 참조하세요.
/api/export?fps=....이 기능을 활성화하면 데이터베이스가 일괄 자격 증명이 됩니다 — 캡처된 세션을
재생하는 데 필요한 모든 바이트가 포함됩니다. --redact-claims와 결합하여
디코딩된 JWT 보기를 정리할 수 있지만 원시 토큰에는 여전히 수정되지 않은
클레임이 인코딩되어 있다는 점을 인지하세요. 플래그가 꺼져 있을 때 대시보드의
명령 미리보기 블록은 여전히 렌더링되며 <TOKEN>을 자리 표시자로 사용하여
구문 참조로 작동합니다; 내보내기 버튼은 재수집을 위한 힌트를 렌더링합니다.