Chaîne personnalisée pour une désérialisation PHP (gadget chain)

Developing a custom gadget chain for PHP deserialization

L’application stocke la session dans une cookie sérialisée + encodée en Base64. Lors de la désérialisation, certains magic methods s’exécutent automatiquement (notamment __wakeup()), ce qui ouvre la voie à une chaîne de gadgets menant à une exécution de commande.

On retrouve le commentaire suivant

Fichier lisible avec le ~

1) Analyse du code (fichier backup CustomTemplate.php~)

Point d’entrée automatique : CustomTemplate::__wakeup()

  • Pendant unserialize(), PHP appelle automatiquement __wakeup().

  • Ici, __wakeup() appelle build_product().

Propagation vers Product

build_product() fait :

  • new Product($this->default_desc_type, $this->desc)

Et dans Product::__construct() :

  • $this->desc = $desc->$default_desc_type;

Donc le code tente d’accéder à une propriété dynamique sur l’objet $desc, avec comme nom la valeur contrôlable $default_desc_type.

Gadget décisif : DefaultMap::__get($name)

Si $desc est un objet DefaultMap :

  • il n’a pas de propriété réelle appelée HTML_DESC / TEXT_DESC / ou autre chaîne qu’on impose,

  • donc PHP déclenche __get($name),

  • __get() fait : call_user_func($this->callback, $name).

Si on met callback = "system", on obtient system($name).

2) Objectif de la chaîne

Exécuter :

  • system("rm /home/carlos/morale.txt")

3) Construction de la chaîne (logique)

On fabrique un objet :

  • CustomTemplate->default_desc_type = "rm /home/carlos/morale.txt" (ce sera le “nom de propriété” demandé à DefaultMap, donc l’argument passé à system)

  • CustomTemplate->desc = objet DefaultMap

  • DefaultMap->callback = "system"

Déroulé à la désérialisation :

  1. unserialize() → appelle CustomTemplate::__wakeup()

  2. __wakeup()build_product() → instancie Product

  3. Product::__construct() fait $desc->$default_desc_type

  4. $desc est DefaultMap et la propriété n’existe pas → DefaultMap::__get($name)

  5. __get()call_user_func("system", $name) → exécute la commande

4) Payload PHP sérialisé (attention aux longueurs)

Payload sérialisé :

Commande :

Mis à jour