flawopen.com/ssrf/Php

● CWE-918 · Hoch
Sicherheitsforschung · FlawOpen

Server-Side Request Forgery in PHP

How curl_exec in PHP exposes internal networks, and how to filter IPs using FILTER_VALIDATE_IP and CURLOPT_FOLLOWLOCATION.

💡 Einfache Erklärung (ELI5)

Stellen Sie sich vor, Sie schicken einen Boten, um ein Paket in einem öffentlichen Geschäft abzuholen, geben ihm aber die Adresse des Tresors im Büro des Geschäftsführers. Da der Bote einen internen Ausweis besitzt, öffnet er den Tresor und händigt Firmengeheimnisse aus.

Kernkonzepte & Begriffe

Web Application Security
Kernkomponente der Architektur, die von CWE-918 betroffen ist.
CWE-918
Standardmäßige Common Weakness Enumeration (CWE)-Klassifizierung für ssrf-php.
Defense-in-Depth
Mehrschichtige technische Verifikation und Laufzeit-Grenzenisolation.

Schritt-für-Schritt Angriffsablauf

Step 1

Eingabe Nicht Vertrauenswürdiger URLs

Die Anwendung akzeptiert externe URL-Parameter für Webhooks, Avatare oder PDF-Voransichten.

Step 2

Adressierung Interner Netzwerke

Der Angreifer übergibt eine Ziel-URL auf Cloud-Metadaten oder interne Loopback-Adressen (z. B. http://169.254.169.254/latest/meta-data/).

Step 3

Ungefilterter Socket-Ausgang

Der HTTP-Client des Servers sendet die Anfrage aus der geschützten VPC, ohne die Ziel-IP gegen private Subnetzbereiche abzugleichen.

Step 4

Exfiltration von Cloud-Zugangsdaten

Der interne Metadatendienst vertraut der Server-Anfrage und liefert temporäre IAM-Schlüssel und Tokens zurück.

Quellcode: Verwundbar vs. Sicher

✕ VERWUNDBARE IMPLEMENTIERUNG
<?php
// VULNERABLE: file_get_contents on user-controlled URL
$url = $_GET['url'];

// Attacker input: http://169.254.169.254/latest/meta-data/
$content = file_get_contents($url);

echo $content;
?>
✓ GEHÄRTETER SICHERHEITS-PATCH
<?php
// HARDENED: Parse URL, resolve DNS, filter private IPs, and disable redirects
$url = $_GET['url'] ?? '';

$parsed = parse_url($url);
if (!$parsed || !in_array(strtolower($parsed['scheme'] ?? ''), ['http', 'https'], true)) {
    http_response_code(400);
    exit('Invalid URL scheme');
}

$host = $parsed['host'] ?? '';
$ips = gethostbynamel($host);

if (!$ips) {
    http_response_code(400);
    exit('Unable to resolve host');
}

// Check every resolved IP address
foreach ($ips as $ip) {
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
        http_response_code(403);
        exit('Access to private/internal address denied');
    }
}

// Fetch using cURL with redirects disabled
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => false, // Prevent redirect bypasses
    CURLOPT_TIMEOUT        => 3,
    CURLOPT_PROTOCOLS      => CURLPROTO_HTTP | CURLPROTO_HTTPS,
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>

Checkliste für Engineering & Systemsicherheit

References