Skip to content
advanced Phase 7 · Web Vulnerabilities and the OWASP Top 10

SSRF and Unsafe Deserialization

Abuse server-side fetches and object loaders to reach internal resources.

55m
0 problems
Topic Progress 0%

SSRF: Turning the Server into an Attacker's Proxy

Server-Side Request Forgery: When the Server Fetches What the Attacker Wants

Server-Side Request Forgery (SSRF) is a vulnerability that allows an attacker to coerce a server into making HTTP requests to internal hosts that the attacker cannot reach directly. The server becomes a proxy that accesses resources on behalf of the attacker, bypassing firewalls and network segmentation.

How SSRF Works

When a web application fetches a user-supplied URL without proper validation, the attacker can supply URLs that point to internal services:

# VULNERABLE — fetches user-supplied URL without validation
@app.route('/fetch')
def fetch_url():
    url = request.args.get('url')
    response = requests.get(url)  # Attacker controls the URL
    return response.text

An attacker supplies http://169.254.169.254/latest/meta-data/iam/security-credentials/ and the server retrieves its own cloud IAM credentials.

SSRF Attack Targets

1. Cloud Metadata Endpoints

Cloud providers expose metadata services at 169.254.169.254 (AWS, GCP, Azure). These endpoints provide:

  • Temporary IAM credentials
  • User-data scripts (executed at instance boot)
  • Instance configuration and network details
# AWS metadata — retrieve IAM credentials
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/my-role

# AWS user-data — retrieve boot scripts
curl http://169.254.169.254/latest/user-data

2. Internal Services

Internal services often have no authentication because they are only accessible from within the network:

  • http://localhost:6379 — Redis (no auth by default)
  • http://localhost:9200 — Elasticsearch (no auth by default)
  • http://localhost:8080/manager/html — Tomcat manager (default credentials)
  • http://127.0.0.1:22 — SSH (port scanning via response timing)

3. File Protocol Abuse

If the application uses a library that supports non-HTTP protocols:

file:///etc/passwd
file:///proc/self/environ
gopher://127.0.0.1:6379/_*1%0d%0a$4%0d%0aFLUSHALL%0d%0a

4. DNS Rebinding

An attacker controls a domain that resolves to a public IP during validation but to an internal IP (e.g., 127.0.0.1) when the server actually fetches it. This bypasses URL validation that checks the resolved IP.

SSRF Impact

  • Credential theft: Cloud metadata endpoints expose temporary credentials
  • Internal network scanning: Response timing and content reveal internal hosts and ports
  • Data exfiltration: Internal services (Redis, Elasticsearch) can be read or modified
  • Remote code execution: Some internal services allow command execution (e.g., Jenkins script console)

Real-World SSRF

In 2019, Capital One suffered a breach that exposed 100 million customer records. An SSRF vulnerability in a web application firewall allowed the attacker to access the AWS metadata service and retrieve temporary credentials for an IAM role with excessive permissions. The attacker then used these credentials to access S3 buckets containing sensitive data.

SSRF Defense and Unsafe Deserialization

Defending Against SSRF and Understanding Deserialization Attacks

SSRF Defense Layers

1. URL Validation (Allow-List)

The most effective defense is to validate user-supplied URLs against an allow-list of permitted domains and IP ranges:

import ipaddress
from urllib.parse import urlparse

def is_safe_url(url):
    parsed = urlparse(url)
    
    # Only allow HTTP/HTTPS
    if parsed.scheme not in ('http', 'https'):
        return False
    
    # Resolve the hostname and check the IP
    try:
        ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
    except socket.gaierror:
        return False
    
    # Block private, loopback, and link-local addresses
    if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved:
        return False
    
    return True

2. Network-Level Controls

  • Egress filtering: Configure firewalls to block outbound requests from application servers to internal IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16).
  • Separate metadata endpoint: Use AWS IMDSv2 (Instance Metadata Service Version 2) which requires a session token obtained via a PUT request, preventing simple SSRF attacks.
  • Disable unnecessary protocols: If the application only needs HTTP/HTTPS, disable support for file://, gopher://, dict://, etc.

