11 questions pour comprendre la dernière vulnérabilité de l’API Rest WordPress

Quelques jours après la sortie de la version 4.7.2 de WordPress, l’éditeur signalait la correction d’une vulnérabilité critique affectant l’API REST du CMS. Découverte par les chercheurs en sécurité de l’entreprise SUCURI, la vulnérabilité a été publiquement dévoilée le 1er février 2017.

Qu’en est-il vraiment ? Nous vous proposons de répondre à cela en 11 questions pour mieux comprendre cette faille, et son exploitation.

1. Qu’est-ce que WordPress ?

WordPress est un système de gestion de contenu (CMS) sous licence libre créé en 2003 et basé sur le langage PHP. Celui-ci permet de créer facilement un site web grâce à un gestionnaire de thème, un panneau d’administration ainsi que de nombreuses fonctionnalités. WordPress est principalement utilisé pour générer des sites vitrine et des blogs. En outre, il peut également être utilisé pour réaliser des sites de e-commerce.

Extrêmement populaire, 27% des sites sur Internet reposaient sur WordPress en décembre 2016. Cette popularité fait de WordPress une application particulièrement sensible, tant les vulnérabilités découvertes peuvent affecter un nombre d’utilisateurs conséquents.

2. Qu’est-ce qu’une API REST ?

Une API (Application Programming Interface) est un ensemble normalisé d’interfaces (classes, méthodes ou fonctions) permettant d’interagir avec un programme.

Une API REST (Representational State Transfer) est plus précisément un protocole client-serveur « sans état », permettant de communiquer avec un programme. HTTP est le principal protocole utilisé dans le cadre des API REST.

Une API REST octroie donc la capacité de communiquer avec un site ou une application depuis un autre site, de manière programmable et automatisable. Elle rend ainsi possibles la communication et la récupération de données entre applications, sans avoir besoin d’accéder au site à partir d’un navigateur.

Généralement, une API REST permet d’interagir via l’envoi de requêtes HTTP sous forme d’un schéma d’URL correspondant à des commandes. Les réponses reçues sont au format JSON (Javascript Object Notation) ou parfois au format XML.

La sécurisation des échanges se fait généralement par la mise à disposition, par le fournisseur de l’API, d’une « clé d’API » unique par client.

L’API REST de WordPress a été introduite dans la version 4.4 le 8 décembre 2015 et elle est activée par défaut depuis la version 4.7. Elle n’utilise pas de clé d’API, mais se base nativement sur le cookie généré après connexion au Dashboard WordPress. En revanche dans le cas d’utilisation d’applications distantes, il est possible d’utiliser d’autres moyens d’authentification.

3. Quelle est la vulnérabilité ?

En envoyant une requête HTTP spécialement conçue sur l’API REST exposée publiquement sur Internet, un utilisateur non authentifié est en capacité de modifier entièrement un article ou une page du site vulnérable, sans aucune restriction.

4. Quels sont les impacts liés à l’exploitation de cette vulnérabilité ?

Cette vulnérabilité permet de modifier le titre d’un article et son contenu. Par conséquent, cette vulnérabilité peut impacter l’image d’une entreprise.

Étant donné que cette faille permet de modifier le contenu d’un article, on peut également penser à des attaques de type « blackhat SEO » visant à développer son référencement grâce à l’insertion de contenu et de « backlinks » au sein d’un site à fort trafic. Ou au contraire « polluer » un site cible afin d’affaiblir son référencement.

En outre, un site équipé d’un plugin WordPress permettant d’insérer du code arbitraire (par exemple le plugin « Insert PHP ») permet à un attaquant de prendre le contrôle du site, voire du serveur sous-jacent en utilisant le système de « short-codes » de WordPress.

5. D’où provient la vulnérabilité ?

La vulnérabilité provient d’un défaut de vérification dans le traitement du paramètre « id » reçu par l’API Rest et d’un mauvais design de la fonction de contrôle d’accès (fonctionnement en mode liste noire).

Cas d’un scénario d’utilisation légitime

Afin d’éditer l’article « Hello World », présent par défaut et ayant l’identifiant n°1 , il est nécessaire d’envoyer la requête authentifiée suivante :

  • Requête: http://localhost:8888/wp-json/wp/v2/posts/1
  • Contenu POST de la requête : 1&title=Article1&content=Bonjour

legit0
Envoi des paramètres sur l’API WordPress de notre site cible

schema-legit3

À la réception de la requête, l’API de WordPress vérifie si l’utilisateur dispose des droits d’écriture sur l’article spécifié. Pour ce faire, elle récupère l’identifiant de l’article passé en argument au sein de la requête HTTP POST (1).

