CVE-2020-28032: Deserialization of Untrusted Data (CWE-502)
value: WordPress before 5.5.2 mishandles deserialization requests in wp-includes/Requests/Utility/FilteredIterator.php.
CWE description: The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
CVSS v3 base score: 9.8
Published: 2020-11-02T21:15Z
Repository: https://github.com/WordPress/wordpress-develop
Language: PHP
Files changed: src/wp-includes/Requests/Utility/FilteredIterator.php, tests/phpunit/tests/functions.php
Commit date: 2020-10-29 17:58:49 +0000
Commit message: 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

Diff: diff --git a/src/wp-includes/Requests/Utility/FilteredIterator.php b/src/wp-includes/Requests/Utility/FilteredIterator.php
index 76a29e7228..0e27944932 100644
--- a/src/wp-includes/Requests/Utility/FilteredIterator.php
+++ b/src/wp-includes/Requests/Utility/FilteredIterator.php
@@ -40,6 +40,22 @@ class Requests_Utility_FilteredIterator extends ArrayIterator {
 	public function current() {
 		$value = parent::current();
 		$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 );
+	}
 }
diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php
index ffd533ebec..4301214358 100644
--- a/tests/phpunit/tests/functions.php
+++ b/tests/phpunit/tests/functions.php
@@ -267,10 +267,39 @@ class Tests_Functions extends WP_UnitTestCase {
 	 */
 	function test_is_serialized( $value, $expected ) {
 		$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 ),
 			array( serialize( true ), true ),
 			array( serialize( false ), true ),

Fixed code: 
	/**
	 * @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 );
	}
	/**
	 * @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 ) ) ),
		);
	}