3. Response Validation

  • Do not return the full response body to the user. Parse and sanitize the response.
  • Set a maximum response size to prevent large data exfiltration.
  • Set a short timeout to prevent slow-response attacks.

Unsafe Deserialization

Deserialization is the process of converting a serialized byte stream back into an object. Unsafe deserialization occurs when an application deserializes untrusted data without verification, allowing attackers to instantiate arbitrary objects and trigger unintended code paths.

How deserialization attacks work:

  1. Attacker crafts a serialized object that, when deserialized, executes a "gadget chain" — a sequence of method calls that leads to code execution.
  2. The application deserializes the object without checking its type or integrity.
  3. The gadget chain executes during or after deserialization.

Java deserialization example:

// VULNERABLE — deserializes untrusted data
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Object obj = ois.readObject();  // Attacker controls the byte stream

Python pickle example:

# VULNERABLE — deserializes untrusted data
import pickle
data = pickle.loads(request.POST['data'])  # Attacker controls the data

PHP unserialize example:

// VULNERABLE
$data = unserialize($_POST['data']);

Gadget Chains

A gadget chain is a sequence of existing methods in the application's codebase (or its dependencies) that, when called in sequence during deserialization, produce a dangerous effect (command execution, file write, etc.). Common gadgets include:

  • Templates: freemarker.template.utility.Execute (Java)
  • Commons Collections: InvokerTransformer chain (Java)
  • YAML: yaml.load with !!python/object/apply:os.system (Python)

Deserialization Defense

1. Do not deserialize untrusted data. Use JSON or other data-only formats instead.

2. If deserialization is required:

  • Use integrity checks (HMAC signatures) to verify the data has not been tampered with:
import hmac, hashlib

