Skip to content

GitLab pour auditer la sécurité de vos sites WordPress ?

Lorsque l’on parle de CMS (Content Management System) ou de blog, bien souvent le mot WordPress n’est jamais très loin.

Lancé en 2003, il est rapidement devenu le chouchou des webmasters pour la création de sites internet. A tel point qu’il détient en 2023 60 % du marché des CMS d’après une infographie publiée par WP Clipboard.

WordPress est-il fâché avec la sécurité ?

Forcément, autant de popularité amène son lot de problèmes… Si l’on se penche du côté des attaques et de la sécurité, qu’est ce que ça donne ?

Wordfence, une solution de sécurité pour WordPress rapporte qu’il n’y a pas moins de 90 000 attaques sur des sites WordPress toutes les minutes 😱. Parmi elles, 8 % des sites se font compromettre à cause d’un mot de passe faible, 61 % se font infecter parce-que ils ne sont pas mis à jour…
Forcément, autant de popularité amène son lot de problèmes… Si l’on se penche du côté des attaques et de la sécurité, qu’est ce que ça donne ?
Wordfence, une solution de sécurité pour WordPress rapporte qu’il n’y a pas moins de 90 000 attaques sur des sites WordPress toutes les minutes 😱. Parmi elles, 8 % des sites se font compromettre à cause d’un mot de passe faible, 61 % se font infecter parce-que ils ne sont pas mis à jour…

Extrait de l’infographie wpclipboard

Au niveau des vulnérabilités, on retrouve 39 % de failles XSS (Cross-site scripting), 52 % sont causées par des plugins ou encore 11 % proviennent des thèmes utilisés et installés… 

Ces chiffres font clairement froid dans le dos ! 🥶

Je me suis alors demandé comment est-ce que l’on pourrait auditer régulièrement nos sites WordPress ? 

Étant joueur de CTF, j’avais déjà un premier élément de réponse : WPScan. C’est un outil bien pratique lorsque l’on souhaite rechercher des vulnérabilités sur un site WordPress. Je ne vais pas faire une présentation de l’outil dans cet article, Florian d’IT connect a fait un superbe travail si ça vous intéresse. 

“T’es mignon, mais moi, je ne connais pas ton truc, je ne fais pas de CTF et en plus, je n’ai pas envie de prendre du temps à lancer un scan ou même, penser à le faire…”

Si je suis sensible à la sécurité informatique, je le suis aussi pour l’automatisation 😅. C’est pourquoi, nous allons coupler l’utilisation de WPScan à GitLab CI. On aura un scan automatique à fréquence régulière avec des rapports que l’on pourra facilement consulter ! 

Ça vous dit ? Ben, let’s go, rendez-vous dans la deuxième partie de l’article !!

Mise en place du Pipeline GitLabCI

Dans le cadre de cet article, j’ai déployé un site WordPress sur une instance AWS EC2. C’est celui-ci que nous allons scanner et analyser, via notre CI à l’aide de WPScan.

Petit aparté, si vous n’êtes pas super à l’aise avec GitLab CI, c’est votre jour de chance ! Vous trouverez sur mon blog un article expliquant le fonctionnement de ce dernier 😛

Maintenant, que vous êtes un pro, on va pouvoir commencer à écrire notre fichier .gitlab-ci.yml

Dans un premier temps, déclarons nos 3 stages :

stages:
    - scan
    - build
    - deploy

Le premier, correspondra au scan de notre site WordPress. Le build quant à lui aura pour but de convertir le résultat qui est au format JSON, en HTLM. Puis le dernier stage sera le déploiement de notre site web. Nous passerons par GitLab pages.

Aller, c’est tipar pour écrire notre premier job :

Scan WordPress:
  stage: scan
  image:
    name: wpscanteam/wpscan
    entrypoint: [""]
  variables:
    TARGET: "https://example.com"
  script:
    - wpscan --url ${TARGET} -e vp,vt,tt,cb,dbe,u,m --format json --output scan_result.json
  artifacts:
    name: "WordPress Scan Report ${CI_COMMIT_SHA}"
    paths:
      - scan_result.json
    expire_in: 1 hour

Si l’on reprend step by step cette déclaration : 

  • Ce job est défini dans le stage scan
  • L’image utilisée est wpscanteam/wpscan , qui est une image Docker pré configurée pour exécuter WPScan.
  • L’entrypoint est défini avec une liste vide, cela permet d’exécuter les commandes WPScan normalement.
  • La variable TARGET sera utilisée pour stocker l’URL du site WordPress à scanner.
  • La section script contient la commande wpscan à exécuter avec des arguments permettant de spécifier URL du site à scanner, les éléments à énumérer (versions des plugins, versions des thèmes, vulnérabilités connues, commentaires, bases de données, utilisateurs, médias) et une sortie au format JSON
  • Un fichier nommé scan_result.json sera conservé comme artefact pendant 1 heure après l’exécution du pipeline.

En résumé, ce job utilise WPScan pour effectuer une analyse de sécurité complète de notre site WordPress et stocke les résultats au format JSON en tant qu’artefact.

Mais pourquoi avons-nous besoin d’un artefact, me diriez-vous ? 🤔

Tout simplement pour être en mesure d’utiliser notre fichier JSON dans notre prochain job, et de le convertir en HTML !

Trêve de blabla, on a un peu de pain sur la planche 🥖, on a un script python à écrire pour opérer cette conversion 😅.

