LÉOCARD Jérémie
SAÉ 3 Cyber.04 Découvrir le pentesting - Installation des services et vulnérabilitées
Lien pour créer l'infrastructure : Infrastructure de base.
Lien vers scénario d'attaque et démonstration : Scenario et déroulement de l'attaque.
Table des matières
Rappel de l'infrastructure

Serveur MYSQL SAMBA
Le serveur Mysql permettra d'authentifier les clients tandis que le servuer LDAP permettra d'authentifier l'administration.
Installation de MYSQL
Premièrement, il faut installer le paquet mariadb-server.
$sudo apt install mariadb-server
Configuration de la BDD hotel_leocard
On se connecte en root à la mysql (la commande permet d'ouvrir une session MySQL en utilisant l'utisateur root) :
$sudo mysql -u root
Je créer la BDD hotel_leocard :
> CREATE DATABASE hotel_leocard;
Je sélectionne la BDD :
> USE hotel_leocard;
Pour créer les tables client, chambre et reservation, je rentre dans mysql :
CREATE TABLE client (
id_client INT PRIMARY KEY AUTO_INCREMENT,
nom VARCHAR(50) NOT NULL,
prenom VARCHAR(50) NOT NULL,
uid VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(100) NOT NULL
);
CREATE TABLE chambre (
id_chambre INT PRIMARY KEY AUTO_INCREMENT,
numero INT NOT NULL UNIQUE,
type VARCHAR(30),
prix_nuit DECIMAL(10,2) NOT NULL
);
CREATE TABLE reservation (
id_reservation INT PRIMARY KEY AUTO_INCREMENT,
id_client INT NOT NULL,
id_chambre INT NOT NULL,
date_debut DATE NOT NULL,
date_fin DATE NOT NULL,
FOREIGN KEY (id_client) REFERENCES client(id_client),
FOREIGN KEY (id_chambre) REFERENCES chambre(id_chambre)
);
Vision avec la commande DESCRIBE de mysql des tables client, chambre et reservation :

Je vais créer dès à présent les 3 chambres de mon hotel avec :
INSERT INTO chambre (numero, type, prix_nuit) VALUES ('20', 'Chambre La Classique', '95.00');
INSERT INTO chambre (numero, type, prix_nuit) VALUES ('30', 'Chambre Boisée', '125.00');
INSERT INTO chambre (numero, type, prix_nuit) VALUES ('40', 'Chambre Royale', '250.00');

Une fois la BDD créée, il faut créer un utilisateur qui y aura accès. Pour ce faire, il faudra saisir :
CREATE USER 'leocard'@'192.168.10.10' IDENTIFIED BY 'abc';
GRANT ALL PRIVILEGES ON hotel_leocard.* TO leocard@192.168.10.10;
FLUSH PRIVILEGES;
Explication :
192.168.10.10est l'adresse de mon serveur-dmz.FLUSH PRIVILEGES;permet d'appliquer directement les changements. Sinon il aurait fallu redémarrer le service mysql.
Il faut ensuite autoriser l'accès depuis des machines distantes. Actuellement, comme on le voit avec la commande $ss -lunt sur la machine serveur-mysql, le port 3306 est uniquement accessible depuis la machine local :

Rappel : Un socket en Linux permet d'envoyer et de recevoir des données entre les processus. Ces processus peuvent être en local ou en distant.
ss: Acronyme deSocket Statistics.-l: Permet d'afficher les sockets qui écoutent. (LISTEN).-u: On sélectionne ceux qui sont en UDP.-n: Permet d'afficher les adresses sous forme d'IP et non de nom de domaine. Exemple,127.0.0.1s'affichera au lieux delocalhost.-t: On sélectionne ceux qui sont en TCP.
Il faut faire en sorte que le socket permettant de se lier à Mysql écoute depuis l'extérieur. Pour cela, on va se rendre dans la configuration du serveur mysql /etc/mysql/mariadb.conf.d/50-server.cnf ou il faudra remplacer :
bind-address = 127.0.0.1
Par
bind-address = 0.0.0.0
Redémarrer le service avec $systemctl restart mysql.
Désormais on voit bien sur le ss -lunt que le socket du processus mysql écoute bien depuis n'importe qu'elle IP :

Configuration de la BDD message_administrateur
Le but de cette BDD sera que l'administrateur envoie des message directement sur le dashboard des manager sur le site web.
On se connecte en root à la mysql (la commande permet d'ouvrir une session MySQL en utilisant l'utisateur root) :
$sudo mysql -u root
Je créer la BDD message_administrateur :
> CREATE DATABASE message_administrateur;
Je sélectionne la BDD :
> USE message_administrateur;
Voici le shéma UML de ma BDD :

Pour créer la table message je rentre dans mysql :
CREATE TABLE message (
id_message INT PRIMARY KEY AUTO_INCREMENT,
objet VARCHAR(1000) NOT NULL,
message VARCHAR(10000) NOT NULL,
date DATETIME DEFAULT CURRENT_TIMESTAMP
);
Vision avec la commande DESCRIBE de mysql de la table message :

