2016-10-05 09:13:56 +00:00
|
|
|
|
\newpage
|
|
|
|
|
|
2017-10-23 20:25:51 +00:00
|
|
|
|
Les *capabilities*
|
2021-10-05 15:23:09 +00:00
|
|
|
|
------------------
|
2016-10-05 09:13:56 +00:00
|
|
|
|
|
2017-10-23 20:25:51 +00:00
|
|
|
|
Historiquement, dans la tradition UNIX, on distinguait deux catégories de
|
2021-10-05 15:23:09 +00:00
|
|
|
|
processus :
|
2016-10-05 09:13:56 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
* les processus *privilégiés* : dont l'identifiant numérique de son utilisateur
|
|
|
|
|
est 0 ;
|
|
|
|
|
* les processus *non-privilégiés* : dont l'identifiant numérique de son
|
2019-10-22 16:03:09 +00:00
|
|
|
|
utilisateur n'est pas 0.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
|
|
|
|
Lors des différents tests de permission fait par le noyau, les processus
|
|
|
|
|
privilégiés outrepassaient ces tests, tandis que les autres devaient passer les
|
|
|
|
|
tests de l'effective UID, effective GID, et autres groupes supplémentaires...
|
|
|
|
|
|
|
|
|
|
Depuis Linux 2.2 (en 1998), les processus privilégiés peuvent activer ou
|
|
|
|
|
désactiver des *capabilities*, chacune donnant accès à un groupe d'actions
|
|
|
|
|
privilégiées au sein du noyau.
|
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
On trouve par exemple :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
* `CAP_CHOWN` : permet de modifier le propriétaire d'un fichier de manière
|
|
|
|
|
arbitraire ;
|
|
|
|
|
* `CAP_KILL` : permet de tuer n'importe quel processus ;
|
|
|
|
|
* `CAP_SYS_BOOT` : permet d'arrêter ou de redémarrer la machine ;
|
|
|
|
|
* `CAP_SYS_MODULE` : permet de charger et décharger des modules ;
|
|
|
|
|
* et beaucoup d'autres, il y en a environ 41 en tout (ça dépend de la
|
|
|
|
|
version du noyau) !
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### `ping`
|
|
|
|
|
|
|
|
|
|
Pour émettre un ping, il est nécessaire d'envoyer des paquets ICMP. À la
|
2021-10-05 15:23:09 +00:00
|
|
|
|
différence des datagrammes UDP ou des segments TCP, il n'est pas forcément
|
|
|
|
|
simple d'envoyer des paquets ICMP lorsque l'on est simple utilisateur, car
|
2022-02-24 19:43:43 +00:00
|
|
|
|
l'usage du protocole ICMP dans une soket est restreint : il faut soit être
|
2021-10-05 15:23:09 +00:00
|
|
|
|
super-utilisateur, soit que le noyau ait été configuré pour autoriser certains
|
|
|
|
|
utilisateurs à envoyer des `ECHO_REQUEST`.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
|
|
|
|
Pour permettre à tous les utilisateurs de pouvoir envoyer des ping, le
|
2017-10-22 22:14:32 +00:00
|
|
|
|
programme est donc généralement *Setuid root*. Cela permet à n'importe quel
|
2016-10-05 20:49:08 +00:00
|
|
|
|
utilisateur de prendre les droits du super-utilisateur, le temps de l'exécution
|
|
|
|
|
du programme.
|
|
|
|
|
|
|
|
|
|
Les problèmes surviennent lorsque l'on découvre des vulnérabilités dans les
|
2017-10-22 22:14:32 +00:00
|
|
|
|
programmes *Setuid root*. En effet, s'il devient possible pour un utilisateur
|
2016-10-05 20:49:08 +00:00
|
|
|
|
d'exécuter du code arbitraire, ce code sera exécuté avec les privilèges de
|
2021-10-05 15:23:09 +00:00
|
|
|
|
l'utilisateur *root* ! Dans le cas de `ping`, on se retrouverait alors à
|
2017-10-22 22:14:32 +00:00
|
|
|
|
pouvoir lire l'intégralité de la mémoire, alors que l'on avait juste besoin
|
|
|
|
|
d'écrire sur une interface réseau.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
C'est donc à ce moment que les *capabilities* entrent en jeu : un processus (ou
|
2016-10-06 01:58:52 +00:00
|
|
|
|
même un thread) privilégié peut décider, généralement à son lancement, de
|
|
|
|
|
réduire ses *capabilities*, pour ne garder que celles dont il a réellement
|
|
|
|
|
besoin. Ainsi, `ping` pourrait se contenter de `CAP_NET_RAW`.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
::::: {.warning}
|
|
|
|
|
Bien que ce paramètre existe [depuis
|
|
|
|
|
2011](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=c319b4d76b9e583a5d88d6bf190e079c4e43213d),
|
|
|
|
|
ce n'est que [depuis 2020](https://github.com/systemd/systemd/pull/13141) que les distributions comme Fedora et Ubuntu
|
|
|
|
|
se mettent à fournir par défaut une configuration qui permette de se passer de
|
|
|
|
|
*capabilities* pour lancer `ping`.\
|
|
|
|
|
|
|
|
|
|
Si vous vous rendez compte que votre binaire `ping` est dans ce cas, testez
|
2022-02-24 19:43:43 +00:00
|
|
|
|
depuis un conteneur, par exemple :
|
2021-10-05 15:23:09 +00:00
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```
|
|
|
|
|
42sh$ docker run -it --rm alpine
|
|
|
|
|
|
|
|
|
|
(ctnr)# apk add --no-cache acl iputils
|
|
|
|
|
(1/4) Installing libacl (2.2.53-r0)
|
|
|
|
|
(2/4) Installing acl (2.2.53-r0)
|
|
|
|
|
(3/4) Installing libcap (2.50-r0)
|
|
|
|
|
(4/4) Installing iputils (20210202-r0)
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
(ctnr)# su -s/bin/ash daemon
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
(ctnr)$ _
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Dans le conteneur le binaire `ping` est *setuid root*, vous pouvez faire des
|
2022-02-24 19:43:43 +00:00
|
|
|
|
tests en retirant le *setuid* :
|
2021-10-05 15:23:09 +00:00
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```
|
|
|
|
|
(ctnr)# chmod u-s /bin/ping
|
|
|
|
|
|
|
|
|
|
(ctnr)$ ping epita.fr
|
|
|
|
|
ping: socket: Operation not permitted
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Puis en ajoutant la *capability* :
|
2021-10-05 15:23:09 +00:00
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```
|
|
|
|
|
(ctnr)# setcap cap_net_raw+p /bin/ping
|
|
|
|
|
|
|
|
|
|
(ctnr)$ ping epita.fr
|
|
|
|
|
PING epita.fr (172.67.156.141) 56(84) bytes of data.
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Vous vous retrouverez dans le scénario attendu, tout en pouvant agir sur le
|
|
|
|
|
binaire `ping` sans avoir peur de casser votre distribution.
|
|
|
|
|
:::::
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Les attributs de fichier étendus
|
|
|
|
|
|
|
|
|
|
Une grosse majorité des systèmes de fichiers (ext[234], XFS, btrfs, ...)
|
2017-10-23 20:25:51 +00:00
|
|
|
|
permet d'enregistrer, pour chaque fichier, des attributs (dits attributs
|
2016-10-05 20:49:08 +00:00
|
|
|
|
*étendus*, par opposition aux attributs *réguliers* qui sont réservés à l'usage
|
|
|
|
|
du système de fichiers).
|
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Sous Linux, les attributs sont regroupés dans des espaces de noms :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
* *security* : espace utilisé par les modules de sécurité du noyau, tel que
|
|
|
|
|
SELinux, ... ;
|
|
|
|
|
* *system* : espace utilisé par le noyau pour stocker des objets système, tels
|
|
|
|
|
que les ACL POSIX ;
|
2016-10-05 20:49:08 +00:00
|
|
|
|
* *trusted*: espace dont la lecture et l'écriture est limité au
|
2021-10-05 15:23:09 +00:00
|
|
|
|
super-utilisateur ;
|
|
|
|
|
* *user* : modifiable sans restriction, à partir du moment où l'on est le
|
2016-10-05 20:49:08 +00:00
|
|
|
|
propriétaire du fichier.
|
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Par exemple, on peut définir un attribut sur un fichier comme cela :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```bash
|
|
|
|
|
42sh$ echo 'Hello World!' > toto
|
|
|
|
|
42sh$ setfattr -n user.foo -v bar toto
|
|
|
|
|
42sh$ getfattr -d toto
|
|
|
|
|
# file: toto
|
|
|
|
|
user.foo="bar"
|
2016-10-05 20:49:08 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
En tant que simple utilisateur, vous ne pouvez pas modifier des attributs en
|
|
|
|
|
dehors de l'espace *user*. Par contre, en *root*, vous pouvez définir et
|
|
|
|
|
changer les ACL POSIX :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```bash
|
|
|
|
|
42sh$ sudo chown root:root toto && sudo chmod o-r toto
|
|
|
|
|
42sh$ cat toto
|
|
|
|
|
cat: toto: Permission denied
|
2021-10-05 15:23:09 +00:00
|
|
|
|
42sh$ sudo setfacl -m u:$USER:r toto
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh$ cat toto
|
|
|
|
|
Hello World!
|
2016-10-05 20:49:08 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2016-10-06 01:58:52 +00:00
|
|
|
|
Bien que les droits UNIX traditionnels ne vous donnent pas accès au fichier,
|
|
|
|
|
les ACL POSIX vous autorisent à le lire.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Vous pouvez voir ces attributs bruts avec la commande :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```bash
|
|
|
|
|
42sh$ getfattr -d -m "^system" toto
|
|
|
|
|
# file: toto
|
|
|
|
|
system.posix_acl_access=0sgAAEAD/////AgAEOgDAEAA/////xAABAD////8=
|
2016-10-05 20:49:08 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Il s'agit d'une représentation d'une structure du noyau, pas forcément très
|
|
|
|
|
lisible en l'état. On utilisera `getfacl` pour la version lisible.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
|
|
|
|
|
#### `ping`\
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2017-10-23 20:25:51 +00:00
|
|
|
|
De la même manière que l'on peut définir de façon plus fine les droits d'accès
|
|
|
|
|
par utilisateur, un attribut de l'espace de nom *security* peut être défini
|
|
|
|
|
pour accroître les *capabilities* d'un processus lorsqu'il est lancé par un
|
2021-10-05 15:23:09 +00:00
|
|
|
|
utilisateur non-privilégié. On peut voir le *setuid root* comme l'utilisation
|
|
|
|
|
de cet attribut, qui accroîtrait l'ensemble des *capabilities*.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Si votre distribution profite de ces attributs étendus, vous devriez obtenir :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```bash
|
|
|
|
|
42sh$ getfattr -d -m "^security" $(which ping)
|
|
|
|
|
# file: bin/ping
|
|
|
|
|
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=
|
2016-10-05 20:49:08 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Comme pour les ACL POSIX, une structure du noyau est enregistrée comme attribut
|
|
|
|
|
du fichier ; et on peut l'afficher dans sa version plus lisible :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```bash
|
|
|
|
|
42sh$ getcap $(which ping)
|
|
|
|
|
/bin/ping = cap_net_raw+ep
|
2016-10-05 20:49:08 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-05 09:13:56 +00:00
|
|
|
|
|
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
### Exercice : visualisateur de capabilities d'un processus {-}
|
2016-10-05 09:13:56 +00:00
|
|
|
|
|
2016-10-06 01:58:52 +00:00
|
|
|
|
Écrivons maintenant un programme permettant de voir les *capabilities*
|
2021-10-05 15:23:09 +00:00
|
|
|
|
d'un processus :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```
|
|
|
|
|
42sh$ ./view_caps 1
|
|
|
|
|
cap_user_header_t
|
|
|
|
|
-----------------
|
|
|
|
|
Version: 20080522
|
|
|
|
|
PID: 1
|
|
|
|
|
|
|
|
|
|
cap_user_data_t
|
|
|
|
|
---------------
|
|
|
|
|
effective: 0x3fffffffff
|
|
|
|
|
CAP_AUDIT_CONTROL
|
|
|
|
|
CAP_AUDIT_READ
|
|
|
|
|
[...]
|
|
|
|
|
CAP_SYS_TIME
|
|
|
|
|
CAP_SYS_TTY_CONFIG
|
|
|
|
|
CAP_SYSLOG
|
|
|
|
|
CAP_WAKE_ALARM
|
|
|
|
|
permitted: 0x3fffffffff
|
|
|
|
|
CAP_AUDIT_CONTROL
|
|
|
|
|
CAP_AUDIT_READ
|
|
|
|
|
[...]
|
|
|
|
|
CAP_SYS_TIME
|
|
|
|
|
CAP_SYS_TTY_CONFIG
|
|
|
|
|
CAP_SYSLOG
|
|
|
|
|
CAP_WAKE_ALARM
|
|
|
|
|
inheritable: 0x0
|
2016-10-05 09:13:56 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Appelé sans argument, `view_caps` affichera les capabilities du processus
|
|
|
|
|
courant.
|
|
|
|
|
|
|
|
|
|
Astuces : `capget(2)`, X-macros, ...
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
### Pour aller plus loin {-}
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Je vous recommande la lecture des *man* suivants :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
* `capabilities(7)` : énumérant tous les capabilities, leur utilisation, etc. ;
|
|
|
|
|
* `xattrs(7)` : à propos des attributs étendus.
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Et de ces quelques articles :
|
2016-10-05 20:49:08 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
* [Linux Capabilities: Why They Exist and How They Work](https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work)
|
2016-10-06 01:58:52 +00:00
|
|
|
|
* [Guidelines for extended attributes](https://www.freedesktop.org/wiki/CommonExtendedAttributes/)
|
|
|
|
|
* [File-based capabilities](https://lwn.net/Articles/211883/)
|
|
|
|
|
* [A bid to resurrect Linux capabilities](https://lwn.net/Articles/199004/)
|
2021-09-11 12:41:43 +00:00
|
|
|
|
* [False Boundaries and Arbitrary Code Execution](https://forums.grsecurity.net/viewtopic.php?f=7&t=2522#p10271)
|
2021-11-19 23:00:30 +00:00
|
|
|
|
* [Linux Capabilities on HackTricks](https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities)
|
2016-10-06 01:58:52 +00:00
|
|
|
|
|
2021-10-05 15:23:09 +00:00
|
|
|
|
Pour revenir à Docker, un certain nombre de *capabilities* sont désactivées par
|
|
|
|
|
défaut ; vous pouvez en ajouter et en retirer via les arguments `--cap-add` et
|
|
|
|
|
`--cap-drop` du `docker container run`.
|