Blog Details

Demystifying PHP Object Injection

Hello readers, in this blog post, our consultant Aditya has discussed the PHP Object Injection vulnerability. He explains the vulnerability details, minimum requirements, vulnerability techniques, vulnerability chaining with other vulnerabilities, recommendations, practice labs, and much more.

PHP's popularity has been consistent since its beginning, and statistics show that it is a preferred language for many web application developers. This is one of the reasons why PHP has long piqued the curiosity of the information security community. Another reason PHP is well-known in the information security field is because of its use in various Content Management Systems (CMS), the source codes for which are publicly available on platforms such as GitHub. Since the source codes are open source in nature, several vulnerabilities have been uncovered that are particular to applications and systems that use PHP as their preferred language.

The variety and number of vulnerabilities discovered in PHP-based applications are significant. However, not all of the discovered vulnerabilities are easy to comprehend and detect, and hence the majority of security professionals and developers overlook or ignore those vulnerabilities. PHP Object Injection is one such vulnerability that falls into this category, which we will discuss in this blog so that the reader has a better understanding of this obscure vulnerability, why it exists, and how an attacker might exploit it. In addition, we have created a compilation of four practice labs on our platform Vulnmachines where you may navigate and gain hands-on experience with various real-life scenarios.


  1. PHP Object Injection occurs as a result of the deserialization of data from insecure sources, such as user-supplied input, and the absence of integrity verification measures.
  2. PHP Object Injection makes use of magic methods, which are predefined PHP methods that help in the exploitation of this vulnerability.
  3. Several vulnerabilities such as Command Injection, Path Traversal, Authentication Bypass, and others can be chained with PHP Object Injection to enhance the impact.
  4. An intentionally vulnerable testing playground is available on Vulnmachines for hands-on practice.

Serialization vs Deserialization

Before delving into the jargon of PHP Object Injection, we must first understand serialization and deserialization, as these terms will be used frequently, and this blog will appear as rocket science if these concepts are not clear.

The objects in modern-day web applications are shared among modules, therefore they must be sent across the wire. As objects typically have multiple pieces, writing the code to handle the delivery of each portion can be tedious. Serialization provides us with the ability to preserve and uniformly transfer an object's state. In contrast, Deserialization allows us to reconstruct these objects that have been serialized for communication over the internet, across apps, over firewalls, and other applications.

Now that we know what serialization and deserialization are, let's take a deeper dive into them and learn how they function in PHP and how PHP uses them to serialize and deserialize objects.

Serialization and the serialize() method

Serialization is the process of transforming an object into a value representation to store it in a memory buffer or transfer it to a database, via a network, or to a file. When serialization is performed it is ensured that the state of the object is also maintained, which implies that the properties of the object, as well as their allocated values, are retained. The primary goal of serialization is to store an object's state, so that it may be recreated when needed.

The serialize() method in PHP accepts a single parameter which is the data we want to serialize and converts it into a storable representation of value that can be returned by the method as a serialized string. Other than resource-type data, such as references to external resources and certain objects, the serialize() method can handle all types of values. 

The table below outlines the basic structure of a PHP serialized string, which will assist in understanding the serialized strings explained in the subsequent code samples throughout the log post.




Represents an object with the length of class name as 4


Represents the parameter name as a string of 4 characters i.e., “test”


Represents an array of 2 elements


Represents an element at index two


Represents a Boolean


Represents a Float

The following table summarizes the technical details associated with the serialize() method:



Parameter Value


Return Type


Return Value

A String of byte-stream representation of the specified parameter value, which could be stored anywhere.


The preceding code snippet creates a SerializationExample class object and then generates the serialized string representation of that object:


A better understanding of the above-serialized string representation of the object can be obtained from the below table:




Represents an object with the length of class name as 20


Represents the parameter name as a string of 4 characters i.e., “data”


Represents an array of 3 elements


Represents an element at index zero

Deserialization and the unserialize() method

Deserialization is the process of reassembling an object or data structure from a single serialized variable into a PHP value.