Une fois la BDD créée, il faudra configurer un utilisateur qui y aura accès. Pour ce faire, il faudra saisir :
GRANT ALL PRIVILEGES ON message_administrateur.* TO leocard@192.168.10.10;
FLUSH PRIVILEGES;
RAPPEL :
Pour supprimer une ligne dans une BDD, c'est la commande DELETE qui s'utilise comme ça :
> DELETE FROM message WHERE id_message = '2';
Installation de SAMBA
SAMBA est un service qui permet de partager des ressources sur le réseau, ce peut être par exemple une imprimante, des fichiers.. etc. L'avantage de SAMBA est qu'il permet d'échanger ces ressources à travers différents OS comme Linux ou Windows.
Il faut installer le paquet samba avec :
$sudo apt install samba
Configuration de SAMBA côté serveur
La configuration de SAMBA se fera via le fichier /etc/samba/smb.conf dans lequel il faudra rajouter à la fin :
[share]
comment = Serveur De Ressources Entreprise
path = /home/sambauser/share
valid users = sambauser
read only = no
browseable = yes
guest ok = no
Explication des ajouts du [share] ! :
[share]: Permet de définir le nom du partage (comment est-ce que les gens le verront une fois connecté à SAMBA). Ce sera sur la forme\\ip_serveur\share.comment:Serveur De Ressources Entreprise. Lorsque les personnes listeront les différents partages, le commentaire apparaitra. Il est optionnel mais recommandé pour la lisibilité.path:/home/sambauser/share. Permet de définir l'emplacement du partage de fichier sur la machine locale.valid users:sambauser. L'utilisateur qui pourra utiliser accèder au partage. Point très important ! SAMBA utilise un utilisateur qui est présent sur le serveur. Cet utilisateur ne sera utilisable par SAMBA que SI ET SEULEMENT si il a un mot de passe SAMBA (avec la commande$smbpasswd). En général, l'utilisateur sera créer avec un shell/sbin/nologin. L'utilisateur ne pourra donc rien faire sur le système de base debian !! La sécurité est garantie !read only:no. Signifie que ceux qui s'y connecte peuvent écrire dans le répertoire, pas seulement lire. Ils peuvent ajouter, supprimer, modifier..etc.browseable:yes. Permet aux machines du réseau de pouvoir voir le partage directement depuis leurs machines.guest ok:no. Interdit les connexion anonyme.
Puis, redémarrer le service smbd avec : $sudo systemctl restart smbd.
Il faut donc désormais créer l'utilisateur sambauser et son mot de passe SAMBA avec :
$sudo useradd -s /sbin/nologin sambauser
$sudo smbpasswd -a sambauser
Pour sudo smbpasswd -a sambauser il faudra rentrer le mot de passe qui va se servir à se connecter à cet utilisateur SAMBA. Ici, j'ai mis abc.
Explication de la commande sudo useradd -s /sbin/nologin sambauser :
useradd: Permet de créer un nouvel utilisateur sur un système debian.-s:/sbin/nologin. Permet de spécifier un shell spécial pour cet utilisateur. Ici, l'utilisateursambausern'aura pas de shell, donc aucune interaction possible avec le système de base.sambauser: Le nom du nouvel utilisateur à créer.
Explication de la commande sudo smbpasswd -a sambauser :
smbpasswd: Permet de gérer les mots de passe des utilisateurs SAMBA.-a:sambauser. Cette option permet d'ajouter un nouvel utilisateur SAMBA. Ici, on veut ajouter l'utilisateursambauser.
Puis créer le répertoire /home/sambauser/share avec les bons droits :
$sudo mkdir /home/sambauser
$sudo mkdir /home/sambauser/share
$sudo chown sambauser:sambauser /home/sambauser/share
$sudo chmod -R 700 /home/sambauser/share
Actuellement, le serveur SAMBA a beaucoup de ports ouverts !! on le voit avec le ss -lunt :

Comme on le voit ici, les ports 137(UDP), 138(UDP) et 139(TCP) possèdent plusieurs socket d'écoute.
Ces 3 ports sont utilisé pour NetBIOS qui est un protocole des annnées 90 de communication pour Windows. Mais désormais, c'est le protocole TCP/IP qui est utilisé.
Dans le but de sécurisé, on va donc désactiver la possibilité d'utiliser NetBIOS. Il faudra éteindre et désactiver le service de SAMBA qui gère les aspects NetBIOS et qui s'appelle nmbd avec :
$sudo systemctl stop nmbd
$sudo systemctl disable nmbd
Puis, à l'intérieur du fichier /etc/samba/smb.conf dans la section [global] il faudra rajouter la ligne :
smb ports = 445
Cette ligne permettra d'ouvrir seulement le port 445 (SMB avec TCP/IP). Désormais, sur le ss -lunt, on a bien seulement le port 445 :