Ce n’est un secret pour personne, je ne suis pas Dev. Même avec l’aide de El famoso ChatGPT j’ai mis un peu de temps à arriver au résultat que je souhaitais. Ce n’est peut-être pas parfait, mais ça a le mérite de fonctionner (toute remarque constructive est la bienvenue) 😅. Je ne vais pas rentrer dans le détail, mais en gros, ce script prend le fichier JSON généré par WPSCan et le convertit en un fichier HTML. 

Si vous mourez d’impatience pour voir tout ça, ainsi que mes compétences de développeur Python, les sources sont ici.

Maintenant, revenons à nos moutons 🐑 (plutôt à notre pipeline GitLab 😂). Déclarons un nouveau job pour utiliser notre script et générer le fichier html. 

Convert to html:
  stage: build
  image: python:3.9
  before_script:
    - pip install jinja2
  script: 
    - python3 json_to_html.py scan_result.json scan_result.html template.html
  artifacts:
    name: "WordPress Scan HTML Report ${CI_COMMIT_SHA}"
    paths:
      - scan_result.html
    expire_in: 1 hour

Ce job n’est pas très compliqué.

Il exécute notre script json_to_html.py , pour convertir le fichier JSON (scan_result.json) en un fichier HTML (scan_result.html). Le tout, en utilisant un modèle de template (template.html). Le fichier HTML généré est ensuite placé en tant qu’artefact avec un nom basé sur le hachage du commit Git actuel. 

Booooooon ça commence à ressembler à quelque chose là non ? 😏

Dernière étape et je vous libère ! On va créer un job pour que l’on puisse consulter le résultat de notre scan via une page web. Stylé de ouf non ? 😁

Voici le job en question :

pages:
  stage: deploy
  script:
    - mkdir -p public/
    - cp scan_result.html public
  artifacts:
    paths:
      - public

Ce job est un “piti” peu spécial. Don’t worry, on va reprendre tout ça ensemble :

  • Le nom du job doit obligatoirement se nommer pages. C’est cette déclaration qui va opérer automatiquement le déploiement des pages
  • La section script crée un répertoire public et place le fichier HTML dedans. Attention, le dossier doit forcément se nommer public pour que gitlab page fonctionne.
  • Puis nous déclarons notre dossier public en tant qu’artefact.

Lorsque notre job pages sera trigger un deuxième job pages:deploy sera exécuté. 

Attendez un moment… 🕥 Et quelques secondes plus tard, on va pouvoir atteindre notre page à cette url : 

https://<Votre_Nom_de_Groupe>.gitlab.io/<Votre_Nom_de_projet>/scan_result.html

Testons tout ça

C’est bien, on a notre pipeline, mais ce serait quand même cool que l’on valide tout ça non ?

Et ben, ça tombe bien, j’ai lancé une petite instance EC2 sur AWS avec une AMI faisant tourner WordPress. On récupère l’URL et on définit celle-ci dans la variable TARGET de notre pipeline. Ce qui nous donne :

Scan WordPress:
 stage: scan
 image:
   name: wpscanteam/wpscan
   entrypoint: [""]
 variables:
   TARGET: "http://ec2-35-180-100-19.eu-west-3.compute.amazonaws.com/"
 script:
   - wpscan --url ${TARGET} -e vp,vt,tt,cb,dbe,u,m --format json --output scan_result.json
 artifacts:
   name: "WordPress Scan Report ${CI_COMMIT_SHA}"
   paths:
     - scan_result.json
   expire_in: 1 hour

On commit, et la CI devrait se lancer. Une fois que tous les voyants sont au vert :

On peut se rendre sur notre page web, dans mon cas l’url est la suivante : https://gribhb.gitlab.io/wpscan-ci/scan_result.html

Ettttt tadaaaaaaam 🥳🥳

Bon ok, niveau design ce n’est pas la folie… 🤢

Mais parfois les choses simples sont les meilleures non ? 😅. Un jour, j’ajouterai un peu de CSS… Un jour…

Petit point sécu quand même 🛡️. On est d’accord, les infos contenues sur cette page web sont quand même un peuuuuuu 🤏sensible (en-tout-cas ça peut l’être). Je vous conseille l’utilisation des GitLab pages access control afin qu’uniquement, vos utilisateurs GitLab connectés puissent accéder à cette ressource.

Il ne nous reste plus qu’à programmer l’exécution de notre pipeline afin d’avoir des scans réguliers. Et bien évidemment, pensez à aller consulter le rapport. Vous trouverez toutes les sources sur mon GitLab si jamais vous voulez tester 😉

Conclusion

On l’a vu, en introduction, les hackers peuvent utiliser plusieurs techniques pour pirater un site WordPress. Les mots de passe faibles, les thèmes et plugins vulnérables ou l’absence de sauvegarde, sont les failles de sécurité les plus couramment exploitées. Il est donc crucial de mettre en place des mesures solides pour protéger nos sites WordPress.

Vous le savez tout autant que moi, ces tâches de gestion et de vérification ne sont que très rarement faites… Que ce soit par faute de temps, de motivation (tout le monde à une bonne excuse de toute façon 🥲). 

Avec cet article, nous avons déjà automatisé la génération du rapport. C’est un bon début, mais il ne sera pas très utile s’il n’y a pas de remédiations derrière. Et ça, c’est comme lorsque l’on doit aller au WC, personne ne peut le faire pour vous 😉

(en vrai si, on peut passer par des services ou personnes tierces, maiiiiiis ce n’est pas le sujet de cet article 😅)

En attendant, j’espère que cet article vous aura fait prendre conscience de la sécurité qu’il faut apporter aux sites WordPress. N’hésitez pas à me faire vos retours sur LinkedIn ou sur X

Published inNon classé