When a serialized string containing an object and its properties is passed to the unserialize() method, the unserialize() method will perform Object Instantiation, which is the process of recreating an instance of the provided initially serialized object in memory. Once the object has been recreated in memory, PHP will attempt to invoke the __wakeup() magic method and execute the code in the __wakeup() method; if a __wakeup() method exists, the code will be performed in the existing method.

The __wakeup() magic method can recreate any properties that the original object has had. The__wakeup() magic method is meant to be used to restore any database connections that may have been lost during serialization and to execute additional reinitialization operations. When no reference to the deserialized object instance exists, the __destruct() magic method of that class is invoked.


The preceding code snippet recreates the SerializationExample class object from the serialized string representation of that object.

The following table summarizes the technical details associated with the unserialize() method:


unserialize(string, options)

Parameter String

Mandatory (Serialized String)

Parameter options

Optional (Could be an array of class names, false for no classes and true for all classes)

Return Type

String, Boolean, Array, Float, Integer, or Object

Return Value

The unserialized value

What is PHP Object Injection?

When the user-supplied input is not properly validated and sanitized before being sent to the unserialize() PHP function, PHP Object Injection occurs. Since PHP supports object serialization, attackers could supply arbitrary serialized strings to a susceptible unserialize() method, resulting in the injection of arbitrary PHP object(s) into the application. PHP Object Injection allows for the unrestricted alteration of object content, which must be unserialized using the PHP unserialize() function.


The following prerequisites must be satisfied in order to properly exploit a PHP Object Injection vulnerability:

  • On the injection points, the application must not have a comprehensive input validation mechanism.

  • The application must not validate the serialized data's integrity and must enable deserializing data from untrusted sources.

  • A class that implements at least one PHP magic method must be present in the vulnerable application (In the parts that follow, there will be further information about these).

  • All of the classes used during the attack must be declared when the vulnerableunserialize() is being called, otherwise object autoloading must be supported for such classes.


The impact of PHP Object Injection depends largely on the context where it is discovered; however, it enables an attacker to execute a variety of malicious attacks, including but not limited to Code Injection, SQL Injection, Path Traversal, and Application Denial of Service, among others.

Since we now understand what PHP Object Injection is and what prerequisites must be satisfied for it to exist, and what impact it has, let us now look at the showstopper, i.e., the magic methods, which play a critical part in the existence of this exotic vulnerability.

Magic Methods

PHP magic methods are methods that are automatically invoked when specific criteria are satisfied. As they are predefined methods, one cannot have functions with these names in any of the classes unless users desire the accompanying magic functionality. A magic method is easily distinguished from conventional methods since it begins with a double underscore in PHP.

PHP includes 15 magic methods that can lead to PHP Object Injection, all of which are listed in the table below:

Magic Method



When a non-existing or inaccessible method is called by an object, PHP will automatically invoke the __call() magic method using the name of the method you requested to call and the argument you provided as parameters.

The below-mentioned code snippet utilizes the getAnyRandomData method, which is not declared anywhere in the above code snippet, and therefore the __call() magic method is invoked.


When an inaccessible static method of a class is called by an object, PHP will automatically invoke the __callStatic() method.

The below-mentioned code snippet utilizes the getAnyRandomData static method, which is not declared anywhere in the above code snippet, and therefore the __callStatic() magic method is invoked.


When an object is cloned in PHP with the clone keyword, the __clone() magic method is invoked. After the object has been cloned, the __clone() magic method is used to manipulate the object's state.

The below-mentioned code snippet utilizes the ‘clone’ keyword as a result of which PHP invokes the __clone() magic method.


Due to the fact that it is used to configure a class when it is initialized, PHP's __construct() method is the most frequently used magic method. Classes with a constructor method utilize this method on newly formed objects, making it ideal for any initialization that the object may require before it is utilized. Classes with a ‘constructor’ method utilize this method on newly formed objects, making it ideal for any initialization that the object may require before it is utilized.

The below-mentioned code snippet utilizes the __construct() magic method which is invoked by PHP when the object of the constructMagicMethod class is created.


The __debugInfo() magic method is executed when an object is utilized inside the var_dump() method to dump information for debugging purposes. The __debugInfo() magic returns an array of variables that might be helpful while performing debugging.

