Linux Capabilities
RootedCON est l'événement le plus pertinent en matière de cybersécurité en Espagne et l'un des plus importants en Europe. Avec pour mission de promouvoir les connaissances techniques, ce congrès est un point de rencontre bouillonnant pour les professionnels de la technologie et de la cybersécurité dans chaque discipline.\
Capacités Linux
Les capacités Linux divisent les privilèges root en unités plus petites et distinctes, permettant aux processus de disposer d'un sous-ensemble de privilèges. Cela réduit les risques en ne accordant pas inutilement des privilèges root complets.
Le Problème :
Les utilisateurs normaux ont des autorisations limitées, ce qui affecte des tâches comme l'ouverture d'un socket réseau qui nécessite un accès root.
Ensembles de Capacités :
Héritées (CapInh) :
Objectif : Détermine les capacités transmises par le processus parent.
Fonctionnalité : Lorsqu'un nouveau processus est créé, il hérite des capacités de son parent dans cet ensemble. Utile pour maintenir certains privilèges à travers les spawns de processus.
Restrictions : Un processus ne peut pas acquérir des capacités que son parent ne possédait pas.
Effectives (CapEff) :
Objectif : Représente les capacités réelles qu'un processus utilise à tout moment.
Fonctionnalité : C'est l'ensemble de capacités vérifié par le noyau pour accorder l'autorisation pour diverses opérations. Pour les fichiers, cet ensemble peut être un indicateur indiquant si les capacités autorisées du fichier doivent être considérées comme effectives.
Signification : L'ensemble effectif est crucial pour les vérifications de privilèges immédiates, agissant comme l'ensemble actif de capacités qu'un processus peut utiliser.
Autorisées (CapPrm) :
Objectif : Définit l'ensemble maximal de capacités qu'un processus peut posséder.
Fonctionnalité : Un processus peut élever une capacité de l'ensemble autorisé à son ensemble effectif, lui donnant la possibilité d'utiliser cette capacité. Il peut également supprimer des capacités de son ensemble autorisé.
Limite : Il agit comme une limite supérieure pour les capacités qu'un processus peut avoir, garantissant qu'un processus ne dépasse pas son champ de privilèges prédéfini.
Limitation (CapBnd) :
Objectif : Met un plafond sur les capacités qu'un processus peut acquérir à tout moment de son cycle de vie.
Fonctionnalité : Même si un processus a une certaine capacité dans son ensemble hérité ou autorisé, il ne peut pas acquérir cette capacité à moins qu'elle ne soit également dans l'ensemble de limitation.
Cas d'utilisation : Cet ensemble est particulièrement utile pour restreindre le potentiel d'escalade de privilèges d'un processus, ajoutant une couche de sécurité supplémentaire.
Ambiante (CapAmb) :
Objectif : Permet à certaines capacités d'être maintenues à travers un appel système
execve
, qui entraînerait normalement une réinitialisation complète des capacités du processus.Fonctionnalité : Garantit que les programmes non-SUID qui n'ont pas de capacités de fichier associées peuvent conserver certains privilèges.
Restrictions : Les capacités de cet ensemble sont soumises aux contraintes des ensembles hérités et autorisés, garantissant qu'elles ne dépassent pas les privilèges autorisés du processus.
Pour plus d'informations, consultez :
Capacités des Processus et des Binaires
Capacités des Processus
Pour voir les capacités d'un processus particulier, utilisez le fichier status dans le répertoire /proc. Comme il fournit plus de détails, limitons-le uniquement aux informations liées aux capacités Linux. Notez que pour tous les processus en cours d'exécution, les informations sur les capacités sont maintenues par thread, pour les binaires dans le système de fichiers, elles sont stockées dans des attributs étendus.
Vous pouvez trouver les capacités définies dans /usr/include/linux/capability.h
Vous pouvez trouver les capacités du processus actuel en utilisant cat /proc/self/status
ou en exécutant capsh --print
, et celles des autres utilisateurs dans /proc/<pid>/status
Ce commandement devrait renvoyer 5 lignes sur la plupart des systèmes.
CapInh = Capacités héritées
CapPrm = Capacités autorisées
CapEff = Capacités effectives
CapBnd = Ensemble de limitation
CapAmb = Ensemble de capacités ambiantes
Ces nombres hexadécimaux n'ont pas de sens. En utilisant l'utilitaire capsh, nous pouvons les décoder en noms de capacités.
Vérifions maintenant les capacités utilisées par ping
:
Bien que cela fonctionne, il existe une autre manière plus simple. Pour voir les capacités d'un processus en cours d'exécution, utilisez simplement l'outil getpcaps suivi de son identifiant de processus (PID). Vous pouvez également fournir une liste d'identifiants de processus.
Vérifions ici les capacités de tcpdump
après avoir donné suffisamment de capacités au binaire (cap_net_admin
et cap_net_raw
) pour écouter le réseau (tcpdump s'exécute dans le processus 9562):
Comme vous pouvez le constater, les capacités données correspondent aux résultats des 2 façons d'obtenir les capacités d'un binaire. L'outil getpcaps utilise l'appel système capget() pour interroger les capacités disponibles pour un thread particulier. Cet appel système n'a besoin que du PID pour obtenir plus d'informations.
Capacités des Binaires
Les binaires peuvent avoir des capacités qui peuvent être utilisées lors de l'exécution. Par exemple, il est très courant de trouver le binaire ping
avec la capacité cap_net_raw
:
Vous pouvez rechercher des binaires avec des capacités en utilisant :
Suppression des capacités avec capsh
Si nous supprimons les capacités CAP_NET_RAW pour ping, alors l'utilitaire ping ne devrait plus fonctionner.
Outre la sortie de capsh elle-même, la commande tcpdump devrait également générer une erreur.
/bin/bash: /usr/sbin/tcpdump: Operation not permitted
L'erreur montre clairement que la commande ping n'est pas autorisée à ouvrir un socket ICMP. Maintenant, nous savons avec certitude que cela fonctionne comme prévu.
Supprimer les capacités
Vous pouvez supprimer les capacités d'un binaire avec
Capacités de l'utilisateur
Apparemment, il est possible d'attribuer des capacités également aux utilisateurs. Cela signifie probablement que chaque processus exécuté par l'utilisateur pourra utiliser les capacités de l'utilisateur.
Basé sur ceci, ceci et ceci quelques fichiers doivent être configurés pour donner à un utilisateur certaines capacités, mais celui qui attribue les capacités à chaque utilisateur sera /etc/security/capability.conf
.
Exemple de fichier:
Capacités de l'environnement
En compilant le programme suivant, il est possible de créer un shell bash à l'intérieur d'un environnement qui fournit des capacités.
À l'intérieur du bash exécuté par le binaire ambiant compilé, il est possible d'observer les nouvelles capacités (un utilisateur régulier n'aura aucune capacité dans la section "actuelle").
Vous ne pouvez ajouter que des capacités présentes à la fois dans les ensembles autorisés et héritables.
Binaires conscients des capacités / Binaires ignorants des capacités
Les binaires conscients des capacités n'utiliseront pas les nouvelles capacités données par l'environnement, tandis que les binaires ignorants des capacités les utiliseront car ils ne les rejettent pas. Cela rend les binaires ignorants des capacités vulnérables à l'intérieur d'un environnement spécial qui accorde des capacités aux binaires.
Capacités de service
Par défaut, un service s'exécutant en tant que root se verra attribuer toutes les capacités, ce qui peut parfois être dangereux. Par conséquent, un fichier de configuration du service permet de spécifier les capacités que vous souhaitez lui attribuer, et l'utilisateur qui devrait exécuter le service pour éviter d'exécuter un service avec des privilèges inutiles:
Capacités dans les conteneurs Docker
Par défaut, Docker attribue quelques capacités aux conteneurs. Il est très facile de vérifier quelles sont ces capacités en exécutant :
RootedCON est l'événement le plus pertinent en matière de cybersécurité en Espagne et l'un des plus importants en Europe. Avec pour mission de promouvoir les connaissances techniques, ce congrès est un point de rencontre bouillonnant pour les professionnels de la technologie et de la cybersécurité dans chaque discipline.
Privesc/Évasion de conteneur
Les capacités sont utiles lorsque vous voulez restreindre vos propres processus après avoir effectué des opérations privilégiées (par exemple, après avoir configuré un chroot et lié à un socket). Cependant, elles peuvent être exploitées en leur transmettant des commandes ou des arguments malveillants qui sont ensuite exécutés en tant que root.
Vous pouvez forcer des capacités sur des programmes en utilisant setcap
, et les interroger en utilisant getcap
:
Le +ep
signifie que vous ajoutez la capacité ("-" la supprimerait) en tant qu'Effective et Permitted.
Pour identifier les programmes dans un système ou un dossier avec des capacités :
Exemple d'exploitation
Dans l'exemple suivant, le binaire /usr/bin/python2.6
est trouvé vulnérable à l'élévation de privilèges :
Capacités nécessaires par tcpdump
pour permettre à n'importe quel utilisateur de capturer des paquets:
Le cas spécial des capacités "vides"
D'après la documentation : Notez qu'il est possible d'attribuer des ensembles de capacités vides à un fichier de programme, et il est donc possible de créer un programme avec un ensemble d'identifiants utilisateur définis par l'utilisateur qui modifie l'identifiant utilisateur effectif et enregistré du processus qui exécute le programme en 0, mais ne confère aucune capacité à ce processus. Autrement dit, si vous avez un binaire qui :
n'est pas détenu par root
n'a pas les bits
SUID
/SGID
définisa un ensemble de capacités vide (par exemple :
getcap myelf
renvoiemyelf =ep
)
alors ce binaire s'exécutera en tant que root.
CAP_SYS_ADMIN
CAP_SYS_ADMIN
est une capacité Linux très puissante, souvent assimilée à un niveau quasi-root en raison de ses privilèges administratifs étendus, tels que le montage de périphériques ou la manipulation des fonctionnalités du noyau. Bien qu'indispensable pour les conteneurs simulant des systèmes entiers, CAP_SYS_ADMIN
pose d'importants défis en matière de sécurité, notamment dans les environnements conteneurisés, en raison de son potentiel d'escalade de privilèges et de compromission du système. Par conséquent, son utilisation nécessite des évaluations de sécurité rigoureuses et une gestion prudente, avec une forte préférence pour la suppression de cette capacité dans les conteneurs spécifiques à une application afin de respecter le principe du moindre privilège et de réduire au minimum la surface d'attaque.
Exemple avec un binaire
En utilisant python, vous pouvez monter un fichier passwd modifié sur le vrai fichier passwd:
Et enfin monter le fichier passwd
modifié sur /etc/passwd
:
Et vous pourrez su
en tant que root en utilisant le mot de passe "password".
Exemple avec l'environnement (évasion de Docker)
Vous pouvez vérifier les capacités activées à l'intérieur du conteneur Docker en utilisant :
À l'intérieur de la sortie précédente, vous pouvez voir que la capacité SYS_ADMIN est activée.
Mount
Cela permet au conteneur docker de monter le disque hôte et d'y accéder librement:
Accès complet
Dans la méthode précédente, nous avons réussi à accéder au disque hôte de Docker. Au cas où vous constateriez que l'hôte exécute un serveur ssh, vous pourriez créer un utilisateur à l'intérieur du disque de l'hôte Docker et y accéder via SSH:
CAP_SYS_PTRACE
Cela signifie que vous pouvez échapper au conteneur en injectant un shellcode à l'intérieur d'un processus s'exécutant dans l'hôte. Pour accéder aux processus s'exécutant dans l'hôte, le conteneur doit être exécuté au moins avec --pid=host
.
CAP_SYS_PTRACE
accorde la capacité d'utiliser les fonctionnalités de débogage et de traçage des appels système fournies par ptrace(2)
et les appels d'attachement de mémoire croisée comme process_vm_readv(2)
et process_vm_writev(2)
. Bien que puissant à des fins de diagnostic et de surveillance, si CAP_SYS_PTRACE
est activé sans mesures restrictives comme un filtre seccomp sur ptrace(2)
, cela peut sérieusement compromettre la sécurité du système. Plus précisément, il peut être exploité pour contourner d'autres restrictions de sécurité, notamment celles imposées par seccomp, comme le démontrent des preuves de concept (PoC) comme celle-ci.
Exemple avec un binaire (python)
Exemple avec binaire (gdb)
gdb
avec la capacité ptrace
:
Créez un shellcode avec msfvenom pour l'injecter en mémoire via gdb