Configuration de SAMBA côté client
Il faudra installer le paquet samba-client.
Connexion à SAMBA
On peut lister dans un premier temps les différents partages du serveur SAMBA disponible avec le compte sambauser avec la commande :
$sudo smbclient -L '\\192.168.20.20\' -U sambauser
Explication de la commande :
smbclient: Commande permettant de se connecter en tant que client à un serveur SAMBA.-L: Permet de lister les dossiers de partage (ici de l'utilisateursambausergrâce au-U).\\192.168.20.20\: Ici, on spécifie l'adresse IP du serveur SAMBA. À noter que ça commence par\\et fini par '\'. Les antislashs sont de Windows. C'est de la forme\\@IP\chemin.-U:sambauser. On spécifie l'utilisateur auquel on va se connecter. On aura donc seulement la liste des dossiers de partage que cet utilisateur peut consulter.
Voici le retour de la commande depuis la machine attaquant-interne :

On peut voir que le mot de passe SAMBA du compte sambauser est demandé. J'ai donc tapé abc. Également, le dossier de partage share apparaît.
Pour se connecter, il faut taper la commande :
$sudo smbclient '\\192.168.20.20\share' -U sambauser'
On peut désormais accèder au partage de fichier et exécuter des commandes à l'intérieur :

Serveur LDAP
Il faut bien faire la différence entre le serveur MYSQL et le serveur LDAP. Le serveur LDAP permettra de s'authentifier. Le serveur MYSQL permettra une fois authentifié de récupérer ses informations.
Installation de LDAP
Premièrement, il faut installer les paquets slapd et ldap-utils.
Configuration de slapd
La configuration slapd se lance avec la commande ci dessous qui va nous ouvrir plusieurs fenêtres de configuration.
$sudo dpkg-reconfigure slapd
Si la commande n'est pas trouvé, c'est que /usr/sbin n'est possiblement pas dans la variable d'environnement PATH. Pour ce faire il faut rajouter dans le fichier .bashrc :
export PATH=$PATH:/usr/sbin
Puis rentrer la commande qui va permettre de recharger la configuration en cours :
$source .bashrc
Nom de domaine
J'ai mis sae.com qui sera automatiquement transformé en dc=sae,dc=com. Le nom du DNS est libre.
Saisi de l'organization
Le nom de domaine et l'organization doivent être cohérent, sinon la configuration plante. Vu que j'ai mis pour le nom de domaine sae.com, alors il faut que mon organization soit sae. J'ai donc saisi sae.
Mot de passe administrateur
J'ai mis abc.
J'ai remis abc pour confirmer le mot de passe.
Conservation de la base de données
Ici, il est recommandé de sauvegarder la BDD LDAP. J'ai donc sélectionné <Non>.
Effacement de données déjà présente
Correspond au déplacement d'anciennes données d'une configuration de LDAP. J'ai sélectionné <Oui> pour déplacer les anciennes données au cas ou il y en aurait.
Configuration de l'arbre de l'annuaire LDAP
Le but sera de créer l'arbre suivant :

Actuellement, la structure de notre arbre LDAP est vide, comme le montre l'affichage de la commande :
$sudo ldapsearch -x -b dc=sae,dc=com
Explication de la commande :
ldapsearch: Commande qui permet d'ouvrir une connexion sur un serveur LDAP et effectuer des recherches à l'intérieur avec des filtres si besoin.-x: Indique que l'authentification au serveur LDAP sera "simple", c'est à dire avec un login et un mdp ou anonymement si le serveur le permet. Sans le-x, ce sera avec Kerberos ou encore GSSAPI.-b:dc=sae,dc=com. Permet d'indiquer le noeud auquel on veut se connecter.

Le résultat nous indique qu'il n'y a pas de données en dessous de la racine dc=sae,dc=com.
Pour ce faire, on va créer un fichier structure.ldif contenant :
dn: dc=sae,dc=com
dn: ou=Manager,dc=sae,dc=com
objectClass: organizationalUnit
ou:Clients
dn: ou=Admin,dc=sae,dc=com
objectClass: organizationalUnit
ou:Admin
Pour ajouter la structure, on rentre la commande en sudo :
$sudo ldapadd -c -x -D cn=admin,dc=sae,dc=com -f structure.ldif -W

On peut voir qu'il n'est pas content mais pas de soucis. C'est parcequ'il manque une définition précise du dn: dc=sae,dc=com.. Il s'attendait qu'on lui mette des objectClass mais dans ce cas pas besoin pour ce noeud car on l'a déjà défini lors du dpkg-reconfigure.
Explication de la commande :
ldapadd: Commande qui permet d'ouvrir une connexion sur un serveur LDAP et effectuer d'ajouter des informations (structure ou données).-c: Permet de continuer d'exécuter la commande sur le serveur même en cas d'erreurs, celles-ci seront juste reporté sur la console en guise d'information.-x: Indique que l'authentification au serveur LDAP sera "simple", c'est à dire avec un login et un mdp ou anonymement si le serveur le permet. Sans le-x, ce sera avec Kerberos ou encore GSSAPI.-D:cn=admin,dc=sae,dc=com. Permet d'indiquer le noeud auquel on veut se connecter et avec quel utilisateur. Ici, l'utilisateuradmina été configuré lors dudpkg-reconfigureen tant d'admin de l'annuaire.-f:structure.ldif. Permet d'indiquer que les données à ajouter se trouve dans le fichier qui suit.-W: Permet d'indiquer que lors de l'authentification, on rentrera le mot de passe une fois la commande rentré. Ça permet de ne pas devoir le rentrer en clair dans la commande. Ici, on devra rentrer le mot de passe de l'utilisateuradmin.
Désormais, quand on affiche le contenu du noeuf dc=sae,dc=com, on peut voir que l'OU Manager et l'OU Admin ont bien été ajoutées :

On va ensuite ajouter un premier client à la main à partir du fichier nouveau_manager.ldif :
dn: uid=jdupont,ou=Manager,dc=sae,dc=com
objectClass: InetOrgPerson
uid: jdupont
cn: jean dupont
sn: dupont
userPassword: {crypt}$5$ougAa51VGc4XHB2B$eYFp3t9sru7Y3VkGskxNO7gi7AfXiDkRWo.xpKevOw9
À savoir : Chaque noeud doit obligatoirement être lié à un ou plusieurs objectClass qui vont le définir. Un peu comme les objets en Python. Et chaque objectClass possède des attributs obligatoire et d'autres facultatifs. Ici, uid, cn et sn sont obligatoire, en revanche userPassword est facultatif.
Pour le mot de passe, j'ai généré son hash avec la commande mkpasswd du paquet whois. Pour que LDAP le reconaisse comme étant un hash, il faut commencer par {crypt} puis mettre le hash. Avec la commande :
$mkpasswd -m sha256crypt toto
En utilisant sha256 ici. Le -m permet de spécifier le type de chiffrement à effectuer.

On ajoute le nouveau client avec la commande :
$sudo ldapadd -c -x -D cn=admin,dc=sae,dc=com -f nouveau_manager.ldif -W
Et on voit le résultat lorsqu'on affiche en dessous du noeud ou=Manager,dc=sae,dc=com :

On va faire idem pour initialiser un nouvel administrateur à partir du fichier nouveau_admin.ldif :
dn: uid=ldubois,ou=Admin,dc=sae,dc=com
objectClass: InetOrgPerson
uid: ldubois
cn: lucas dubois
sn: dubois
userPassword: {crypt}$5$ougAa51VGc4XHB2B$eYFp3t9sru7Y3VkGskxNO7gi7AfXiDkRWo.xpKevOw9
En l'ajoutant et en affichant, on voit bien qu'il apparait en dessous de son OU Admin :

Si on essaye d'ajouter un nouvel utilisateur (manager ou admin) mais que son uid est déjà présent dans l'annuaire, alors il n'y aura pas d'ajout ni de réécriture.
Cela est du qu'un noeud doit avoir un DN unique, et que celui-ci est composé de l'uid puis du chemin :

Serveur DMZ
Installation du service FTP
Côté Serveur
Côté serveur, il faudra installer le paquet vsftpd (Very Secure FTP Daemon).
Pour que le daemon soit automatiquement démarré lors du boot de la machine, rentrer la commande :
$sudo systemctl enable vsftpd
La configuration du serveur FTP se fera dans le fichier /etc/vsftpd.conf qu'il faudra modifier en sudo.
À l'intérieur de ce fichier, nous allons :
Décommenter les lignes :
write_enable=YES: Va permettre aux utilisateurs de déposer, modifier et supprimer des fichiers.chroot_local_user=YES: La personne se connectera à un user du système. Cela permettra de restreindre l'accès à son répertoire, pour qu'il ne puisse pas se balader sur le système.
Rajouter les lignes :
-
allow_writeable_chroot=YES: Cette ligne est en complément dechroot_local_user=YES. Elle permettra que l'utilisateur puisse écrire dans son répertoire personnel. -
pasv_enable=YES: Permet que ce soit le client qui établisse la connexion vers le serveur FTP. Si on ne met pas cette ligne, ce sera l'inverse, et si le client est derrière un Pare-Feu ou un NAT, le serveur ne pourrait pas se connecter (Unreacheable) ! pasv_min_port=30000: Lorsqu'un client fait une demande de connexion au serveur FTP, le serveur FTP lui renverra une plage de ports auquel il pourra se connecter. Voici l'adresse minimal de la plage.pasv_max_port=30100: Et voici l'adresse maximal de la plage.
On redémarre évidement le service vsftpd avec :
$sudo systemctl restart vsftpd
Et on regarde l'état du service avec :
$sudo systemctl status vsftpd

Comme on peut le voir, j'ai un problème... Et pour regarder pourquoi il y en a un, on va essayer de lancer à la main le service avec :
$sudo /usr/sbin/vsftpd
Et le problème nous apparaît claire comme de l'eau de roche (plus qu'à le règler (c'est le "s" en trop à la fin dans ce cas)) !

Ensuite, il va falloir créer un utilisateur spécifique avec son répertoire personnel pour le service FTP qui servira de répertoire de partage de fichier.
On va créer comme pour le serveur SAMBA, un utilisateur sans shell pour des raisons de sécurité et également son mot de passe :
$sudo useradd ftpuser
$sudo passwd ftpuser
Puis, encore comme pour le user du serveur SAMBA, on va créer son répertoire personnel avec les bons droits :
$sudo mkdir /home/ftpuser
$sudo chown ftpuser:ftpuser /home/ftpuser
$sudo chmod -R 700 /home/ftpuser
Côté Client
Côté client, on voudra se connecter depuis le terminal, on installera donc le paquet ftp. Si on avait voulu une interface graphique, on aurait utilisé filezilla par exemple.
Ici, je le ferai depuis le routeur en guise de test.
Il faudra saisir pour se connecter :
$sudo ftp 192.168.10.10
Puis entrer en Name ftpuser et son mot de passe : On atteri sur le partage FTP :

Site Web
Le but du site web sera de laisser des failles (injection de fichier, attaque par force brute, injections LDAP, attaque XXE, SSRF (à partir des URL), Reverse Shell) pour permettre à un attaquant d'accèder à la base MYSQL, à LDAP ou encore de permettre une élévation de privilèges. Il faut que la page web soit ergonomique (Javascript, manipulation du DOM.)
Voici la structure du site Web :
/var/www/html/
|--index.html
|--hotel_leocard/
|--index.html
|--html/
|--presentation_chambres.html
|--formulaire_reservation_chambre.html
|--connexion_client.html
|--inscription_client.html
|--connexion_administration.html
|--php/
|--traitement_formulaire_reservation_chambre.php
|--traitement_connexion_client.php
|--traitement_inscription_client.php
|--traitement_connexion_administration.php
|--portail_gestion_admin.php
|--portail_gestion_manager.php
|--css/
|--style.css
|--js/
|--script.js
|--ressources/
|--images/
|--videos/
|--icons/
Installation du site
Il faudra installer le paquet apache2, php, php-mysql et php-ldap. Sans le module php, rien ne s'affichera dans les pages .php autrement.
Une fois installé, il faut assigner le dossier /var/www/html/ et ses sous-répertoires à l'utilisateur www-data ainsi qu'au groupe www-data.
$chown -R www-data:www-data /var/www/html/
Mettre ces attributions sont obligatoires, elle permet au serveur web (qui est l'utilisateur www-data en réalité !) d'avoir les bonnes permissions pour pouvoir lire et exécuter les fichiers.
Authentification via MYSQL et PHP PDO
Pour ce faire, il faudra créer 2 fichiers, le premier html et le deuxième php. Le fichier html permettra de créer le formulaire et le fichier php permettra de traiter les informations qui sont contenus à l'intérieur.
Formulaire html basique (à mettre dans le body) :
<form action="traitement_formulaire.php" method="POST">
<p>Nom :</p>
<input type="text" id="login" name="login" required><br><br>
<p>Email :</p>
<input type="password" id="password" name="password" required><br><br>
<button type="submit">Envoyer</button>
</form>
Explication :
-
<form action="traitement_formulaire.php" method="POST">:action="traitement_formulaire.php": Permet qu'une fois le formulaire html validé, le contenu soit envoyé en traitement à ce fichier php.method="POST": Permet d'envoyer les données avec la méthode POST, la plus sécurisé car les données sont envoyées dans le corps de la requête et non dans l'URL (comme la méthode GET le ferai.)
-
<input type="text" id="login" name="login" required><br><br>:type="text": Permet à l'utilisateur de rentrer du texte. Ça aurait pu être type="password" et dans ce cas le champs de saisi aura les caractères masqués quand l'utilisateur tapera son mot de passe.id="login": Permet de référencer le champs pour pouvoir y accèder en Javascrypt ou le CSS par exemple.name="login": Permet de référencer le champs pour pouvoir y accèder en PHP.
Création du lien entre PHP et Mysql en utilisant PDO
Cette configuration est sur la page traitement-formulaire.php.
Avant de faire le lien avec Mysql, il faut qu'il y ai une BDD valide et un utilisateur configuré qui nous servira d'identifiant de connexion. Si ce n'est pas déjà fait, aller ici : Configuration BDD Mysql.
<?php
// Il est préférable ici de mettre l'IP
$servername = "192.168.20.20";
// Ci-dessous les identifiants de connexion à la BDD
$username = "leocard";
$password = "abc";
// Le nom de la BDD à laquelle on veut se connecter
$dbname = "hotel_leocard";
// Connexion de base à la BDD
try {
$connexion = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$connexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
echo "Connexion à la BDD réussie.";
?>
Écriture de données à la BDD depuis PHP
Désormais je vais ajouter des données de client. Il y a 2 méthodes :
Méthode non sécurisé
Méthode non sécurisé, on ne contrôle pas les données de l'utilisateur.
$nom = "dupont";
$prenom = "jean";
$uid = "jdupont";
$password_hash = password_hash("toto");
$connexion->query("INSERT INTO client (nom, prenom, uid, password_hash) VALUES ('$nom', '$prenom', '$uid', '$password_hash')");
On voit bien que le nouveau client a été ajouté :

À savoir, la méthode pour recevoir les erreurs MYSQL directement sur le PHP est d'utiliser :
try {
// Création et insert des données dans la table client :
$nom = "dupont";
$prenom = "jean";
$uid = "jdupont";
$password_hash_client = password_hash("toto", PASSWORD_DEFAULT);
$connexion->exec("INSERT INTO client (nom, prenom, uid, password_hash) VALUES ($nom, $prenom, $uid, $password_hash_client)");
echo "Les données ont bien été insérées dans la BDD";
// Si il y a une erreur en cours de route, on passera dans le catch
} catch(PDOException $e) {
echo "<br>" . $e->getMessage();
}
Méthode sécurisé
Méthode sécurisé, on contrôle les données de l'utilisateur.
$nom = "dupont";
$prenom = "jean";
$uid = "jdupont";
$password_hash = password_hash("toto", PASSWORD_DEFAULT);
// On met des ':' devant les noms de variables pour dire qu'on prépare
// la requête et qu'elle sera comme celà à la fin (cette syntaxe)
$preparation_requete_sql = "INSERT INTO client (nom, prenom, uid, password_hash) VALUES (:nom, :prenom, :uid, :password_hash)";
// Voici comment les injections sql sont évitées ! Ici, on prépare
// SQL à recevoir une requête de cette syntaxe, si il y a le moindre
// changement de syntaxe en cours, il annulera la requête.
$requete_sql = $connexion->prepare($preparation_requete_sql);
// Et après on insére les données du client dans la requête
$requete_sql->bindParam(':nom', $nom);
$requete_sql->bindParam(':prenom', $prenom);
$requete_sql->bindParam(':uid', $uid);
$requete_sql->bindParam(':password_hash', $password_hash);
// Enfin, on envoie la requête à MariaDB
$requete_sql->execute();
Point important : Normalement il faut mettre dans la requête des simple quote ' autour des valeurs qui seront inserées. Pour le cas normal il les faut. Cependant il ne les faut pas lorsqu'on utilise les requêtes préparées !
Lecture de données de la BDD depuis PHP et affichage
Ce script provient de la page portail_gestion_manager.php qui affiche les message de puis la BDD message_administrateur dans la table message :
if ($conn) {
// La requête de base qui retourne un objet d'instance PDOStatement
$resultat_query = $conn->query("SELECT objet, message, date FROM message");
// Je met l'objet sous forme d'une liste qui contiendra chaque ligne de réponse
// PDO::FETCH_ASSOC va être un formatage du retour. Ici, sous la forme
// Array ( [0] => Array ( [objet] => Nouveau message [message] => contenu message [date] => 2025-12-20 21:21:04 ) )
$resultat_fetch = $resultat_query->fetchAll(PDO::FETCH_ASSOC);
// Affichage des messages des administrateurs
foreach ($resultat_fetch as $ligne) {
echo $ligne['objet']."</br>";
echo $ligne['message']."</br>";
echo $ligne['date']."</br>";
echo "</br>";
}
}
Authentification d'un client avec la BDD depuis PHP
J'utiliserai ici des requêtes préparées donc sécurisées.
$uid = $_POST['uid'];
$password = $_POST['password'];
// On met des ':' devant les noms de variables pour dire qu'on prépare
// la requête et qu'elle sera comme celà à la fin (cette syntaxe)
$preparation_requete_sql = "SELECT * FROM client WHERE uid = :uid";
// Voici comment les injections sql sont évitées ! Ici, on prépare
// SQL à recevoir une requête de cette syntaxe, si il y a le moindre
// changement de syntaxe en cours, il annulera la requête.
$requete_sql = $connexion->prepare($preparation_requete_sql);
// Et après on insére les données du client dans la requête
$requete_sql->bindParam(':uid', $uid);
// Enfin, on envoie la requête à MariaDB
$requete_sql->execute();
// J'utilie fetch() pour n'obtenir qu'une seule liste car le
// résultat de mon SELECT ne doit renvoyer qu'une seule ligne
$resultat_fetch = $requete_sql->fetch(PDO::FETCH_ASSOC);
print_r($resultat_fetch);
// Si il y a un user dans la réponse du SELECT et que le mot de passe correspond, alors il est authentifié en tant que client
// La fonction password_verify est de cette forme :
// password_verify($mot_de_passe_en_clair, $mot_de_passe_hashé);
// Si ça correspond alors c'est True.
if ($resultat_fetch && password_verify($password, $resultat_fetch['password_hash'])) {
// Je démarre une session ou reprend celle déjà existante et j'indique que cette session correspond à un client
session_start();
$_SESSION['role'] = 'client';
}
Authentification via LDAP
Ceci étant des tests, tout comme l'authentification via Mysql, on fera juste en sorte que ça fonctionne, on fera le site web complet plus tard. Ici l'idée est donc de se connecter à titre expérimental au site en utilisant l'annuaire LDAP qui est sur le serveur LDAP.
On va créer 2 fichiers, formulaire-pour-ldap.html et traitement-formulaire-pour-ldap.php.
Formulaire HTML basique
On va faire le même formulaire que dans le fichier formulaire.html à l'exeption qu'on enverra les données au fichier traitement-formulaire-pour-ldap.php.
<form action="traitement-formulaire-pour-ldap.php" method="POST">
<p>Nom :</p>
<input type="text" id="login" name="login" required><br><br>
<p>Email :</p>
<input type="password" id="password" name="password" required><br><br>
<button type="submit">Envoyer</button>
</form>
Création du lien entre PHP et LDAP
On éditera le fichier traitement-formulaire-pour-ldap.php. Cette page de wiki sera le sacro-saint : Documentation Officielle PHP-LDAP.
Avant de faire le lien avec LDAP, il faut qu'il y ai un annuaire valide et un utilisateur configuré qui nous servira d'identifiant de connexion. Si ce n'est pas déjà fait, aller ici : Installation et Configuration Annuaire LDAP.
Voici mon fichier php :
<?php
// Récupération des informations de connexion du formulaire
$login_user = $_POST["login"];
$password_user = $_POST["password"];
// Information de connexion à l'annuaire LDAP
$ip_serveur_ldap = "192.168.20.10";
$connexion_ldap = ldap_connect("ldap://".$ip_serveur_ldap);
if ($connexion_ldap) {
// Il faut activer la version 3 de LDAP car la 2 est obsolète ! Pas d'authentification simple.. etc
ldap_set_option($connexion_ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
// On tente la connexion en supposant que c'est un client ou que c'est un admin
$connexion_bind_client = ldap_bind($connexion_ldap, "uid=$login_user,ou=Clients,dc=sae,dc=com", $password_user);
$connexion_bind_admin = ldap_bind($connexion_ldap, "uid=$login_user,ou=Admin,dc=sae,dc=com", $password_user);
// On test si c'est un client, un admin ou si les identifiants sont incorrects
if ($connexion_bind_client) {
echo "Bienvenue cher client. Vous êtes bien connecté en tant que $login_user."."<br/>";
} elseif ($connexion_bind_admin) {
echo "Bienvenue cher admin. Vous êtes bien connecté en tant que $login_user."."<br/>";
} else {
echo "L'identifiant ou le mot de passe est incorrect.";
}
}
?>
Session PHP
Une fois connecté depuis la page connexion_administration.html, il va falloir créer une nouvelle session pour toutes la pages qui le demande (portail_gestion_admin.php et portail_gestion_manager.php).
Création de la SESSION
Pour ce faire, il va falloir créer une fois loggé la session avec :
// À chaque page qui nécessite la variable $_SESSION, on appelle session_start()
// Permet de démarrer ou de reprendre une session existante
session_start();
// On défini pour $_SESSION qu'il va possèder un couple ; role:admin. Qu'on va pouvoir récupérer sur les autres pages qui le nécessite.
$_SESSION['role'] = "admin";
Utilisation des paramètres de SESSION
L'utilisation se fera en deux temps, et je vais prendre l'exemple de la page gestion_portail_administrateur.php :
En premier je test si $_SESSION['role'] est défini pour l'utilisateur en cours avec :
session_start();
if (!isset($_SESSION['role'])) {
header('Location: ../html/connexion_administration.html');
}
Puis dans un deuxième temps si il existe je vais vérifier pour savoir si c'est un admin dans ce cas.
// Si l'utilisateur possède une session, on vérifie que c'est un admin
if ($_SESSION['role'] !== 'admin') {
header('Location: ../html/connexion_administration.html');
}
Autrement, je le renvoie vers la page de connexion connexion_administration.html, c'est le rôle du header dans :
header('Location: ../html/connexion_administration.html');
Exemple de mon fichier gestion_portail_administrateur.php :
<?php
// Avant tout affichage HTML, on vérifie que l'utilisateur possède bien une session
session_start();
if (!isset($_SESSION['role'])) {
header('Location: ../html/connexion_administration.html');
}
// Si l'utilisateur possède une session, on vérifie que c'est un admin
if ($_SESSION['role'] !== 'admin') {
header('Location: ../html/connexion_administration.html');
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Hotel Léocard</title>
<meta charset="utf-8">
</head>
<body>
<p>Texte affiché dans le Body si la personne qui se connecte est un admin.</p>
</body>
</html>
Il faudra toujours faire la vérification php en premier avant d'afficher du html.
Bootstrap
Pour mon site web j'utiliserai bootstrap.
Installation de Bootstrap
Il faudra se rendre sur le site Site Téléchargement Bootstrap et installer :

Le fichier installé est un zip qui contient 2 répertoires, css/ et js/. Et nous allons les placer dans l'arborescence du site à la place du répertoire css/ et js/ existant. Jes les envoies ici avec scp :

Et je les retrouve bien sur serveur-dmz :

Utilisation de Bootstrap
En premier, il faudra lier le css et le css de bootstrap. Pour ce faire, on va faire le lien css dans le head et le lien js en bas du body. C'est une bonne habitude de mettre le lien js en bas du body car autrement js pourrait vouloir affecter des éléments html qui n'existerai pas encore ! Il y a donc des soucis. Dans mon cas je met le js mais je ne m'en servirai pas forcément.
Voici un exemple minimal :
<!DOCTYPE html>
<html>
<head>
<title>Hotel Léocard</title>
<meta charset="utf-8">
<!-- Lien vers le CSS -->
<link rel="stylesheet" href="../css/bootstrap.min.css">
</head>
<body>
<!-- Lien vers le JS (en bas de page) -->
<script src="../js/bootstrap.bundle.min.js"></script>
</body>
</html>
Et dans mon exemple, j'ai juste mit les liens sur ma mage gestion_portail_admin.php et je peux déjà voir une différence d'affichage :

Mini cours Bootstrap
Pour toutes les classes existante, aller sur la documentation officielle de Bootstrap. Cf Documentation Officielle Bootstrap.
Fonctionnement basique
À savoir : Bootstrap fonctionne exclusivement avec des class CSS. Exemple :
<button class="btn btn-primary">Valider</button>
Il faudra toujours appeler en premier la classe principale, ici btn puis une ou plusieurs classes plus spécifique, ici btn-primary.
- btn : Fait référence au style commun de bouton.
- btn-primary : Fait référence au style spécifique du bouton bleu. Il ne redéfinit pas tout, il ajoute seulement quelques éléments de style à
btnqui contient déjà les principaux.
Pour la couleur, voici les principales :
- Rouge :
danger - Vert :
success - Jaune :
warning - Noir :
dark - Clair :
light
Ainsi, le bouton de base <button>Valider</button> est :

Et le résultat une fois le bootstrap appliqué <button class="btn btn-primary">Valider</button> est :

Organisation d'une page
Ici, je parlerai de la notion de Grille qui permet de décrire précisément chaque endroit de la page. En utilisant des container, row et col :
Le but et de pouvoir s'adapter à toutes les tailles d'écran. Ils doivent être organisé de cette façon :
<div class="container">
<div class="row">
<div class="col">Colone 1 de la grille</div>
</div>
</div>
Il peut bien évidement y avoir plusieurs colones et plusieurs lignes. Cependant, pour qu'il y ai une ligne row, il faut qu'il y ai un container qui l'englobe. Idem pour les colones avec le row.
Il existe le concept des 12 blocs dans le colonnes. Ainsi, une row est divisé en 12 et chaque col peut choisir d'en prendre un certain nombre. Exemple ici d'une colone qui prend 6 (donc la moitié) :
<div class="container">
<div class="row">
<div class="col-6">Colone 1 de la grille</div>
</div>
</div>
Pour centrer horizontalement un row (ça ne s'applique que sur le row), il faut rajouter le lien de classe :
Dans la syntaxe, le - sert à spécifier à la suite un complément de style css. Ici, que la colonne fera la moitié de l'écran.
Souvent utilisé
Pour les formulaire, class="form-control" est souvent utilisé pour mettre en forme.
Sans :

Avec (également avec les colonnes et le centrage, ici col-3) :

Navbar
Voici la structure de base, celle-ci est lourde mais complète :
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" href="#">Accueil</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">À propos</a>
</li>
</ul>
</div>
</div>
</nav>
Ensemble des codes des pages HTML et PHP
Site non sécurisé (hotel_leocard/)
Pages HTML
index.html
presentation_chambre.html
formulaire_reservation_chambre.html
connexion_client.html
inscription_client.html
connexion_administration.html
Pages PHP
traitement_formulaire_reservation_chambre.php
traitement_connexion_client.php
traitement_inscription_client.php
traitement_connexion_administration.php
portail_gestion_admin.php
Ici, il y aura des informations pour l'admin, et surtout la possibilité d'envoyer des messages sur le dashboard des managers. C'est par là que je vais envoyer l'attaque XSS. Il faudra donc un formulaire.
portail_gestion_manager.php
Le but de cette page sera d'accueillir l'attaque XSS pour que un manager se connecte et se fasse voler son cookie.
Je vais ici passer par une BDD MariaDB qui contiendra le XSS stored sous forme de message que l'administrateur a envoyé.
Attaquant Interne
Installation de NMAP
Il faudra installer le paquet nmap avec :
$sudo apt install nmap
Poste Manager
Je vais installer une interface graphique minimal sur la VM, pour ce faire, je vais ouvrir le menu des interfaces graphiques possible avec la commande :
$sudo tasksel
Et j'obtiens :

Je vais sélectionner Xfce avec la barre espace.
Puis je vais sélectionner la version graphique par défaut qui s'exécutera grâce à la commande :
$sudo update-alternatives --config x-session-manager

Je vais choisir dans mon cas 0 pour xfce4. Le mode automatique est l'option qu'il a jugé la meilleure.
TigerVNC
DISCLAIMER : ÇA N'A PAS MARCHÉ POUR MOI, MA CONNECTION VNC NE FONCTIONNE PAS CAR IL ME DIT QUE LE MOT DE PASSE EST MAUVAIS ALORS QU'IL EST BON... IL FAURA QUE JE M'Y REPENCHE
Cela va me permettre de faire un vnc sur la machine poste-manager.
Serveur TigerVNC
Pour pouvoir faire un vnc sur la machine, j'ai installé :
$sudo apt install tigervnc-standalone-server
Je vais créer le mot de passe, obligatoire car autrement le serveur VNC ne démarrera pas :
$vncpasswd
Et j'ai mis comme mot de passe azerty (il faut au moins qu'il fasse 6 caractères). J'ai dit non au mode view-only, ne sert à rien.
Puis je démarre l'écoute vnc sur le port par défaut 5901 avec :
$vncserver :1
Ça sera le port 5901 car 5900+1, 1 qui est le numéro que j'ai saisi.
Pour information, les données du serveur VNC comme les logs ou le pid du processus sont stockées dans /home/leocard/.config/tigervnc/
Client TigerVNC
Sur le client qui est sur le shéma ma machine Pc-Portable, je vais installer le paquet tigervnc-viewer avec :
$sudo apt install tigervnc-viewer
Et pour me connecter, je n'aurai qu'à faire :
$vncviewer 192.168.20.40:5901
Ça ne fonctionne pas car mon Pc-Portable a une passerelle par défaut vers l'extérieur, je vais donc rajouter une route par défaut pour ce réseau précis avec la commande :
$sudo ip route add 192.168.20.0/24 via 192.168.56.10 dev vboxnet0
Bon, ça aurait du fonctionner mais j'ai eu l'erreur :

Ça signifie que la machine poste-manager est accessible mais que la connexion vnc est impossible.
Analyse avec le classique ss -lunt sur poste-manager :

Et on voit bien que le port 5901 est ouvert seulement en local.
J'ai regardé sur internet et c'est une sécurité de vnc de ne pas s'ouvrir à tout le monde, car vnc n'est pas très sécurisé en lui-même.
Le but ici est de nous faire ouvrir une connexion SSH en -L pour ouvrir le port 5901 en local puis d'initier la connexion VNC. Et c'est ce que je vais faire avec depuis Pc-Portable :
$sudo ssh -L 5901:localhost:5901 poste-manager
Pour relancer le serveur vnc, il faut faire un peu bourrin (sur poste-manager) :
$vncserver -kill :1
Puis pour le relancer :
$vncserver :1
Et on peut voir que ça fonctionne ensuite :

J'ai eu un problème, car j'avais installé avant un serveur VNC et je dois kill le processus qui tourne sur ma machine sur le port 5901, .. Donc pour trouver qui tourne derrière, je vais utiliser la commande lsof comme suit :
$sudo lsof -i :5901
Explication de la commande : $sudo lsof -i :5901.
lsof: Permet de lister tous les fichiers ouverts par tous les processus (en gros tout ce qui tourne sur l'OS car Linux considère tout comme un fichier).-i: Filtre par fichier réseau, par défaut il va lister les ports réseaux utilisés (UDP et TCP).:5901: Et ici, je filtre donc par le port:5901
Et je vais kill le processus, dans mon cas avec le PID 3783 avec :
$sudo kill 3783