Rappel théorique
La désérialisation non sécurisée survient lorsqu'une application
reconstruit des objets PHP à partir de données fournies par l'utilisateur via
unserialize(), sans aucune restriction. PHP peut alors instancier
n'importe quelle classe connue de l'application et appeler
automatiquement ses méthodes magiques (__wakeup(), __destruct(),
__toString()...), même si rien dans ces méthodes n'était censé être
déclenchable par un attaquant.
Si une classe quelconque du projet effectue, dans une de ces méthodes magiques, une action sensible à partir d'une propriété de l'objet (écrire un fichier, exécuter une commande, faire une requête...), un attaquant peut fabriquer un objet sérialisé "piégé" pour déclencher cette action - même sans jamais appeler directement cette classe lui-même. On parle de chaîne POP (Property-Oriented Programming).
Exemple de classe vulnérable
class MaliciousPayload {
public string $cmd;
public function __wakeup(): void {
system($this->cmd); // exécuté automatiquement par unserialize() !
}
}
// Coté attaquant :
$payload = serialize(new MaliciousPayload());
$payload = str_replace('""', '"rm -rf /"', $payload); // injecte sa commande
// Envoyé au serveur, qui fait : unserialize($_POST['data']);
Conséquences
- Exécution de code arbitraire (RCE) sur le serveur.
- Suppression ou altération de fichiers.
- Déni de service, élévation de privilèges, selon les classes disponibles.
Mesures de protection
- Éviter
unserialize()sur des données provenant de l'utilisateur. Préférer un format sans état comme JSON (json_decode/json_encode), qui ne permet jamais d'instancier des objets ni d'appeler des méthodes magiques. - Si
unserialize()est indispensable, restreindre les classes autorisées avec l'option['allowed_classes' => false](aucune classe - tout objet devient__PHP_Incomplete_Class, sans appel de méthode magique) ou une liste blanche précise. - Vérifier l'intégrité des données sérialisées (signature/HMAC) si elles doivent transiter côté client.
Démo vulnérable
unserialize($_POST['data']) sans restriction : un objet
MaliciousPayload sérialisé déclenche son __wakeup(),
qui écrit un fichier marqueur (à la place d'une vraie commande système).
Démo sécurisée
Même formulaire, mais unserialize($data, ['allowed_classes' => false]) :
__wakeup() n'est jamais appelé. Alternative recommandée : JSON.