def safe_deserialize(data, secret):
    # data = signature + payload
    sig, payload = data[:32], data[32:]
    expected = hmac.new(secret, payload, hashlib.sha256).digest()
    if not hmac.compare_digest(sig, expected):
        raise ValueError('Invalid signature')
    return pickle.loads(payload)
  • Use type restrictions (e.g., Java's ObjectInputFilter in newer versions)
  • Use safe serialization formats (JSON, Protocol Buffers) instead of native serialization

3. Keep dependencies updated. Many deserialization gadgets exist in third-party libraries (e.g., Apache Commons Collections, Spring Framework).

Practice Problems

0 / 2 solved
Identify and Fix SSRF

The following endpoint is vulnerable to SSRF. Identify the vulnerability and implement a fix. ```python @app.route('/webhook') def webhook(): url = request.json.get('url') response = requests.get(url, timeout=5) return response.text ``` An attacker can supply `http://169.254.169.254/latest/meta-data/` to access cloud metadata.

Solution
The endpoint fetches a user-supplied URL without any validation. Fix by implementing URL validation:

```python
import ipaddress
import socket
from urllib.parse import urlparse

def is_safe_url(url):
    parsed = urlparse(url)
    if parsed.scheme not in ('http', 'https'):
        return False
    try:
        ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
    except (socket.gaierror, ValueError):
        return False
    if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved:
        return False
    return True

@app.route('/webhook')
def webhook():
    url = request.json.get('url')
    if not is_safe_url(url):
        return jsonify({'error': 'URL not allowed'}), 403
    response = requests.get(url, timeout=5)
    return response.text
```

Additionally, implement network-level egress filtering to block requests to internal IP ranges.
Deserialization Attack Analysis

A Java application uses `ObjectInputStream.readObject()` to deserialize user-supplied data. Explain how an attacker could exploit this and what the defense should be.

Solution
An attacker crafts a serialized Java object that, when deserialized, triggers a gadget chain leading to remote code execution. The most famous example is the Apache Commons Collections gadget chain, which uses `InvokerTransformer` to execute arbitrary commands during deserialization.

Defense:
1. Do not deserialize untrusted data — use JSON instead
2. If deserialization is required, implement an `ObjectInputFilter` to restrict which classes can be deserialized
3. Add integrity checks (HMAC signatures) to verify the data has not been tampered with
4. Keep all dependencies updated — many gadgets exist in third-party libraries
5. Use the `serial-killer` or `SerialKiller` library as a runtime deserialization firewall

Quiz

1. What is the primary defense against SSRF attacks?

Question 1 options

2. Why are cloud metadata endpoints like 169.254.169.254 frequent SSRF targets?

Question 2 options

3. What is a gadget chain in the context of deserialization attacks?

Question 3 options

4. Which of the following is NOT a valid defense against unsafe deserialization?

Question 4 options

5. What is DNS rebinding in the context of SSRF?

Question 5 options

Flashcards

Question

What is SSRF?

Answer

Server-Side Request Forgery — coercing a server into making requests to internal hosts the attacker cannot reach directly. The server becomes a proxy that accesses internal resources on behalf of the attacker.

Question

Why are cloud metadata endpoints (169.254.169.254) dangerous in SSRF attacks?

Answer

They provide temporary IAM credentials and instance configuration without authentication. An attacker who can make the server fetch this endpoint can obtain credentials with the instance's IAM permissions.

Question

What is a gadget chain?

Answer

A sequence of existing methods in the application or its dependencies that, when called in sequence during deserialization, produce a dangerous effect like command execution. Example: Apache Commons Collections InvokerTransformer chain.

Question

What is the primary defense against SSRF?

Answer

URL validation — checking user-supplied URLs against an allow-list and blocking requests to private, loopback, and link-local IP ranges. Network-level egress filtering provides an additional layer.

Question

What is DNS rebinding in SSRF context?

Answer

An attack where a domain resolves to a public IP during validation but to an internal IP when the server fetches it, bypassing IP-based URL validation. Defense: resolve the hostname once and use the resolved IP for the actual request.

Revision Notes

Key Takeaways

  • 1. SSRF coerces a server into making requests to internal hosts the attacker cannot reach directly
  • 2. Cloud metadata endpoints (169.254.169.254) are high-value SSRF targets because they expose temporary credentials without authentication
  • 3. Primary SSRF defense: URL validation with allow-list + blocking internal IP ranges + network egress filtering
  • 4. Unsafe deserialization can lead to remote code execution via gadget chains in third-party libraries
  • 5. DNS rebinding bypasses IP-based URL validation by changing DNS resolution between validation and fetch

Interview Tips

  • • Walk through the Capital One breach (2019) as a concrete example of SSRF leading to cloud credential theft
  • • Explain why URL validation alone is insufficient — mention DNS rebinding and the need for network-level controls
  • • Discuss deserialization gadget chains with the Apache Commons Collections example
  • • Connect SSRF to cloud security — explain how IMDSv2 mitigates the metadata endpoint attack

Cheat Sheet

SSRF and Unsafe Deserialization Cheat Sheet

Phase: Web Vulnerabilities and the OWASP Top 10 | Level: advanced

SSRF Attack Targets:

  • Cloud metadata: http://169.254.169.254/latest/meta-data/
  • Internal services: Redis (6379), Elasticsearch (9200), Tomcat manager (8080)
  • File protocol: file:///etc/passwd
  • DNS rebinding: domain resolves to public IP during validation, internal IP during fetch

SSRF Defense:

  • URL validation with allow-list of permitted domains
  • Block private, loopback, link-local, and reserved IP ranges
  • Network-level egress filtering
  • Use AWS IMDSv2 (requires session token)
  • Disable unnecessary protocols (file://, gopher://)

Deserialization Defense:

  • Do not deserialize untrusted data — use JSON instead
  • HMAC integrity checks on serialized data
  • ObjectInputFilter to restrict deserializable classes (Java)
  • Keep dependencies updated (gadgets exist in third-party libraries)

Key points:

  • SSRF coerces a server into making requests to internal hosts the attacker cannot reach directly
  • Cloud metadata endpoints like 169.254.169.254 are frequent SSRF targets for credential theft
  • Deserializing untrusted data can instantiate gadgets that execute arbitrary code paths
  • DNS rebinding bypasses IP-based URL validation

Tags: ssrf, web-security

Continue Learning

Before You Start

  • No prerequisites listed.