The below-mentioned code snippet utilizes the __debugInfo() magic method which is invoked by PHP when the object of the debugInfoMagicMethod class is used inside thevar_dump()method as a parameter.


PHP automatically invokes the __destruct() magic method when the object is destroyed at the end of the program and no longer serves usage.

The below-mentioned code snippet utilizes the __destruct()magic method which is automatically invoked by PHP when the object of the destructMagicMethod class is destroyed at the end of the program and no longer serves usage.


The __get() magic method is invoked when an inaccessible private or protected variable, or a variable that does not exist, is used.

The below-mentioned code snippet utilizes the __get() magic method inside the getMagicMethod class which is invoked by PHP when a non-existing variable is used.


When an object is treated as a function, the __invoke() magic method is called. The major function of the __invoke() method is that you may implement it if you wish to represent your objects as callable.

The below-mentioned code snippet utilizes the __invoke() magic method which is called automatically by PHP when the object of the invokeMagicMethod class is treated as a function.


The __isset() magic method is triggered when a call is made to the empty() or isset() method on an inaccessible or non-existent object property.

The below-mentioned code snippet uses the isset() function on the Test property, which is absent from the issetMagicMethod class, and thus the __isset() magic method is triggered.


When an inaccessible variable, such as a private or public variable, or a non-existent variable, is edited or altered, PHP automatically invokes the __set()magic method.

The below-mentioned code snippet utilizes the __set() magic method inside the setMagicMethod class which is invoked automatically by PHP when a non-existing variable i.e., $absentVariable is used or altered.


The __set_state() magic method is a static method that works with the var_export() function. When using this magic method to export classes, the var_export() function must be specified in the class.

In the below-mentioned code snippet PHP automatically invokes the __set_state() magic method when the object of the ‘setstateMagicMethod’ class is passed to the var_export() function.


The __sleep() magic method is triggered when the serialize() function is invoked on an object. Specific properties are saved during serialization under certain cases, and the __sleep() magic method returns an array containing the names of properties that must be serialized.

The below-mentioned code snippet utilizes the __sleep() magic method which will be invoked when the object of the sleepMagicMethod class will be passed to the serialize() function and only the properties i.e., firstName, middleName, and lastName will be preserved.


When an object is represented or processed as a string, PHP automatically invokes the __toString() magic method. Essentially, this magic method assists in expressing what must be showcased when the object is processed as a string. If the __toString() magic method is not available and the class object is used by ‘print’ or echo, an error message will be displayed.

The below-mentioned code snippet utilizes the __toString() magic method, which is invoked automatically by PHP when the object of the toStringMagicMethod is passed to echo’ and therefore treated as a string.


PHP invokes the __unset() magic method when an unset() function is used on an inaccessible private, protected, or non-existent object property.

The code snippet below invokes the unset() function on the Test property, triggering the __unset() magic method, which restores the Test property's original state.


When the unserialize() function is invoked on the object, the __wakeup() magic method is intended to re-establish any connections that may have been lost during serialization and perform other reinitialization tasks.

The code snippet below utilizes the connectionmethod()function, which is used by the __wakeup() magic method, to re-establish the connection when the unserialize() function is implemented to the wakeupMagicMethod’ class object.

PHP Object Injection Samples

As we understand what PHP Object Injection is and how insecure deserialization and magic methods in PHP are the underlying cause, let us look at some vulnerable PHP Object Injection samples to get an understanding of what PHP Object Injection can lead to.

Authentication Bypass via Object Reference

The following example demonstrates the PHP class POI2IDOR with an exploitable ‘unserialize()’ method. In line 9 of the code snippet below, we observe that the data from the inputparameter is deserialized in an unsecured way, which is then given to an if conditional statement on line 12 that is subject to Type Juggling. When a specifically designed serialized object is supplied in this example, an attacker might be able to obtain an object reference for accomplishing an authentication bypass, for example, by accessing the following URL:{s:15:"adminsecretcode";N;s:4:"misc";R:2;}

Vulnerable Code Snippet:

Path Traversal

The below-mentioned example demonstrates a PHP class POI2PT with an exploitable __destruct() magic method spanning from line 5 to line 10. When a specifically constructed serialized object is supplied in this example, an attacker might be able to perform Path Traversal, by browsing the following URL:"POI2PT":1:{s:12:"existingfile";s:22:"../../../../etc/passwd";}

