Installation et utilisation de Blackarch dans un container Docker
Dans mes dernières CTF je me suis mise à utiliser BlackArch, pour deux principales raisons :
- J’utilise Arch Linux comme système principal, et suis donc familière à ce système.
- Il y a beaucoup trop de configuration dans un Kali Linux ou un Parrot qui me semble trop opaques (la quête sainte des Archistes contre le bloat).
S’ajoute à cela deux soucis que je rencontrais dans mon utilisation précédente de Kali et Parrot :
- La virtualisation c’est lourd, et si tant est que l’on a peu de RAM on risque très vite l’overflow. Le
swap
étant bien trop lent ce n’est pas un patch convenable. - Faire tourner un système live m’empêche d’avoir une persistance convenable. Oui c’est le concept. Oui c’est souvent configurable ou outre-passable, non je ne l’ai pas fait.
- Une installation d’un système sur un disque externe, ou une seconde partition, m’oblige à synchroniser sur deux systèmes des données (WebDav, Outils de communications etc.). Oui je pourrai utiliser une partition
/home
, mais mon installation LUKS+LVM me convient.
J’en suis venue à une solution qui est non-seulement plus légère que la virtualisation, mais aussi me permet de ne pas utiliser de système séparé, ne pas avoir à synchroniser mes logiciels, et me permet d’avoir un choix plus que complet sur la configuration à ma disposition.
J’utilise BlackArch (lien). Moins qu’un système, c’est surtout un dépôt de logiciels prévus pour la cybersécurité, disponible via pacman après configuration sur Arch. Les auteurices proposent aussi des images ISO, et un script d’installation des dépôts (des outils spécifiques ont aussi été écris).
Ne voulant pas polluer mon système avec la configuration du lab, j’ai décidé de tenter le coup avec Docker (lien), puisque je tourne déjà avec Arch les conditions étaient plus qu’optimales pour qu’un container tourne correctement.
Mes envies et besoins en fonctionnalités⌗
J’avais au départ quelques fonctions en tête, qui me semblaient nécessaires :
- Pouvoir exécuter des applications graphiques, en forwardant les prototypes de fenêtres vers mon serveur X. Cette solution a l’avantage de ne pas demander beaucoup de ressources graphiques, contrairement à un rendu via VNC.
- Ne pas avoir de configuration réseaux à faire. Il m’arrive régulièrement de lancer des serveurs chisel (lien), de me mettre en écoute via netcat, de lancer un OpenVPN, de monter un serveur HTTP à la volée ou que sais-je encore, je n’ai pas envie d’être limitée par l’exposition des ports du container.
- Avoir un dossier partagé avec le container. Je ne veux pas exposer mon système complet, mais juste ce qu’il me semble nécessaire.
S’ajoute à ça un certain nombre de paquets minimums au build de mon image.
Le build⌗
Le DockerFile que j’utilise est assez direct :
FROM blackarchlinux/blackarch:latest
# hostapd-wpe needs make, but it's not a dep because it's assumed to be installed despite not being a dep
RUN pacman -Syu --noconfirm make && \
# Install packages
pacman -Syu --noconfirm base-devel nano tmux man man-pages pciutils less bash-completion \
blackarch-config-zsh ttf-liberation \
xorg-server xfce4 \
mesa mesa-utils \
blackarch-recon blackarch-webapp blackarch-cracker blackarch-exploitation && \
# Copy BlackArch configs
cp -r /etc/skel/. /root/. && \
echo 'root:blackarch' | chpasswd && \
echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
WORKDIR /root
ENTRYPOINT []
J’utilise l’image préconfigurée officielle de BlackArch, à laquelle j’ajoute simplement quelques outils. Important à noter: pour que la configuration du serveur X fonctionne correctement il faut fournir au container un certain nombre de composantes graphiques de bases, j’utilise pour ça le paquet xfce4
Le build se fait ensuite de manière classique avec la commande
$ docker build --rm --force-rm --tag blackarch/base .
Note : Il faudrait en fait construire l’image avec xbuild, je vous laisse le faire.
Exécution de l’image⌗
Pour la containérisation de l’image il faut passer un certain nombre d’arguments:
- Configurer le réseaux, s’assurer que la connexion hôte est utilisée par le container. Cela se fait en montant les devices (/dev/net/tun pour mettre en place un VPN) et les fichiers descriptifs adéquats. On ajoute enfin les permissions correctes.
- Monter le dossier partagé, en bind pour permettre la modification. À noter que les ID des groupes et utilisateurs seront écrits et lus tels quels par le container, donc si mon utilisateur
root
dans le container écris un fichier il sera écrit avec UID=0:GID=0. - Mettre en place le partage du serveur X de l’hôte.
J’automatise cela avec cette fonction dans mon script d’aide :
createContainer() {
echo "-- Création d'un nouveau container"
SHARECONF="--mount type=bind,src=$HOME/blackarch,dst=/root/blackarch"
NETCONF="--mount type=bind,src=/etc/hosts,dst=/etc/hosts --cap-add NET_ADMIN --device /dev/net/tun --network=host"
XSERVERCONF="-e DISPLAY=$DISPLAY --mount type=bind,src=/tmp/.X11-unix,dst=/tmp/.X11-unix --device=/dev/dri:/dev/dri"
sudo docker run -it $NETCONF $SHARECONF $XSERVERCONF \
blackarch/base:latest /bin/zsh
}
Une petite explication s’impose :
- Les différents
--mount type=bind,src=<chemin hôte>,dst=<chemin container>
indiquent à Docker de monter, à la création du container, les fichiers ou dossiers hôtes à la destination côté container. Cela signifie que toute modification, de l’hôte ou du container, se répercuteront sur les fichiers côté hôte.- Je monte mon
/etc/hosts
sur mon container, alors que ça n’est pas strictement utile. En effet cela me permet simplement de ne pas avoir à modifier deux fichiers lorsque je souhaite utiliser mon navigateur (sur le système hôte) et un outil du container, pour cibler une machine dont l’hostname ne profite pas d’une entrée DNS (comme c’est le cas avec les machines HackTheBox). - Je monte
/dev/net/tun
, qui est l’interface standard du kernel linux pour l’envoie et la réception de paquets à, ou depuis, un programme. En bref, c’est l’interface à laquelle se connecte un VPN logiciel. Cela signifie donc que lorsque j’applique un OpenVPN dans mon container, il se répercutera sur mon système. - Sans trop rentrer dans les détails, les fichiers descripteurs et interfaces
/tmp/.X11-unix
et/dev/dri
sont les lieux d’actions du/des serveur(s) X tournant sur la machine. La variable environnement$DISPLAY
précisant quel espace du serveur X est ciblé (unDISPLAY
pour Xorg consiste en un écran et ses périphériques d’entrées).
- Je monte mon
--network=host
signifie que le container utilisera le système réseaux de l’hôte. Donc tout les ports sont de facto exposés de la même manière que sur l’hôte.--cap-add NET_ADMIN
permet au container d’ouvrir et d’exposer des nouveaux ports comme si il était l’hôte.
Il est évident que cette configuration expose un nombre conséquent d’informations et de fonctionnalités de l’hôte au container. Il s’agit d’une configuration que j’utilise dans des environnements où je n’ai pas besoin d’anonymisation et de sécurité quant aux données ou logiciels que j’acquiert.
De toute manière si vous cherchiez à sécuriser un espace de travail avec de la containérisation vous vous mettez le doigt dans l’œil.
J’aimerais améliorer cette configuration dans le futur
- Construire mon image à partir de l’image docker ArchLinux. Utiliser l’image docker BlackArch revient juste à ajouter une étape en plus au build, surtout que si cette image arrête d’être supportée j’aurai l’air un peu bête.
- Améliorer mon script d’aide, pour l’instant il ne supporte que la création et la gestion des containers actifs (avec suppression, purge, listing et selection). J’aimerais en faire un un peu plus évolué qui me permet de construire une image en me laissant choisir des groupes de paquets et des outils.