L’objet contenant l’article est récupéré via son ID puis envoyé à la méthode de vérification de droits (2). Cette méthode vérifie plusieurs points :

  • L’utilisateur a-t-il le droit de modifier l’article ?
  • L’utilisateur a-t-il le droit de modifier cet article, dont il n’est pas l’auteur ?
  • L’utilisateur a-t-il le droit d’épingler cet article ?
  • L’utilisateur a-t-il le droit d’assigner des mots clés à l’article ?

Dans le cas où l’une de ces conditions est fausse, une erreur est levée. La fonction informe donc l’utilisateur qu’il ne pourra pas modifier l’article souhaité. Néanmoins, si aucune de ces conditions n’est vérifiée, l’utilisateur est tout de même autorisé à modifier l’article. La fonction renvoie « true » et le processus peut donc continuer normalement.

3
update_item_permissions_check (class-wp-rest-posts-controller.php)

Cette structure de vérification (liste noire) engendre un problème : la fonction autorise un utilisateur non authentifié à modifier un article non existant. En effet, si on fournit un identifiant lié à aucun article (exemple : ‘aaa’, ‘100000000’, etc.), aucune des conditions listées ne sera vérifiée. Le comportement par défaut étant d’autoriser, la méthode de vérification renvoie ‘true’.

Une fois les vérifications réalisées, l’API va exécuter le processus de mise à jour de l’article :

  • L’identifiant d’origine est récupéré (3) à partir de la requête POST.
  • Ce dernier est ensuite converti en « entier » (cast) par sécurité (seule la partie numérique de l’expression est conservée) (4). En effet, convertir (cast) un paramètre en un entier (int), permet de se protéger contre des attaques de types applicatives (Injection SQL ou XSS par exemple) et de s’affranchir de l’utilisation de caractères spéciaux.
  • L’article est ensuite récupéré à partir de l’identifiant précédemment converti (5). Une erreur sera donc levée si l’identifiant n’est pas lié à un article existant (exemple : ‘aaa’, ‘100000000’, etc.). L’API WordPress informera l’utilisateur que l’article n’a pu être trouvé.
  • Pour finir l’article récupéré est mis à jour (6).

Cas d’un scénario d’exploitation

Vous l’aurez donc compris, l’exploitation de cette vulnérabilité nécessite de remplir 2 conditions :

  • Fournir un identifiant non valide afin de contourner l’étape de vérification des droits utilisateurs.
  • Fournir un identifiant, qui lorsqu’il sera converti (cast) en entier pointera sur un article existant.

Pour réaliser cette astuce, il faut utiliser des propriétés spécifiques du langage PHP, appelé « type-juggling ». Le type-juggling est un comportement de PHP qui permet la conversion du type d’une variable en fonction de son contexte d’utilisation. Par exemple : une variable contenant une chaîne de caractère « 123Payload » est convertie (cast) en ‘entier’. La conversion permet de conserver uniquement la partie numérique de la chaîne de caractère. Le type-juggling convertira alors le type de la variable d’une chaine de caractère (string) vers un entier (int).

7
Exemple de type-juggling

L’exploitation de la vulnérabilité est donc très simple, il suffit d’envoyer à l’API REST un paramètre « id » composé des éléments suivants :

  • n° d’article existant + une chaine de caractère

Par exemple : 1efzefzf

Si l’on envoie la requête HTTP post suivante via l’API de WordPress dans le but d’éditer l’article ‘1‘ sans authentification :

  • Requête: http://localhost:8888/wp-json/wp/v2/posts/1
  • Contenu POST de la requête : id=1efzefzf&title=Hacked&content=upgrade

schema-exploit3

Comme précédemment, l’identifiant de l’article est extrait (1), mais étant donné que celui-ci est invalide, l’algorithme ne parvient pas à associer l’id avec un article existant. La méthode de vérification des droits reçoit donc un paramètre ‘null’. Mais cette méthode est problématique : si aucune condition n’est vérifiée, les autorisations sont données et le processus se poursuit alors qu’il ne devrait pas.

Dans notre cas, aucun article n’est associé à l’identifiant 1efzefzf. Aucune des 4 conditions ne peut être vérifiée. Les permissions sont donc accordées pour l’article 1efzefzf non existant.

6
update_item_permissions_check (class-wp-rest-posts-controller.php)

Comme dans le scénario légitime, la méthode d’édition est appelée dans le but d’éditer l’article dont l’identifiant est 1efzefzf. Notre variable « id » est cependant tronquée pour ne garder que les caractères numériques à cause de l’utilisation de la fonction de conversion (cast). L’identifiant fourni initialement 1efzefzf se transforme en l’entier 1. Ce traitement permet de rendre notre identifiant valide (4) et ainsi de récupérer notre article cible (5). Un attaquant non authentifié peut ainsi modifier l’article de son choix sur le site WordPress ciblé.

