Web Security Academy

Insecure deserialization - Lab : Developing a custum gadget chain for Java deserialization

Objectif :

  • Accéder au compte administrateur dont l'identifiant est administrator pour ensuite supprimer le compte utilisateur d'une personne se nommant Carlos.

Solution :

Lorsqu'on lance le lab, on arrive sur la première page d'un site de commerce. On aperçoit que l'on peut se loguer sur le site avec un compte utilisateur en appuyant sur "Account login" en haut à droite.

En utilisant les identifiants fournis dans l'énoncé ( nom de compte : wiener ; mot de passe : peter ), on se connecte au site en tant que client ordinaire. Un cookie de session est créé et va désormais apparaître parmi les headers des requêtes envoyées depuis navigateur au serveur :

Il est codé en base64.

On le décode et on aperçoit que la chaîne de caractères correspond à un objet sérialisé en Java : sr"data.session.token.AccessTokenUsers_PIL
accessTokentLjava/lang/String;Lusernameq~xpt XfuVpgfnsSP4aQXGyVdxMnTHJELAj1kVtwiener

On lit le code source de la page et dans à l'intérieur d'un commentaire, un chemin vers un fichier est noté : /backup/AccessTokenUser.java.

On essaye d'accéder au dossier backup depuis l'URL et on voit la présence d'un fichier nommé "ProductTemplate.java".

On télécharge le fichier. Il contient la classe ProductTemplate avec les attributs suivants :

On continue à le lire et on observe une méthode se nommant ProductTemplate.readObject(). La méthode readObject() permet de désérialiser des objets en Java :

À l'intérieur de cette méthode, l'attribut id est intégré dans l'utilisation d'une requête SQL :

À présent, l'idée est d'effectuer une injection SQL par l'envoi d'un objet sérialisé de type ProductTemplate par le cookie pour exfiltrer le mot de passe de l'administrateur dans la base de données si possible.

Cette injection va se faire en modifiant judicieusement la valeur de l'attribut id, en espérant que la réponse à cette requête sera visible.

On va utiliser l'opérateur UNION pour retrouver les tables dans la base de données.

La première étape est de chercher le nombre de colonnes que nous retourne le serveur.

Lorsqu'on assigne la valeur " ' UNION SELECT NULL -- " à l'attribut id, le serveur nous fait part que le nombre de colonnes ne correspond pas :

On teste jusqu'à 8 colonnes ( ' UNION SELECT NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -- ) et le serveur nous répond différemment, sans nous dire que le nombre de colonnes n'est pas correcte.

Ensuite, on vérifie si une table se nommant "users" avec un colonne "password" existe avec ce payload : " ' UNION SELECT NULL, NULL, NULL, NULL, NULL, NULL, password, NULL from users --".

Le serveur répond de cette manière :

Il indique un problème de type. On va caster la colonne "password" en integer : " ' UNION SELECT NULL, NULL, NULL, NULL, NULL, NULL, cast ( password as numeric ), NULL from users --".

Le serveur renvoie une autre erreur :

Il nous donne une chaîne de caractères ressemblant à un mot de passe.

On teste celui-ci pour se connecter sur le compte de l'administrateur et ça fonctionne !

Il suffit ensuite de supprimer le compte de Carlos à accédant au panel administrateur et le lab se valide !