Make WordPress Core

Opened 2 months ago

Closed 2 months ago

#62970 closed enhancement (duplicate)

Adding Defense-in-Depth against PHP Object Injection

Reported by: francescocarlucci's profile FrancescoCarlucci Owned by:
Milestone: Priority: normal
Severity: normal Version:
Component: Security Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

The WordPress core function maybe_unserialize() uses PHP unserialization in an insecure way, and I think we are all well aware of that.

The reason is that PHP unserialize automatically instantiates any object received as input, and if the object uses magic methods it can lead to RCE, file deletion and other dangerous security issues. In the last year there were hundreds of security vulnerabilities caused by unsafe use of maybe_unserialize(), and with this ticket I want to propose a fix at core level, which in my opinion is easy straightforward :)

PHP unserialize() accepts a second parameter allowed_classes that can be set to false to disallow automatic class instantiation, or can be restricted to specific classes.

So we can tweak maybe_unserialize() this way:

<?php
function maybe_unserialize( $data ) {
if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
  $allowed_classes = apply_filters( 'maybe_unserialize_allowed_classes', false );
  return @unserialize( trim( $data ), [ 'allowed_classes' => $allowed_classes ] );
}
    
return $data;
}

This way allowed_classes is false by default and can be hooked to true or a set of classes, this would be a security-first approach.

Other ways, we can have a backward-compatibility first approach:

<?php
function maybe_unserialize( $data ) {
if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
  $allowed_classes = apply_filters( 'maybe_unserialize_allowed_classes', true );
  return @unserialize( trim( $data ), [ 'allowed_classes' => $allowed_classes ] );
}
    
return $data;
}

And then site owners can harden their WP instance with this one-liner:

<?PHP

add_filter( 'maybe_unserialize_allowed_classes', '__return_false' );

To restrict instantiations to specific classes, plugins could hook in like this:

<?php
add_filter( 'maybe_unserialize_allowed_classes', function() {
    return ['MyClass', 'AnotherClass', 'SomeOtherClass'];
});

Anything else needed to merge it in the core? Does anyone see anything that could go wrong?

Thanks,
Francesco

Change History (4)

This ticket was mentioned in PR #8332 on WordPress/wordpress-develop by @sukhendu2002.


2 months ago
#1

  • Keywords has-patch has-unit-tests added

This pull request introduces the maybe_unserialize_allowed_classes filter to enhance security by providing control over which classes can be instantiated during unserialization. This helps to mitigate potential PHP Object Injection vulnerabilities.

Trac ticket: https://core.trac.wordpress.org/ticket/62970

#2 follow-up: @siliconforks
2 months ago

This is similar to #37757.

#3 in reply to: ↑ 2 @FrancescoCarlucci
2 months ago

Replying to siliconforks:

This is similar to #37757.

Thanks for letting me know! Should I keep the discussion on the other ticket?

#4 @johnbillion
2 months ago

  • Milestone Awaiting Review deleted
  • Resolution set to duplicate
  • Status changed from new to closed

Agreed, let's close this off as a duplicate of #37757. Thanks!

Note: See TracTickets for help on using tickets.