En résumé : les autorisations sont vérifiées à partir d’un identifiant invalide (« id ») mal traité, permettant d’outrepasser les vérifications afin d’obtenir les droits d’écriture sur le bulletin. L’identifiant est ensuite traité de manière à considérer uniquement la partie numérique de la variable, permettant ainsi de faire le lien avec l’article existant et de le modifier.

De plus, la structure de la méthode de vérification des droits est problématique. En effet, il s’agit d’une vérification par liste noire (vérifiant les conditions invalides) et accorde par défaut les permissions demandées. Or d’une manière générale, il est recommandé d’appliquer la méthode inverse : implémenter une liste blanche, qui refuse par défaut les droits, sauf dans des conditions maitrisées.

Résultat de la requête via l’API Rest

11-2
Edition de l’article 1 en utilisant l’identifiant 1efzefzf 

L’article a été effectivement édité.

12-2
Page défacée

6. Comment la vulnérabilité a-t-elle été corrigée ?

Afin de corriger la vulnérabilité, les développeurs de WordPress ont rajouté des tests à différents endroits clés de la prise en charge de l’identifiant. Dès la réception de la requête, l’identifiant est extrait et vérifié avant tout traitement dans la méthode get_post. Si l’identifiant est détecté comme invalide, alors une erreur sera levée.

15
get_post (class-wp-rest-posts-controller.php)

Cette erreur de l’API WordPress sera alors retournée :

16-3
Erreur renvoyée par l’API WordPress du à l’utilisation d’un identifiant non valide

7. La faille est-elle facilement exploitable ? Des codes d’exploitation sont-ils disponibles ?

La vulnérabilité est extrêmement facile à exploiter au point qu’aucun outil n’est nécessaire, il suffit d’envoyer une requête HTTP spécialement conçue vers l’API Rest du site WordPress visé.

Des codes d’exploitation développés en Ruby et Python sont cependant disponibles aux adresses suivantes :

Un autre code d’exploitation, s’appuyant sur le plugin WordPress « Insert PHP » permet d’insérer du code PHP et par conséquent de prendre le contrôle du site WordPress.

8. Suis-je affecté par la vulnérabilité ?

Vous êtes affectés par la vulnérabilité si votre application WordPress est sous la version 4.7 ou 4.7.1 et que l’API Rest de WordPress est activée (paramètre par défaut). Les versions antérieures ne sont pas vulnérables.

Vous êtes d’autant plus exposés si votre application WordPress utilise le plugin « Insert PHP », qui permet au pirate de prendre le contrôle du serveur.

9. Des attaques ont-elles été perpétrées ?

Quatre campagnes de défacement ont été observées. Au 6 février, plus de 68 000 pages vulnérables auraient été défigurées en exploitant cette faille.

Moins de 48 heures après la publication du patch 4.7.2 et par conséquent de la vulnérabilité, une première campagne de défiguration de site a été amorcée touchant plus de 66 000 pages web (référencées par Google). Réalisée par le groupe « w4l3XzY3« , les attaquants utilisaient principalement les 4 adresses IP suivantes :

  • 176.9.36.102
  • 185.116.213.71
  • 134.213.54.163
  • 2a00:1a48:7808:104:9b57:dda6:eb3c:61e1

La seconde campagne, moins fructueuse, montre environ 500 pages web défacées et signées par le groupe « Cyb3r-Shia » (utilisant l’adresse IP 37.237.192.22).

Enfin la 3ème et 4ème campagne, signées par deux groupes différents (« +NeT.Defacer » et « +Hawleri_hacker ») mais utilisant la même adresse IP (144.217.81.160) n’auraient touché que 1000 sites selon Google.

Depuis ces observations, il a été constaté au total, entre 1,4 et 1,8 million de pages défigurées.

10. Comment se protéger contre l’exploitation de cette faille ?

Il suffit de mettre à jour votre application ou de désactiver l’utilisation de l’API Rest de WordPress pour vous protéger de cette vulnérabilité.

Nous vous conseillons de mettre à jour votre site WordPress via l’utilitaire de mise à jour inclus au sein de la console d’administration de votre site, ou en téléchargeant la mise à jour disponible à l’adresse suivante : https://fr.wordpress.org/wordpress-4.7.2-fr_FR.zip

11. Dois-je appliquer les correctifs en urgence ?

Si votre version est affectée, oui. Cette vulnérabilité est critique, extrêmement simple à exploiter et peut impacter directement l’image de votre entreprise, voire permettre de prendre le contrôle du site (sous certaines conditions spécifiques).

[distance1]

[line]

Sources :

Adrien Guinault

Découvrir d'autres articles