Vulnerable Code Snippet:

Authentication Bypass via Type juggling

The following example demonstrates an exploitable unserialize method. When a specifically constructed serialized object is supplied using a POST request, an attacker will be able to perform an authentication bypass with the help of type juggling as the comparison statement on line 5 appears to be loosely comparing the data. The HTTP request for exploiting this misconfiguration will be similar to the one mentioned below:

Vulnerable Code Snippet:

POST Request:

Arbitrary Code Injection

As seen in the following example, the PHP class POI2CI includes an exploitable __destruct() magic method from line 7 to line 9. When a precisely configured serialized object is supplied in this code snippet, the application will seek references to the receivedinput object, and once there are no more references, the __destruct() magic method will be called, resulting in the execution of the injected command.

The attacker will be able to obtain command injection, by accessing the following URL: inputparameter=O:6:"POI2CI":1:{s:16:"arbitrarycommand";s:2:"id";}

Vulnerable Code Snippet:

PHPGGC: PHP Generic Gadget Chains

PHPGGC is a deserialization payload library that includes a tool for generating them from the command line or programmatically. This may be used to produce Property Oriented Programming (POP) gadgets from libraries that users have already discovered. While facing unserialize on a website for which you do not have the source code, or simply when attempting to develop an attack, this tool allows you to produce the payload without having to go through the time-consuming procedures of locating and assembling gadgets.

CodeIgniter4, Doctrine, Drupal7, Guzzle, Laravel, Magento, Monolog, Phalcon, Podio, Slim, SwiftMailer, Symfony, WordPress, Yii, and ZendFramework are all supported by PHPGGC. Additionally, PHPGGC requires a PHP version greater than or equivalent to 5.6 for proper functioning.

The attributes associated with a gadget chain generated by the PHPGGC library are described in the table below:




Name attribute specifies the framework or library that the gadgets are intended for.


Version attribute specifies the framework or library version for which the gadgets are intended.


Type attribute describes the sort of exploitation the gadget chain would result in, such as Remote Code Execution, Arbitrary File Deletion, Server-Side Request Forgery, and so on.


Vector attribute describes the PHP magic method that will be used to initiate the chain following the unserialize operation on the specified input.


Information attribute describes any extra detail associated with the gadget chain.

At the time of writing, the PHPGGC library has 94 gadget chains associated with various frameworks and libraries that it could exploit. The list of available gadget chains in PHPGGC can be obtained by executing the below-mentioned command:

Depending on the application technology, we can also use the following command to filter the gadget chain available in the PHPGGC that is most suited for testing:

PHPGGC provides a -i flag that can be used to retrieve additional information about the specified gadget chain using the command below:

On a high level, PHP Object Injection Exploitation Using PHPGGC includes the following activities:

  1. Detection of the framework or library in use.

  2. Identification of a possible injection point, such as a parameter, cookie, or Header.

  3. Additional attack preparation, such as a reverse shell or a backdoor, which will be uploaded to the application server upon successful exploitation of the vulnerability.

  4. Custom serialized object creation using PHPGGC.

Interesting Real World Scenarios

Over time, security experts worldwide have discovered several instances of PHP Object Injection vulnerability, some of which could be exploited to achieve Remote Code Execution, Authentication Bypass, etc. Some of the most significant cases of the PHP Object Injection vulnerability are described below, which will aid in acquiring a better understanding of this vulnerability and knowing some of the finest publicly known exploits.

Data Tampering through PHP Object Injection

WooCommerce is a WordPress e-commerce plugin. It simplifies the process of developing and administering an online store by providing decent levels of flexibility as well as various important features such as inventory and tax administration, secure payments, and shipping integration.

In this case, the security researcher was testing the order feature in the WooCommerce WordPress plugin and discovered that the PHP native unserialize method allows small o as an option and treats it as a StdClass object.

Vulnerable Code Snippet:

Using the obtained knowledge about the small o as an option, the security researcher constructed a bypass that allowed them to tamper with any ‘order’ object. In addition, when paired with capital S, existing firewall rules failed, causing the firewall to be bypassed.

