The WordPress Function maybe_unserialize() Won’t Prevent PHP Object Injection
Recently, an update was released for a WordPress plugin that had a changelog that said the new version addressed a PHP object injection vulnerability by using the WordPress function maybe_unserialize(). That function doesn’t accomplish that. The developer then made a second attempt to address the vulnerability, which did fix it. To better understand why maybe_unserialize() won’t address that, let’s look at how they managed to fix it.
The code passes user input to the function unserialize():
13 14 15 | $subscribeToken = urldecode($_GET['subscribeToken']) $token = openssl_decrypt(str_replace(" ","+",$subscribeToken),'aes128',$apiKey); $dataNewContact = unserialize($token); |
The PHP documentation warns about the danger of PHP object injection if malicious input is passed to that function:
Unserialization can result in code being loaded and executed due to object instantiation and autoloading, and a malicious user may be able to exploit this.
The best option for code like that is to replace unserialization and connected serialization, with JSON decoding and JSON encoding. That is what the PHP documentation recommends. But you can also instruct PHP not to unserialize objects, by setting an option. This is what the developer did in their second attempt to fix this:
15 | $dataNewContact = unserialize($token, array('allowed_classes' => false)); |
If you look at the code of maybe_unserialize() you can see that it doesn’t set that option when using unserialize():
function maybe_unserialize( $data ) { if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in. return @unserialize( trim( $data ) ); } return $data; } |
It also doesn’t try to stop PHP object injection from occurring in any other way.
To recap, in most cases, use JSON encoding/decoding instead of serialization/unserialization. But if you can’t, set the option to instruct PHP to not unserialize objects. Using maybe_unserialize() instead won’t work to prevent PHP object injection from occurring.