Gestion des capabilities

Si vous avez suivi le projet Discovery alors vous avez sûrement dû vous rendre compte qu’il est possible de lancer un scan UDP sur les IP’s découvertes. Si la majeure partie du code fonctionne avec des droits basiques, une fonctionnalité ne pourra fonctionner qu’avec les droits root : le scan UDP.

La raison est simple, lorsque l’on scan un port avec UDP, on envoie en fait un header vide sur chacun des ports de la machine ciblée. Si la machine destinataire nous renvoie un message ICMP de type 3 et de code 3 (« port unreachable ») alors on sait que le port est fermé. Si on reçoit un autre code c’est que le port est soit ouvert soit filtré.

Or pour utiliser ICMP sous Linux il faut disposer des droits root. C’est d’ailleurs pour cela que le binaire ping est marqué par un SUID :

cap1.png

Alors qu’est ce que je fais ? Je marque le binaire nmap d’un bit SUID et je l’exécute en tant que root ? Ça fonctionnerait mais ça serait dangereux puisque n’importe quel utilisateur pourra augmenter ses privilèges via l’utilisation des options –script ou –interactive.

Non, pour pallier ce problème nous allons utiliser les capabilities. Pour faire simple, les capabilities constituent un ensemble de sous privilèges liés au privilège root. L’idée avec les capabilities c’est qu’on va découper les privilèges root en plusieurs sous privilèges que l’on pourra attribuer (ou non) à un binaire en fonction des besoins de ce dernier.

L’exemple le plus courant pour illustrer le fonctionnement des capabilities c’est de supprimer le SUID sur le binaire ping ce qui aura pour conséquence de nous empêcher d’envoyer des requêtes ICMP :

cap2.png

Si derrière je lui attribue les bonnes capabilities je pourrais à nouveau pinger sans pour autant que mon binaire ping dispose de l’entièreté des privilèges root :

cap3.png

Tout ce que nous venons de faire c’est d’affiner les droits du binaire ping en appliquant la règle du « moindre privilège ».

Actuellement Linux supporte environ 40 capabilities que l’on pourra lister en utilisant la commande suivante :

capsh --print

cap4.png

Vous trouverez la liste des capabilities ainsi qu’une description expliquant leurs utilités en lisant le man :

man capabilities

Alors comment ça marche l’attribution de capabilities ? Eh bien avant tout il faut savoir qu’il existe trois ensembles de capabilities :

Effective: liste les capabilities autorisées par le noyau pour le processus
Permitted: liste les capabilities permises pour un processus.
Inheritable: liste les capabilities qui sont transmises lors d’un appel à execve. Pour rappel execve remplace le flux d’instruction du processus courant par celui d’un autre processus. Il peut donc être nécessaire que ce processus hérite des mêmes capabilities que le processus originel.

Pour qu’un processus puisse utiliser une capability il faut que cette dernière soit à la fois présente dans le set effective et permitted. D’ailleurs si on reprend l’exemple vu plus tôt sur le binaire ping on remarque que nous avons bien placé la capability à la fois dans le set effective et dans le set permitted :

sudo setcap cap_net_rwa=pe /bin/ping

Pour attribuer des capability à un binaire nous nous servirons de la commande setcap :

sudo setcap nom_de_la_capability=(p et/ou e et/ou i) chemin_du_binaire

Pour  lister les capabilities liés à un binaire on se servira de la commande getcap :

sudo getcap chemin_du_binaire

cap5.png

Si vous commencez à jouer un peu avec les capabilty je vous invite fortement à utiliser le binaire capsh afin de vérifier l’étendu de vos actions. En effet si vous supprimez une capability vous pouvez potentiellement pourrir votre système. Ça serait dommage surtout quand on sait que le binaire capsh est capable d’exécuter un binaire en dropant une capability à la volée. Par exemple on pourra drop la capability cap_net_raw et voir comment se comporte le binaire ping :

capsh --drop=cap_net_raw --print -- -c "/bin/ping -c 1 127.0.0.1"

cap6.png

Globalement voilà ce qu’il faut savoir sur les capabilities. Je vous invite, encore une fois, fortement à consulter le man afin de voir l’étendu des possibilités de ce mécanisme de sécurité.

Pour en revenir à notre problème originel, comment faire pour autoriser le scan UDP ? Eh bien de la même manière que nous venons de le faire avec ping, nous allons lui attribuer des capabilities !

sudo setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip /usr/bin/nmap

Arguments:

cap_net_raw : autorise l’utilisation des sockets.
cat_net_admin : autorise la configuration des interfaces, l’administration du firewall, la modification des tables de routage, donne la possibilité de se binder à un port sur n’importe quelle adresse, autorise la mise en place du mode promiscuous sur une interface, active le multicast.
cat_net_bind_service : autorise le bind sur un port plus petit que 1024.

On s’assurera ensuite que les capabilities ont bien été positionnées :

sudo getcapt /usr/bin/nmap

cap7.png

Pour lancer un scan nmap UDP il ne nous restera plus qu’à spécifier l’option –privileged :

nmap --privileged -sU localhost

cap8.png

Notre scan UDP fonctionne !