Proof of Concept Code:

Type Juggling Chained with PHP Object Injection for SQL Injection

ExpressionEngine is a robust and flexible open-source Content Management System. ExpressionEngine has a large community of developers making add-ons that extend system capabilities.

In this scenario, when the security researcher attempted to log in with the username 'admin,' the server responded with a cookie containing PHP serialized data. The researcher then downloaded and installed a copy of the application for further analysis. After walking through the code, the researcher discovered that a few checks were done before the cookie was parsed and subsequently unserialized. Further investigation revealed that a cookie integrity validation mechanism was in place, ensuring that the cookie was not tampered with. Since the application was written in PHP, a loosely typed language, using the loose comparison operator resulted in the comparison evaluating as true because 0ex will always be zero when cast to integers, a process known as Type Juggling.

The researcher then created the following proof of concept, which brute forces the md5($payload.$this->sess_crypt_key) until an MD5 hash sum of the updated $payload and $this->sess_crypt_key that starts with ‘0e’ and ends in all digits was discovered:

Proof of Concept Code:


When the researcher compared the MD5 hash sum to any $signature value, they discovered that the original $payload was successfully updated, confirming the existence of Type Juggling and PHP Object Injection.

The researcher discovered a method that appears to be checking the database to see if the given ‘$username’ is locked out pre-authentication. Since the researcher got access to the value of ‘$username’ and he was able to inject a SQL query there, it resulted in SQL injection.

Following an additional inspection of the source code and multiple hit-and-try efforts, the researcher constructed the Proof of concept code shown below to insert the ‘sleep(5)’ command into the database:

Proof of Concept Code:



The researcher then submitted the below-mentioned payload through the ‘exp_flash’ cookie generated by the preceding proof of concept code and observed that the response was shown after 5 seconds, confirming the vulnerability:

Object Injection to Pre-Auth Remote Code Execution in Moodle

Moodle is a learning platform that aims to give educators, administrators, and learners a unified, secure, and integrated system for creating personalized learning environments.

In this scenario, the researcher discovered that Moodle's Shibboleth authentication module was vulnerable to Remote Code Execution through a PHP Object Injection vulnerability. The vulnerability was discovered in the logout handler in the logout_file_session function spanning from line 17 to line 22, since the file handler traverses all session files. Each session file holds a single serialized session object. The handler handles this by reading each file and deserializing its data using the ‘unserializesession’ function. When a matching session ID in a session object is identified, the relevant file is unlinked, resulting in a logged-out session, as shown in the below-mentioned code snippet:

The code fails to properly parse the serialized value of a session key if it contains an unexpected Pipe ‘|’ character, introducing the risk of the parser misinterpreting the beginning and end of a serialized value within the session object, leading to the deserialization of potentially user-controlled input.

The researcher sent the payload xxx|O:8:"Evil":0:{} which was saved in the $_SESSION object of an unauthenticated guest user, which the session handler then serialized and stored on the filesystem in the form USER|O:8:"stdClass":…:{…} SESSION|O:8:"stdClass":…:{… s:…:"filterfirstname";s:19:"xxx|O:8:"Evil":0:{}";…}, confirming the PHP Object Injection vulnerability which was then exploited for obtaining Remote Code Execution.

Practice Labs

Being a team of Advanced Penetration Testers and Security Researchers, we strongly believe in a hands-on approach to cyber security and therefore we have published a compilation of four PHP Objection labs on our platform Vulnmachines for the readers to learn PHP Object Injection by practicing in labs that mimic real-life circumstances. 

The practice labs relevant to PHP Object Injection are listed below and can be accessed by navigating to Vulnmachines:

  • Demystifying PHP Object Injection (Why So Serialize)

Mitigations and Best Practices

  • Deserializing user input should be avoided unless necessary.

  • When deserializing data from untrusted sources, avoid using the ‘unserialize()’ method with user-supplied input and instead use the ‘json_decode()’ and ‘json_encode()’ methods.

  • Implement a verification mechanism for serialized data before deserializing it from any untrusted source, such as user input.



Secure your Company from Cyber Attacks

Contact Us
shape img