Diving into unserialize(): POP Chains
Last time, we talked about how PHP’s unserialize() can introduce serious vulnerabilities if it is given user-controlled input.
In a nutshell, when an attacker controls a serialized object that is passed into unserialize(), she can control the properties of the created object. This will then allow her the opportunity to hijack the flow of the application, by controlling the values passed into magic methods like __wakeup().
This works… sometimes. The problem is this: what if the declared magic methods of the class do not contain any useful code in terms of exploitation? Then the unsafe deserialization is useless and the exploit is bust, right?
Unfortunately, even if the magic methods themselves are not exploitable, an attacker could still wreak havoc using something called POP chains. POP stands for Property Oriented Programming, and the name comes from the fact that the attacker can control all of the properties of the deserialized object. Similar to ROP attacks (Return Oriented Programming), POP chains work by chaining code “gadgets” together to achieve the attacker’s ultimate goal. These “gadgets” are code snippets borrowed from the codebase that the attacker uses to further her goal.
An example chain
POP chains use magic methods as the initial gadget, which then calls other gadgets. Consider the following example:
class Example
{
private $obj;
function __construct()
{
// some PHP code...
}
function __wakeup()
{
if (isset($this->obj)) return $this->obj->evaluate();
}
}class CodeSnippet
{
private $code;
function evaluate()
{
eval($this->code);
}}
// some PHP code...
$user_data = unserialize($_POST['data']);
// some PHP code...
In this example, there are two classes defined: Example and CodeSnippet.