La requête ci-dessus contient les paramètres suivants :
action=tribe_dropdown, pour exécuter l'action wp_ajax_nopriv_tribe_dropdown
source=search_posts, pour appeler la fonction vulnérable identifiée
args[nopaging]=true, pour désactiver la pagination et obtenir tous les résultats
args[post_status][]=all, pour lister tous les articles, y compris les articles privés
Ainsi, comme attendu suite à l'analyse du code, un utilisateur anonyme est en mesure de lister les titres de tous les articles, y compris ceux encore en brouillon ainsi que ceux privés et protégés par un mot de passe.
Récupération du contenu des articles
Être en mesure de lister les titres de tous les articles est certes intéressant et peut conduire à des fuites de données, mais pouvoir lire leur contenu serait bien plus intéressant ! L'objet WP_Query permet d'effectuer des recherches précises dans le contenu des posts. Ainsi, il est possible de retrouver le contenu d'un article, caractère par caractère.
WordPress implémente par défaut une heuristique de recherche dans WP_Query ayant pour objectif d'être souple dans les recherches et de retrouver le plus de résultats plausibles que possible. Néanmoins, ces règles rendent la récupération du contenu d'un article plus difficile. En explorant la documentation et le code source de WP_Query, nous avons identifié plusieurs arguments permettant de durcir les règles de recherche et rendre possible l'extraction du contenu d'un article :
p: permet de spécifier l'ID de l'article dans lequel faire une recherche. Ce paramètre peut être pratique pour éviter de chercher dans tous les articles et en cibler un spécifique. À noter qu'il n'est pas possible de l'utiliser avec un article privé.
search_columns : Liste des colonnes en base de données dans lesquelles effectuer la recherche. Seules les valeurs suivantes sont autorisées :
sentence : Si elle est activée, l'option permet de s'assurer que le texte de recherche est exactement présent dans l'article.
En combinant ces paramètres, il est possible d'effectuer des recherches spécifiques dans le contenu d'un article et de retrouver tout son contenu, caractère par caractère.
Évidemment, cette recherche reste lente avec une complexité en O(n*m) où n est la taille de l'article et m est le nombre de caractères dans l'alphabet de recherche. Il est possible de réduire m au strict minimum en vérifiant dans un premier temps si un caractère est présent. Cela est faisable en exploitant le fait que si le critère de recherche commence par -, WP_Query effectue une recherche inversée. Ainsi, si la recherche -c retourne un résultat, cela signifie que le caractère c n'est pas présent dans l'article.
Nous avons utilisé cette méthode et, bien qu'elle demeure lente, nous avons été en mesure de retrouver le contenu d'articles privés dans un temps raisonnable.
Correction
Dans le correctif publié par l'éditeur, l'attribut args est désormais forcé avec la valeur [ 'post_status' => 'publish' ] et seule les clés taxonomy et post_type sont désormais contrôlables. Il n'est ainsi plus possible d'obtenir d'informations d'articles privés et la méthode de récupération du contenu décrite précédemment n'est plus exploitable.
Un correctif simple et efficace !