CVE-2020-28032 (published 2020-11-02T21:15Z)

WordPress before 5.5.2 mishandles deserialization requests in wp-includes/Requests/Utility/FilteredIterator.php.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-502
cwe_name: Deserialization of Untrusted Data
description: The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
extended_description: 
            It is often convenient to serialize objects for communication or to save them for later use. However, deserialized data or code can often be modified without using the provided accessor functions if it does not use cryptography to protect itself. Furthermore, any cryptography would still be client-side security -- which is a dangerous security assumption.
            Data that is untrusted can not be trusted to be well-formed.
            When developers place no restrictions on "gadget chains," or series of instances and method invocations that can self-execute during the deserialization process (i.e., before the object is returned to the caller), it is sometimes possible for attackers to leverage them to perform unauthorized actions, like generating a shell.
         
         

Fix information:
repo_url: https://github.com/WordPress/wordpress-develop
commit_details: repo_url: https://github.com/WordPress/wordpress-develop
author: Jonathan Desrosiers
author_date: 2020-10-29 17:58:49+00:00
msg: External Libraries: Disable deserialization in Requests_Utility_FilteredIterator

Props xknown, peterwilsoncc, desrosj, dd32, whyisjake.
Merges [49373] to trunk.

git-svn-id: https://develop.svn.wordpress.org/trunk@49382 602fd350-edb4-49c9-b593-d223f7449a82
repository: repo_url: https://github.com/WordPress/wordpress-develop
repo_name: WordPress/wordpress-develop
description: WordPress Develop, Git-ified. Synced from git://develop.git.wordpress.org/, including branches and tags! This repository is just a mirror of the WordPress subversion repository. Please include a link to a pre-existing ticket on https://core.trac.wordpress.org/ with every pull request.
repo_language: PHP
owner: WordPress
file_changes: filename: FilteredIterator.php
change_type: ModificationType.MODIFY
diff: @@ -42,4 +42,20 @@ class Requests_Utility_FilteredIterator extends ArrayIterator {
 		$value = call_user_func($this->callback, $value);
 		return $value;
 	}
+
+	/**
+	 * @inheritdoc
+	 */
+	public function unserialize( $serialized ) {
+	}
+
+	/**
+	 * @inheritdoc
+	 */
+	public function __unserialize( $serialized ) { // phpcs:ignore PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.MethodDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.NewMagicMethods.__unserializeFound
+	}
+
+	public function __wakeup() { // phpcs:ignore PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.MethodDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.NewMagicMethods.__wakeupFound
+		unset( $this->callback );
+	}
 }

programming_language: PHP
filename: functions.php
change_type: ModificationType.MODIFY
diff: @@ -269,6 +269,35 @@ class Tests_Functions extends WP_UnitTestCase {
 		$this->assertSame( $expected, is_serialized( $value ) );
 	}
 
+	/**
+	 * @dataProvider data_serialize_deserialize_objects
+	 */
+	function test_deserialize_request_utility_filtered_iterator_objects( $value ) {
+		$serialized = maybe_serialize( $value );
+		if ( get_class( $value ) === 'Requests_Utility_FilteredIterator' ) {
+			$new_value = unserialize( $serialized );
+			if ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
+				$property = ( new ReflectionClass( 'Requests_Utility_FilteredIterator' ) )->getProperty( 'callback' );
+				$property->setAccessible( true );
+				$callback_value = $property->getValue( $new_value );
+				$this->assertSame( null, $callback_value );
+			} else {
+				$current_item = @$new_value->current(); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
+				$this->assertSame( null, $current_item );
+			}
+		} else {
+			$this->assertEquals( $value->count(), unserialize( $serialized )->count() );
+		}
+	}
+
+	function data_serialize_deserialize_objects() {
+		return array(
+			array( new Requests_Utility_FilteredIterator( array( 1 ), 'md5' ) ),
+			array( new Requests_Utility_FilteredIterator( array( 1, 2 ), 'sha1' ) ),
+			array( new ArrayIterator( array( 1, 2, 3 ) ) ),
+		);
+	}
+
 	function data_is_serialized() {
 		return array(
 			array( serialize( null ), true ),

programming_language: PHP