# Recon: What to Put In, Where to Submit Forging the JWE payload is the easy part. The hard part is **what claims the app expects** and **where/how it consumes the token**. ## 1. What to Put In (Claim Discovery) ### pac4j defaults (library behavior) - **Subject** → becomes the profile id (e.g. `UserProfile.getId()`). Apps often use it as username or user id. Common values to try: `admin`, `admin#something`, `administrator`, numeric ids if the app uses them. - **`$int_roles`** → internal roles list. pac4j maps these to `UserProfile.getRoles()`. Many Spring/pac4j apps expect `ROLE_*` (e.g. `ROLE_ADMIN`, `ROLE_USER`, `ROLE_SUPERUSER`). The app may only check for specific strings. - **`exp`** → must be in the future or the token may be rejected. ### How to discover app-specific claims - **Valid token (if you have one):** Decode a real JWT/JWE (if you can decrypt or it’s leaked). Inspect claim names and values (subject format, role names, any custom claims like `email`, `tenant_id`, `iss`). - **Docs / OpenID config:** Some apps document required claims or expose `/.well-known/openid-configuration`. Check for claim requirements or userinfo schema. - **Application behavior:** Try a low-privilege account, capture a legitimate token (e.g. from browser devtools or a proxy), decode and mirror structure with elevated subject/roles. - **Code / config:** If you have access to app or framework config, search for `JwtAuthenticator`, `profileDefinition`, `PrincipalNameAttribute`, or custom claim mappings. That shows which claim is used as username and how roles are read. - **Trial and error:** Start with `sub` + `$int_roles` + `exp`. If the app still returns 401 or doesn’t treat you as admin, try: different subject formats (with/without `#`), different role names (e.g. `ADMIN` vs `ROLE_ADMIN`), and adding common claims (`email`, `preferred_username`, app-specific keys). ### Common claim shapes to try | Scenario | sub | $int_roles | Other | |----------|-----|------------|--------| | Default pac4j | `admin#override` or `admin` | `ROLE_ADMIN`, `ROLE_SUPERUSER` | — | | Spring Security style | `admin` | `ROLE_ADMIN`, `ROLE_USER` | — | | With email | same | same | `email`: `admin@target.com` | | Multi-tenant | target user id | same | `tenant_id` or app-specific | Use the token-forge CLI `--subject`, `--roles`, and `--claim key=value` to iterate without changing code. --- ## 2. Where to Submit (Endpoint and Transport) ### How the token is sent - **Authorization header (most common):** `Authorization: Bearer `. This is the default for many pac4j JWT clients and the usual place to try first. - **Cookie:** Some apps store the JWT in a cookie (e.g. after a callback). Cookie name is often configurable; look for names like `pac4jSessionToken`, `SESSION`, `auth_token`, or names in the app’s security config. Set the cookie to your forged token and reload or hit an API that reads it. - **Custom header:** Less common, but possible (e.g. `X-Auth-Token`, `X-JWT`). Check docs or responses (e.g. `WWW-Authenticate` or error messages that mention a header). ### Finding protected endpoints - **401 / 403 vs 200:** Unauthenticated request returns 401 (or 302 to login); same request with a valid token returns 200 (or different body). Use that to confirm which paths require auth and accept your token. - **Common paths:** Try `/`, `/api`, `/api/**`, `/admin`, `/user`, `/auth/callback`, `/rest/**`, `/graphql`, and any paths mentioned in docs or UI (links, API base URL). - **Framework hints:** pac4j is often used with Spring Boot, Dropwizard, or other Java frameworks. Their default prefixes and security config (e.g. “everything under `/api` is protected”) give you a list of URLs to test. - **Incremental testing:** Once you have a forged token, send it (e.g. `Authorization: Bearer `) to a small set of paths. If you get 200 and user-specific data or different behavior than without the token, you’ve found a submission point and can refine claims (e.g. switch to an admin subject/roles) and retest. ### Quick submission checklist 1. Obtain RSA public key (JWKS, config, or docs). 2. Forge token with `token_forge` (or Java PoC) using a first-guess subject and roles. 3. Send `GET` (or relevant method) to likely paths with `Authorization: Bearer `. 4. If no success, try cookie (guess name from app/framework), then other headers. 5. If still 401/403, adjust claims (subject format, role names, extra claims) and repeat. --- ## 3. Using the Tools ```bash # Try default admin + roles python -m token_forge --public-key pub.pem --subject admin --roles "ROLE_ADMIN,ROLE_USER" # Try with extra claims (app might expect email or preferred_username) python -m token_forge --public-key pub.pem --subject admin --roles "ROLE_ADMIN" --claim email=admin@target.com # Pipe into curl TOKEN=$(python -m token_forge --public-key pub.pem --subject admin) curl -H "Authorization: Bearer $TOKEN" https://target/api/admin/users ``` Use recon to decide `--subject`, `--roles`, and `--claim`; use the checklist to decide where to send the token and how (header vs cookie). --- ## 4. Automated discovery with Kiterunner (kr) Requires **kr** in `~/bin/kr`. The script forges a token and runs `kr brute` (or `kr scan`) with `Authorization: Bearer ` so every request is authenticated. ```bash # From repo root. Default: kr brute with Assetnote apiroutes-210228 wordlist python scripts/kr_scan.py https://target.com --jwks-url https://target.com/.well-known/jwks.json # With PEM and custom subject/roles python scripts/kr_scan.py https://target.com --public-key pub.pem --subject admin --roles "ROLE_ADMIN,ROLE_USER" # Custom wordlist, JSON output, dry-run to print the kr command python scripts/kr_scan.py https://target.com --public-key pub.pem -w paths.txt -o json --dry-run # Use 'kr scan' instead of 'kr brute', different Assetnote wordlist python scripts/kr_scan.py https://target.com --jwks-url https://target.com/.well-known/jwks.json --scan -A apiroutes-210228 ``` Options: `--claim K=V`, `--exp-sec`, `--timeout`, `--kr-extra '--delay 500ms'`. Hits that return different status/length with the forged token than without indicate protected endpoints that accept the token.