Patchstack Weekly, Week 18: PHP Object Injection aka Insecure Deserialize

Published 2 May 2022
Updated 12 July 2023
Robert Rowley
Author at Patchstack
Table of Contents

Welcome back to the Patchstack Weekly Security Update! This update is for week 18 of 2022.

This week I will talk about an obscure vulnerability, something that is commonly overlooked and missed by developers, bug bounty hunters, and security researchers alike. PHP Object Injection, also known as Insecure Unserialize.

I will get started with this week's vulnerability news like always, we have a handful of vulnerabilities I would like to share with you. Including one report of, you guessed it PHP Object Injection.

Vulnerability news

Metform Elementor Contact Form Builder - Unauthenticated Secrets (API keys) Disclosure

Starting with the most serious security bug patched this week. Users of the Metform Elementor Contact Form Builder plugin should update this plugin ASAP.

The developers patched a security bug that could lead to some sensitive data, like the secret API keys used by the plugin if it is integrated with third-party services such as Stripe, PayPal, Mailchimp, etc…

This bug was found by Muhammad Zeeshan.

Hermit 音乐播放器 - Unauthenticated SQL Injection

This music player plugin unfortunately has multiple authenticated and unauthenticated high-risk security bugs that have no patch available.

It appears the last update from the developer was 4 years ago. So, it may have been abandoned. Users of this plugin, if you haven't already, it is time to disable the plugin and look for an alternative.

This security bug was reported through the Patchstack Alliance, by Lenon Leite

Booking Calendar - Insecure Deserialization / Object Injection

Users of the popular Booking Calendar plugin should update to the most recent release. The developers addressed a PHP Object Injection security bug that could be targeted without the need for authentication.

This security bug was reported by the team at WordFence, and Ram Gall did the write-up.

If you have never heard of PHP Object Injection or Insecure Deserialization bugs, then you are in luck. That will be the topic of this week's weekly knowledge share.

So, let's get to it.

Weekly knowledge

PHP Object Injection

Object injection security bugs are also known as insecure deserialization security bugs. Which is a better name for them, because they occur when the code base passed user-controlled data into PHP's unserialize() function.

It seems any time a function is passed user-supplied input, there is a security bug that can go along with it.

In fact, PHP's official documentation clearly states "Do not pass untrusted input to unserialize() …" in a large warning on the unserialize function's manual page.

So, let's learn a little more about how this works and what we can do to secure against it.

How does serialize/unserialize work?

The purpose of the unserialize function is to re-create a PHP variable, object, or other value from a string-based or "serialized" representation of that value.

A project may need to store a PHP value, but we can't just save complex values like arrays, or objects to the database directly. So you use serialize() first to create the string representation which can easily be stored somewhere (like the database) then retrieved at a later point and instantiated using the unserialize() function.

How can that go wrong?

Serialized values stored and retrieved from trusted storage sources, like memory or the database, are fine. But, if the serialized value is stored with a browser, such as in a cookie or POST/GET variables, well, the user controls the value.

If the user controls the value in the browser, they can modify it to anything. When this modified serialized value is sent back to the program, PHP has no way to detect if it was modified. So, PHP will re-instantiate the value to whatever the user modified it to.

PHP Object Injection

This is already starting to look bad, users shouldn't be able to manipulate objects or variables you are storing …. But, It gets worse …

POP chains

The value being instantiated can be ANY PHP value. It could be an object defined by any class which is defined by any plugin or theme installed on the WordPress website.

If an attacker is aware of a class in the site's code-base that let's say, uploads a file when instantiated (via Constructor and Destructor functions).

Then that leads to the situation where an attacker could trick PHP via the insecure unserialize attack vector, to create the object that uploads and files when instantiated.

This is called a POP chain, or originally a gadget chain, sometimes I've heard it called POP Gadget too. It really just means "the Class that is used in conjunction with PHP Object Injection attacks, or deserialization attacks.", a badly defined term used for "the Class that ".

When a website has both an insecure unserialize and a POP chain within its codebase, that is what leads to site compromises.

Securing against PHP Object Injection

Luckily, the fix is easy.

If you can store the serialized string in the database, or another place the user can not modify, then it is safe to use.

If you must store the data in the browser, that's OK, but use a format intended for data exchange such as json_encode() and json_decode(). If you must store serialized data with the browser for some reason, then please verify that the value has not been tampered with before re-instantiating it.

This can be done by storing a hash of the serialized string you send to the browser, and validating that the serialized string the browser sends back matches an existing hash in your records. Or some other data tampering detection method of your choosing.

Insecure Unserialize often looked over

Insecure Unserialize attacks are easy to downplay, due to the requirement of the POP chain. A plugin with an insecure usage of unserialize() likely does not introduce a PHP Class acceptable for attackers to create a POP chain with.

However, any other plugin or theme added to the website could add the class needed for a dangerous POP chain to exist. It is best to not overlook the risk of insecure unserialize() security bugs.

PHP Object Injection

Attackers that can target an insecure unserialize() function, especially un-authenticated, will target that endpoint. I wrote about first-hand experiences with active attacks against PHP Object Injection vulnerabilities in 2016-2017 when handling outbreaks of Object Injection attacks at Pagely.

It has been 5 years, and insecure usages of unserialize() are still being found. If you would like to help secure open-source websites, then you can look for instances of user-supplied inputs being sent to the unserialize() function.

If you find one, I would love to know, you can report it to the Patchstack Alliance, and if you do, let me be the first to welcome you to the world of security bug bounty hunting.

Thanks and appreciation

This week's thanks go out to the developers of the Booking Calendar plugin, thank you for patching that PHP Object Injection security bug and for giving me this week's knowledge share topic.

Thank you as well to the developers of the Metform Elementor Contact Form Builder plugin, Thank you for patching that serious security bug and protecting your users' websites.

Finally, an extended thank you to the existing and new members of the Patchstack Alliance. Some of the top security researchers in the last month were:

  • Muhammad Daffa
  • Nguy Minh Tuan
  • Tien Nguyen Anh
  • Ngo Van Thien
  • Rasi Asef
  • Huli

Our newest member is from Taiwan and already reported a Remote Code Execution security bug which you will learn about after the disclosure process is complete.

I will be back next week with more security tips, tricks, opinions, and news on the Patchstack Weekly security update!

The latest in Patchstack Weekly

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.