Dans un précédent article, je vous ai présenté l’attaque par injection SQL. Quoi de mieux que la pratique pour en apprendre plus ? Laissez-moi vous montrer comment j’ai créé un lab pour des étudiants en 3ème année afin de les challenger sur cette attaque ! Celui-ci est relativement accessible même au débutant et en plus en fin d’article, vous trouverez également un lien pour télécharger une machine virtuelle prête à l’emploi, pour ceux qui préfèrent éviter les configurations manuelles. Let’s go !
L’objectif de ce laboratoire est de développer un site web intégrant volontairement des vulnérabilités d’injection SQL. Il sera connecté à une base de données contenant un ensemble de comptes utilisateurs, y compris leurs noms, prénoms, adresses email et mots de passe. Le site offrira une fonctionnalité de recherche permettant de rechercher l’adresse email d’un utilisateur. Cependant, ce champ de recherche sera délibérément conçu pour être vulnérable aux injections SQL. Cette vulnérabilité permettra à un utilisateur malveillant, par le biais d’une injection SQL, de récupérer les mots de passe des comptes utilisateurs. Voici à quoi ressemblera le site :
Pour ceux désireux de se plonger directement dans l’exercice d’attaque sans examiner le code source, voici le lien vers la machine virtuelle correspondante. Sur cette machine, vous pouvez vous connecter en utilisant les identifiants du compte « allitnetwork », avec « Azerty123 » comme mot de passe. Ce mot de passe est également valable pour le compte root. Il est recommandé de se connecter une première fois afin de récupérer l’adresse IP attribuée par DHCP avec la commande « ip a« . Ceci vous permettra de vous connecter à distance et de tenter une attaque par injection SQL.
Pour ceux qui veulent refaire ce LAB, pour commencer, vous devrez installer une machine virtuelle Debian. Je ne vais pas documenter cette partie, mais vous pouvez retrouver mon article sur l’installation de ce système d’exploitation si vous le souhaitez (notez que l’article est quelque peu ancien et concerne une version antérieure de Debian). A partir de là, il va falloir installer notre environnement de base et pour commencer il nous faudra installer la partie serveur web.
Installation du serveur web
On commence par installer nos outils nécessaires pour la partie web avec :
- nginx : C’est un serveur web léger, haute performance, qui peut également servir de reverse proxy, load balancer, et cache HTTP. Nous aurions pu utiliser Apache2 mais je préfère Nginx 😎 ! Il servira à recevoir les requêtes HTTP/HTTPS, bref indispensable dans ce LAB.
- mariadb-server : C’est un système de gestion de base de données relationnelle, un fork de MySQL. Il permet de stocker, organiser et récupérer des données. MariaDB est utilisé pour gérer les bases de données nécessaires pour les applications web. Ce sera lui que vous allez devoir hacker 😉
- php-fpm : C’est une implémentation alternative de PHP. Il est conçu pour accélérer les sites PHP, en particulier dans un environnement de serveur web à haut trafic. C’est surtout la version de PHP dont Nginx se sert pour fonctionner.
- php-mysql : Ce module fournit une interface entre le langage de programmation PHP et le serveur de base de données MariaDB. Il permet aux scripts PHP d’exécuter des opérations sur la base de données, comme la récupération, l’insertion, la mise à jour, et la suppression de données. Ce module est essentiel pour les applications web qui nécessitent une interaction avec une base de données MySQL ou MariaDB, permettant une intégration transparente et efficace des fonctionnalités de la base de données dans les applications PHP.
Ensemble, ces composants forment la base nécessaire au bon fonctionnement de notre lab. Pour les installer, voici la commande à réaliser :
apt install nginx mariadb-server php-fpm php-mysql
Configuration de la base de donnée
L’idée ici est de créer une structure simpliste d’une base de données avec les informations concernant des utilisateurs fictifs. Pour ce faire, voici une organisation d’une unique table que vous pouvez modifier à votre convenance :
- ID : Sert à identifier de manière unique chaque enregistrement (ou ligne) dans notre table de la base de données. Les enregistrements ne peuvent pas avoir le même ID, garantissant ainsi que chaque enregistrement est distinct.
- name : Nom de l’utilisateur
- email : Adresse email de l’utilisateur
- pass : Mot de passe des utilisateurs
Avant de pouvoir créer notre table et sa structure, nous devons nous connecter à MariaBD avec la commande suivante :
mysql -u root
Commençons par créer notre base de données avec la commande SQL suivante :
create database allitnetwork;
Ensuite connectons-nous à cette nouvelle base de données pour pouvoir créer notre table avec la commande SQL suivante :
use allitnetwork;
Il faut créer un utilisateur mariaDB qui aura les droits pour s’occuper de cette base de données. Pour ce faire utiliser la commande suivante :
GRANT ALL PRIVILEGES ON allitnetwork.* TO vincent@localhost IDENTIFIED BY « mdp »;
Et pour finir, créons la table qui nous servira pour le lab :
CREATE TABLE utilisateurs (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, pass VARCHAR(255) NOT NULL);
Voici une explication détaillée de chaque partie de cette création :
- CREATE TABLE utilisateurs : Cette commande initie la création d’une nouvelle table dans la base de données. La table sera nommée utilisateurs.
- id INT AUTO_INCREMENT PRIMARY KEY, : Cette partie définit une colonne nommée id.
- INT indique que la colonne stockera des nombres entiers.
- AUTO_INCREMENT signifie que chaque fois qu’une nouvelle ligne est ajoutée, cette colonne aura une valeur automatiquement augmentée de 1 par rapport à la dernière entrée, ce qui est pratique pour maintenir des identifiants uniques.
- PRIMARY KEY désigne cette colonne comme la clé primaire de la table, ce qui signifie que chaque valeur dans cette colonne doit être unique et qu’elle sera utilisée pour identifier de manière unique chaque ligne de la table.
- name VARCHAR(255) NOT NULL, : Définit une colonne name.
- VARCHAR(255) spécifie que la colonne stockera des chaînes de caractères (texte) avec une longueur maximale de 255 caractères.
- NOT NULL impose que cette colonne ne peut pas être laissée vide lors de l’ajout d’une nouvelle entrée dans la table.
- email VARCHAR(255) UNIQUE NOT NULL, : Définit une colonne email.
- VARCHAR(255) est similaire à ci-dessus.
- UNIQUE garantit que chaque valeur de cette colonne est unique dans toute la table.
- NOT NULL indique que cette colonne doit également contenir une valeur pour chaque entrée.
- pass VARCHAR(255) NOT NULL : Définit une colonne pass.
- VARCHAR(255) est utilisé encore une fois pour le type de données.
- NOT NULL impose une valeur requise pour cette colonne pour chaque entrée.
Il est à noter qu’ici je fais le choix de ne pas stocker les mots de passe de façon chiffrés pour bien visualiser le résultat obtenu lors d’une injection SQL.
Pour finir, nous pouvons ajouter des comptes fictifs avec la commande suivante. A faire autant de fois que vous souhaitez avec de compte dans votre BDD. Dans ma machine virtuelle, j’ai 20 utilisateurs :
insert into utilisateurs (name, email, pass) values (‘vincent’, ‘vincent@all-it-network.com’, ‘MonMDP2024’);
Voici la liste que j’ai utilisé si vous êtes en panne d’inspiration :
insert into utilisateurs (name, email, pass) values (‘sophie’, ‘sophie@all-it-network.com’, ‘Qm29@4Rt8z’);
insert into utilisateurs (name, email, pass) values (’emmanuel’, ’emmanuel@all-it-network.com’, ‘Zn30$5Sa9u’);
insert into utilisateurs (name, email, pass) values (‘claire’, ‘claire@all-it-network.com’, ‘Hj15&8Xp2k’);
insert into utilisateurs (name, email, pass) values (‘vincent’, ‘vincent@all-it-network.com’, ‘Fr24*7Gh3l’);
insert into utilisateurs (name, email, pass) values (‘marine’, ‘marine@all-it-network.com’, ‘Ld21%9Vb5o’);
insert into utilisateurs (name, email, pass) values (‘olivier’, ‘olivier@all-it-network.com’, ‘Yx26#6Wq4e’);
insert into utilisateurs (name, email, pass) values (‘julie’, ‘julie@all-it-network.com’, ‘Te17!0Km8g’);
insert into utilisateurs (name, email, pass) values (‘nicolas’, ‘nicolas@all-it-network.com’, ‘Qw23@1Zn7h’);
insert into utilisateurs (name, email, pass) values (‘anne’, ‘anne@all-it-network.com’, ‘Uj18$2Tf9i’);
insert into utilisateurs (name, email, pass) values (‘thomas’, ‘thomas@all-it-network.com’, ‘Iu19*3Eg0j’);
insert into utilisateurs (name, email, pass) values (‘catherine’, ‘catherine@all-it-network.com’, ‘Op25&5Rq6m’);
insert into utilisateurs (name, email, pass) values (‘guillaume’, ‘guillaume@all-it-network.com’, ‘Zl22#7Uk4n’);
insert into utilisateurs (name, email, pass) values (‘isabelle’, ‘isabelle@all-it-network.com’, ‘Xv27!8Fj3s’);
insert into utilisateurs (name, email, pass) values (‘alexandre’, ‘alexandre@all-it-network.com’, ‘Ck28@9Dh2t’);
insert into utilisateurs (name, email, pass) values (‘nathalie’, ‘nathalie@all-it-network.com’, ‘Bv29*0Lp1y’);
insert into utilisateurs (name, email, pass) values (‘françois’, ‘francois@all-it-network.com’, ‘Ng31$1Mb6z’);
insert into utilisateurs (name, email, pass) values (‘céline’, ‘celine@all-it-network.com’, ‘Pl32*2Nc5x’);
insert into utilisateurs (name, email, pass) values (‘benjamin’, ‘benjamin@all-it-network.com’, ‘Oj33&3Od4w’);
insert into utilisateurs (name, email, pass) values (‘émilie’, ’emilie@all-it-network.com’, ‘Mi34#4Pe3v’);
Et voilà notre base de données est créée, maintenant passons à notre page web.
Création page Web
Pour cette partie, je vais me concentrer sur l’essentiel. Bien que j’aie développé une page web complète en utilisant HTML et CSS pour lui donner une apparence soignée et professionnelle, notre principal intérêt ici réside dans la partie PHP et la création d’un formulaire intégrant une faille SQL. Je créer la page de mon site (index.php) dans le dossier « /var/www/sqlinjection ».
Je vous fournirai le code complet ultérieurement. Cependant, pour le moment, concentrons-nous sur le code PHP spécifique, que vous pourrez expérimenter et mettre en pratique sur votre propre lab.
<?php
$server = "localhost";
$username = "vincent";
$password = "mdp";
$database = "allitnetwork";
$conn = new mysqli($server, $username, $password, $database);
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if ($_POST["search"] != "") {
$search = $_POST["search"];
$sql = "SELECT name, email FROM utilisateurs WHERE name LIKE '%$search%'";
$result = $conn->query($sql);
}
}
<form action="" method="post">
Nom: <input type="text" name="search">
<input type="submit" value="Recherche">
</form>
<?php
if (isset($result) && $result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo $row["name"] . " - " . $row["email"] . "<br>";
}
}
?>
Ce script PHP est utilisé pour effectuer une recherche dans une base de données MySQL et afficher les résultats sur une page web. Voici une explication détaillée de chaque partie du script :
1) Connexion à la base de données
$server = "localhost";
$username = "vincent";
$password = "mdp";
$database = "allitnetwork";
$conn = new mysqli($server, $username, $password, $database);
Les premières lignes établissent une connexion à une base de données MySQL. « localhost » indique que la base de données est hébergée sur le même serveur que le script. « vincent » est le nom d’utilisateur et « mdp » le mot de passe pour se connecter à la base de données, et « allitnetwork » est le nom de la base de données.
2) Traitement de la recherche
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if ($_POST["search"] != "") {
$search = $_POST["search"];
$sql = "SELECT name, email FROM utilisateurs WHERE name LIKE '%$search%'";
$result = $conn->query($sql);
}
}
Ici on vérifie si le formulaire a été soumis (via une requête POST). Si c’est le cas, on vérifie que ce n’est pas vide et ensuite on récupère la valeur entrée dans le champ de recherche (name= »search »), construit une requête SQL pour rechercher des utilisateurs dont le nom correspond à la chaîne de recherche, et exécute cette requête.
Attention : Cette méthode est vulnérable aux injections SQL (c’est le but 😉) car la variable $search est directement insérée dans la requête sans être nettoyée ou préparée. Cela pourrait permettre à un utilisateur malveillant d’exécuter des requêtes SQL arbitraires.
3) Création du formulaire en HTML
<form action="" method="post">
Nom: <input type="text" name="search">
<input type="submit" value="Recherche">
</form>
La partie en HTML est un simple formulaire avec un champ de texte pour la recherche et un bouton pour soumettre le formulaire. L’action du formulaire est vide (action= » »), ce qui signifie que le formulaire sera soumis à la même page.
4) Affichage du résultat
if ($result && $result->num_rows > 0) {*
while ($row = $result->fetch_assoc()) {
echo $row["name"] . " - " . $row["email"] . "<br> ";
}
} else {
echo $search ? "Aucun résultat trouvé pour '$search'." : "";
}
Après l’exécution de la requête SQL, cette partie du script vérifie si des résultats ont été trouvés ($result->num_rows > 0). Si c’est le cas, il les parcourt avec une boucle while et affiche le nom et l’email de chaque utilisateur trouvé.
En résumé, ce script permet à un utilisateur de rechercher des utilisateurs par leur nom dans une base de données MySQL et d’afficher les résultats de cette recherche sur la page web. Si vous voulez mon code complet voici mon code complet :
- Le premier fichier est index.php, presque à l’identique du script ci-dessus :
<?php
$server = "localhost";
$username = "vincent";
$password = "mdp";
$database = "allitnetwork";
$conn = new mysqli($server, $username, $password, $database);
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if ($_POST["search"] != "") {
$search = $_POST["search"];
$sql = "SELECT name, email FROM utilisateurs WHERE name LIKE '%$search%'";
$result = $conn->query($sql);
}
}
?>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>All IT Network - Entraînement aux Injections SQL</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>All IT Network - Entrainement aux Injections SQL</h1>
<img src="LOGO6.jpg" alt="Logo All IT Network" id="logo">
</header>
<section id="about">
<h2>À propos de moi</h2>
<p>Bienvenue sur ce LAB proposé par All IT Network, votre plateforme dédiée à l'apprentissa> </section>
<section id="services">
<h2>Exercices d'Injection SQL</h2>
<h1>Rechercher l'adresse mail d'un utilisateur de All IT Network</h1>
<form action="" method="post">
Nom : <input type="text" name="search">
<input type="submit" value="Recherche">
</form>
<?php
if ($result && $result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo $row["name"] . " - " . $row["email"] . "<br>";
}} else {
// Afficher un message si aucun résultat n'est trouvé ou si $result est null
echo $search ? "Aucun résultat trouvé pour '$search'." : "";
}
?>
</section>
<section id="contact">
<h2>Qui suis-je ?</h2>
<p>Passionné d’informatique, ma motivation et ma curiosité m’ont permis de réaliser des étu> </section>
<footer>
<p>© All IT Network. Tous droits réservés.</p>
</footer>
</body>
</html>
- Le deuxième fichier est style.css, afin de rendre mon lab un peu plus joli 😎 :
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
color: #333;
}
header {
background-color: #4CAF50;
color: #fff;
padding: 10px 0;
text-align: center;
}
header h1 {
margin: 0;
}
nav ul {
padding: 0;
list-style: none;
}
nav ul li {
display: inline;
margin-right: 20px;
}
nav ul li a {
color: white;
text-decoration: none;
}
section {
padding: 20px;
}
footer {
background-color: #333;
color: white;
margin-top : auto;
text-align: center;
padding: 10px 0;
width: 100%;
}
Configuration de Nginx
Pour que Nginx pointe par défaut vers le nouveau site, nous allons devoir modifier le fichier de configuration de celui via la commande :
nano /etc/nginx/sites-available/default
Voici le contenu de mon fichier permettant d’ajouter le lien vers le dossier « /var/www/sqlinjection » et le support de php (attention en fonction de votre version de php, il faudra changer le fichier) :
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/sqlinjection;
index index.php index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
Nous voilà à la fin de la création de ce LAB, j’espère que celui-ci vous aura plu. N’hésitez pas à me dire en commentaire si vous souhaitez plus d’article comme celui-ci. Je ferais la suite et fin de cet article en montrant les différentes attaques possibles via les injection SQL sur ce lab.
Si l’article vous a plu et si vous aimez mon travail, vous pouvez faire un don en suivant ce lien :