dimanche 11 janvier 2009

Commandes OpenSSL

J'ai toujours du mal à me rappeler de la syntaxe de certaines commandes openssl. Je fais donc un petit mémo pour me rappeler de certaines d'entre elles que j'utilise fréquemment. J'en rajouterai progressivement.

Commandes d'encodage


Pour encoder une suite d'octets avec openssl, il faut utiliser la commande enc. Il est possible par exemple d'encoder grâce à cette commande un texte en base64.

# Encodage du texte toto en base64
$ echo -n toto | openssl enc -base64
dG90bw==

# Decodage du texte dG90bw== encodé en base64
$ echo dG90bw== | openssl enc -base64 -d
toto

Il est à noter que pour le désencodage, openssl attend une chaîne de caratères terminée par un retour chariot. Il ne faut donc pas utiliser l'option -n de la commande echo (qui supprime ce caractère de fin). Si dans l'encodage par contre, on rajoute un retour chariot alors ce dernier sera aussi encodé par la commande.

Commandes de chiffrement asymétrique


Le chiffrement asymétrique est à la base des systèmes de PKI. La particularité de ces algorithmes est que la clef utilisée pour chiffrer le message n'est pas la même clef utilisée pour le déchiffer. Les exemples suivant utilisent l'algorithme RSA accessible via la commande rsautl de openssl.
# Chiffrement avec la clef publique RSA<
$ echo toto | openssl rsautl -encrypt -inkey private.pem
$ echo toto | openssl rsautl -encrypt -inkey public.pem -pubin
Ici le fichier private.pem contient le couple clef publique/clef privée. Le fichier public.pem ne contient que la clef publique. Ici seul la clef publique est utilisée dans le chiffrement (le déchiffrement se fera donc avec la clef privée). La sortie ici n'est pas affichée car rien ne dit qu'elle ne contient que des caractères imprimables. Il faudrait pour cela encoder cette sortie en base64 par exemple pour l'afficher.
# Déchiffrement avec la clef privée RSA
$ echo $to_decrypt | openssl rsautl -decrypt -inkey private.pem
La variable $to_decrypt contient ici le texte chiffré.

Commandes de chiffrement symétrique

Les algorithmes de chiffrement symétrique s'opposent aux algorithmes de chiffrement asymétrique car ils utilisent la même clef pour chiffrer et déchiffrer. La commande enc de openssl (qui permettait aussi l'encodage) permet ce type de chiffrement.
# Chiffrement en AES 256 mode CBC
$ echo toto | openssl enc -aes-256-cbc -K $SKEY -iv $IV -salt

# Dechiffrement en AES 256 mode CBC
$ echo $to_decode | openssl enc -aes-256-cbc -K $SKEY -iv $IV -d
La clef servant au chiffrement/déchiffrement se trouve dans la variable $KEY. Elle doit mesurer 32 octets (car AES 256 bits) et être codée en hexadécimal (donc 64 caractères). Le vecteur d'initialisation $IV utilisé dans ce mode de chiffrement doit faire 16 octets codé en hexadécimal (donc 32 caractères).

Commandes de calcul d'empreinte

Pour plus d'informations sur les fonctions permettant le calcul d'empreinte veuillez vous référer à cet autre billet que j'ai écrit. La commande openssl permettant le calcul d'empreinte s'appelle dgst. Les algorithmes disponibles dans openssl sont nombreux : MD4, MD5, SHA-1, RIPEMD160...
# Calcul d'une empreinte SHA-1
$ echo -n toto | openssl dgst -sha1
0b9c2625dc21ef05f6ad4ddf47c5f203837aa32c

# Calcul d'une empreinte MD5
$ echo -n toto | openssl dgst -md5
f71dbe52628a3f83a77ab494817525c6
La sortie de ces commandes est encodée en hexadécimal.

Commandes de génération de clefs asymétriques

La commande openssl pour générer des clefs asymétriques (RSA) est genrsa. La paire de clef générée peut ou non être chiffrée pour plus de protection.
# Génération d'un couple de clef de 2048 bits
$ openssl genrsa -out keys.pem 2048
Generating RSA private key, 2048 bit long modulus
.............................+++
.................+++
e is 65537 (0x10001)

# Génération d'un couple de clef de 4096 bits qui sera chiffré en triple DES
$ openssl genrsa -des3 -out keys.pem 4096
Generating RSA private key, 4096 bit long modulus
...........++
........................................................................................................................++
e is 65537 (0x10001)
Enter pass phrase for key:
Verifying - Enter pass phrase for key:
La pass phrase demandée servira au chiffrement de la paire de clef. A chaque utilisation de cette clef, cette pass phrase sera demandée. Le fichier résultat ici nommé keys.pem contient le couple de clef généré, c'est à dire la clef privée et la clef publique.

Extraction de la clé publique

Comme dit précédemment, lors de la génération de clés asymétriques, la clé publique et la clé privée sont contenues dans le même fichier. Pour extraire seulement la clé publique de ce fichier voilà la commande.
# Extraction de la clé publique du fichier contenant les deux clés
$ openssl rsa -in keys.pem -out public.pem -outform PEM -pubout
writing RSA key

Commandes relatives aux certificats

Openssl permet de faire toutes les opérations basiques que l'on peut effectuer sur des certificats : création de certificats auto signés, création d'une demande de certificat, signature d'un certificat...
# Création d'un certificat auto signé
$ openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095
Un certificat permet de certifier une clef publique. Cette clef est contenue dans le fichier nommé privkey.pem (contenant aussi la clef privée comme vu plus haut). Dans le cas d'un certificat autosigné, la clef privée sera utilisée pour signer le certificat. Dans notre exemple, le certificat sera valide pendant 1095 jours. Plusieurs autres informations seront demandée comme le pays relatif au certificat, l'état, la ville, l'entreprise, la section et surtout le common name.
# Création d'une demande de certificat
$ openssl req -new -key privkey.pem -out cert.csr
Le certificat obtenu ici n'est pas directement utilisable car il n'est pas signé. Il faudra donc le faire certifier par une autorité de certification de type Verisign, Thawte...

vendredi 9 janvier 2009

Fonctions de Hachage

Aujourd'hui alors que je lisais le document d'un collègue parlant de la nouvelle attaque permettant de faire un rogue CA à partir de la vulnérabilité du MD5, je réalise que j'ai de nombreuses lacunes sur les fonctions de hachage. Ce billet permet donc de faire une petite introduction sur ces fonctions.

Une fonction de hachage qu'est ce que c'est ? C'est une fonction qui prend en entrée une donnée et qui calcule son empreinte, un petit peu comme l'empreinte digitale d'un doigt. Cette empreinte est une suite d'information caractéristique de la donnée initiale.

Les fonctions de hachage sont à sens unique, ce qui veut dire qu'à partir de l'empreinte, il est impossible de revenir aux données initiales. En d'autres termes, si x représente les données et f() une fonction de hachage, alors il n'existe pas de fonction f-¹() permettant à partir de f(x) de revenir x.

Ceci est assez simple à comprendre. Supposons que notre fonction f() ait comme sortie une empreinte de 128 bits (donc 2¹²⁸ empreintes différentes). Si on calcule f(x) pour x allant de 0 à 2¹²⁸ (donc 2¹²⁸+1 valeurs différentes), il y aura au minimum deux f(x) identiques pour deux x différents.

L'autre particularité importante de la fonction de hachage et qu'il est très difficile de trouver une valeur y qui a comme caractéristique que f(y) = f(x) pour x différent de y. Dans le cas idéal, il faudrait brute forcer la valeur de y (c'est à dire tester en moyenne 2¹²⁸/2=2¹²⁷ possibilités) pour trouver un f(y) = f(x) pour un x donné. Le "pour un x donné" est très important car si x n'est pas fixé, d'après le paradoxe des anniversaires, trouver n'importe quel couple x,y tel que f(x) = f(y) ne revient à faire "que" 2⁶⁴ opérations (racine carré de 2¹²⁸).

Ok tout ça c'est bien beau mais à quoi servent ces fonctions ? Ces fonctions sont très utilisées en informatique et particulièrement en sécurité. Les algorithmes MD5, SHA... sont des fonctions de hachages.
On trouve souvent le résultat de ces fonctions à coté de fichier que l'on veut télécharger par exemple. Ce résultat permet de s'assurer que le fichier en notre possession est bien conforme. Il suffit de calculer le md5 du fichier que l'on possède. Si les md5 sont les mêmes, on a bien la même version (et on ne possède pas a priori une version vérolée, excepté bien entendu si le pirate a pu modifier le site web et le md5 affiché).
Une autre utilité est par exemple l'utilisation pour stocker des mots de passe. On ne stocke plus le mot de passe, mais le hash du mot de passe. De cette façon si un pirate s'empare du fichier (ou accède à la base de données), il ne s'empare plus du mot de passe, mais seulement de son hash (et comme il est impossible de remonter aux données initiales...). La vérification de ce dernier se faisant du coup en comparant le hash de la chaîne fournie avec la valeur stockée.
Enfin un autre exemple d'utilité est la signature numérique. Quand quelqu'un vous envoie un fichier, il calcule l'empreinte de ce fichier et chiffre cette dernière avec sa clef privé. A la réception, il ne vous reste plus qu'à déchiffrer la signature grâce à la clef publique de l'émetteur et à la comparer avec l'empreinte du fichier. Si c'est la même, alors vous êtes sûrs que le fichier envoyé n'a pas été modifié par une tierce personne, car seul l'émetteur a pu chiffrer l'empreinte (seul détenteur de la clef privé).

Maintenant que se passe-t'il quand la fonction de hachage n'est pas idéale ? On ne peut bien entendu toujours pas remonter aux données pour les raisons évoquées précédemment, mais par contre la difficulté pour trouver un y tel que f(y) = f(x) peut être réduite. C'est ce qui s'est produit pour le md5, puis plus tard pour SHA-1 qui réduit la complexité pour trouver une collision de 2⁸⁰ itérations (car le SHA-1 produit une sortie de 160 bits) à 2⁶⁹ en Février 2005, puis de nouvelles recherches ont prouvé qu'il était encore possible de faire mieux.

Jusqu'à présent les failles découvertes permettaient de simplifier le calcul pour trouver un couple x,y tel que f(x) = f(y). Chose intéressante bien entendu, mais beaucoup moins que trouver un y tel que f(y) = f(x) pour un x donné. Cela reste un premier pas vers le cassage total de l'algorithme.

Aujourd'hui les recherches en cryptanalyse sur le MD5 montrent qu'il est possible de trouver un y tel que f(y) = f(x) avec seulement une partie de x fixée. Alors vous allez dire que ca casse pas trois pattes à un canard quand il s'agit du mot de passe. Dans ce cas là c'est vrai qu'une bonne atttaque par dictionnaire (ou par rainbow tables) sera toujours plus intéressante, mais dans certains cas cela peut avoir des conséquences beaucoup plus génantes.

mercredi 7 janvier 2009

Attaque ChopChop

Premier article que j'écris en rapport avec la norme 802.11 plus connue sous le nom de WiFi. Pour bien comprendre cet article il est conseillé d'avoir déjà des connaissances sur le fonctionnement du protocole WEP (Wired Equivalent Privacy). Je vais parler d'une attaque relativement connue qui s'appelle l'attaque ChopChop qui a déjà fait ses preuves notamment contre le protocole WEP et qui depuis peu a été utilisé pour mettre en évidence les faiblesses du protocole TKIP (Temporal Key Integrity Protocol). Ce billet est le premier d'une série qui a pour objectif justement d'expliquer cette faille dans TKIP.

Historique


En 2004, alors que le WEP est déjà cassé depuis officiellement 2001, Korek publie la première version d'un outil appelé chopchop qui permet de décrypter n'importe quel paquet chiffré sans connaître la clef[1] WEP. Un nouveau coup dur pour le WEP qui n'en n'avait vraiment pas besoin. Ce n'était ni le premier et encore moins le dernier. Cette attaque probablement moins connue que les attaques FMS ou encore PTW (car elle ne permet pas de trouver la clef WEP) revient sur le devant de la scène grâce à la présentation de Erik Tews faite à la PacSec sur les faiblesses du protocole TKIP.

Fonctionnement de l'attaque


Pour commencer un tout petit rappel sur le fonctionnement du WEP s'impose. Très grossièrement chaque paquet est constitué de deux parties : les données et le CRC32[2] qui permet d'assurer l'intégrité de ces données. Le tout est ensuite envoyé à l'algorithme de chiffrement WEP c'est à dire RC4 : le paquet chiffré envoyé sur le réseau est le résultat du xor entre la concaténation du message et de son CRC32 et le keystream qui est fonction de la clef WEP et du vecteur d'initialisation courant. Si D est le message en clair, ICV l'opération de CRC32 (Integrity Check Value), C le message chiffré, K la clef WEP, IV le vecteur d'initialisation courant et || l'opérateur de concaténation alors ce que je viens d'écrire peut se résumer de cette façon :

C = RC4(IV || K) xor (D || ICV(D))

Ici tout ce qui est en vert est connu par une personne qui n'a pas la clef et qui écoute le réseau et tout ce qui est en rouge est inconnu.

Le CRC32 a à la base était écrit pour assurer l'intégrité des données et en aucun cas pour assurer leur sécurité. L'attaque ChopChop va donc utiliser plusieurs faiblesses de cet algorithme pour injecter des données sur le réseau.

Si l'on souhaite injecter des données dans le réseau à partir d'un paquet chiffré capturé alors nous avons les relations suivantes :

C = RC4(IV || K) xor (D || ICV(D)) est le paquet capturé.

D' représente les données que l'on va injecter dans le réseau tel que : D' = D xor Mod

Nous avons donc :

C' = RC4(IV || K) xor (D' || ICV(D'))

Ici comme nous ne connaissons pas D, nous ne connaissons pas non plus D'.

D' || ICV(D') = (D || ICV(D)) xor (Mod || ICV'(Mod)) ou ICV' est un CRC32 modifié

donc

C' = RC4(IV || K) xor (D || ICV(D)) xor (Mod || ICV'(Mod))

C' = C xor (Mod || ICV'(Mod))

Cette relation montre qu'à partir d'un paquet chiffré valide, il est possible d'injecter n'importe quelle modification de ce paquet. C' qui était inconnu est en définitif seulement fonction d'élément connu.

L'attaque ChopChop utilise une autre vulnérabilité du CRC32. Si le message C est tronqué de son dernier octet de données, le message devient donc invalide car le CRC32 ne correspond plus. Cependant si on xor C avec une certaine valeur Mod, alors le paquet redevient valide. Une démonstration mathématique[3] montre que Mod ne dépend que de la valeur en clair de l'octet tronqué.

On peut donc écrire que Mod = f(X) où X est la valeur en clair de l'octet tronqué.

L'attaque coule maintenant de source. Etant donnée qu'il y a 256 valeurs possibles pour X, il suffit de toutes les tester.

On prend donc notre paquet capturé C, on lui enlève le dernier octet de données. On prend comme hypothèse que la valeur non chiffrée X de cet octet tronqué est 0 et on génère notre modification :

C' = C xor f(x) avec x=0

On envoie C' et si C' est rejoué par l'Access Point alors c'est que notre paquet C' était valide, donc notre hypothèse sur X était bonne. On vient donc de trouver un octet en clair de C (donc un octet de D), et donc un octet du keystream utilisé pour chiffrer cet octet. Si le paquet C' n'est pas rejoué par l'Access Point, alors c'est que notre paquet C' n'est pas valide, donc notre hypothèse sur X était fausse. On retente en incrémentant X, jusqu'à que le paquet C' soit rejoué. En moyenne il faudra donc envoyer 128 paquets pour décrypter un octet.

La suite est évidente, on réitère la même méthode pour trouver tous les octets de D, donc octet par octet.

Outils Implémentant l'attaque


Le premier outil implémentant cette attaque est bien entendu la preuve de concept de Korek.

Le deuxième outil est aireplay-ng de la très célèbre suite aircrack-ng. N'hésitez pas à vos référer à cette page pour la mise en oeuvre de chopchop avec aireplay.

Liens


Voilà une liste de liens qui m'ont permis d'écrire cet article, n'hésitez pas à me corriger si vous avez trouvé des erreurs !

chopchop (Experimental WEP attacks)
Thread initial de Korek sur la preuve de concept. Le contenu du fichier zip que l'on peut avoir directement ici contient plein d'informations très utiles, notamment le fichier DOC.

ChopChop Theory
L'explication de l'attaque faite par le site aircrack-ng

Byte-Sized Decryption of WEP with Chopchop, Part 1
Byte-Sized Decryption of WEP with Chopchop, Part 2
Explications supplémentaires sur le fonctionnement de l'attaque.

Fameuses faiblesses de tkip
Pourquoi c'est pourri le wep part-2
L'explication du fonctionnement de ChopChop sur le blog de Cédric Blancher qui est une mine d'informations sur la sécurité des réseaux WiFi entre autres.

Notes


[1] C'est ici un pléonasme ! Décrypter veut dire trouver le texte en clair à partir du texte chiffré sans la clef.
[2] Le CRC32 comme son nom l'indique fait 32 bits, soit 4 octets.
[3] Cette démonstration mathématique se trouve dans le fichier DOC de la preuve de concept de Korek chopchop-0.1.zip.

vendredi 5 décembre 2008

Droits sur un système de fichier Linux

Dans ce billet je vais vous parler des différents droits qui peuvent être gérés sur un système de fichier Linux. Je vais commencer par faire un rappel sur les droits basiques que tout le monde connaît (lecture, écriture, exécution) qui s'appliquent sur les fichiers et répertoires, puis sur les droits moins communs comme par exemple le setuid bit. Je ne parlerai pas ici d'ACL (Access Control List) qui feront sûrement l'objet d'un futur billet.

Un droit c'est quoi ?

Un droit c'est une information supplémentaire associée à un fichier ou un répertoire qui va permettre de dire qui a la permission d'effectuer ou non certaines actions. Sur un système de fichier Unix, chaque fichier en plus son contenu, possède des informations qui lui sont propres comme son nom, sa taille, son propriétaire... et ses droits d'accès. Toutes ces informations sont décrites dans la norme POSIX. Tout système de fichier qui se veut conforme à cette norme doit donc impérativement posséder ce type d'information.
Les systèmes de fichiers conformes à cette norme sont par exemple : ext2, ext3, reseirfs, xfs... Le système de fichier FAT (système de fichier encore utilisé couramment avec Windows) par exemple n'est pas conforme à la norme POSIX.

Droits : les bases

Les droits sur les systèmes Linux sont relatifs à 3 classes d'utilisateurs :
  • L'utilisateur propriétaire du fichier ou du répertoire qui est appelé u pour user
  • Le groupe propriétaire du fichier ou du répertoire qui est appelé g pour group
  • Tout utilisateur qui n'appartient pas aux deux premières catégories qui est appelé o pour other.

Pour chacune de ces trois classes, il existe trois droits possibles (en réalité un peu plus comme nous le verrons par la suite) :
  • Le droit de lecture appelé r pour read
  • Le droit d'écriture appelé w pour write
  • Le droit d'exécution appelé x pour exécution

Il est possible d'afficher ces droits grâce à la commande ls suivie de l'option -l :
$ ls -l /bin/bash
-rwxr-xr-x 1 root root 678832 Dec 7 2007 bash

Comme on peut le voir dans cet exemple, le fichier bash appartient à l'utilisateur root (premier root affiché par la commande), au groupe root (deuxième root affiché par la commande) et possède les droits en lecture/écriture/exécution pour son propriétaire (rwx), les droits en lecture/exécution pour son groupe propriétaire (premier r-x) et les droits en lecture/exécution pour les autres utilisateurs (deuxième r-x).

Impact de chaque droit

C'est bien joli d'avoir des droits sur des fichiers et des répertoires mais encore faut il précisément savoir à quoi cela peut bien servir.

Droit en lecture
Le droit en lecture noté r est très facile à comprendre. Pour un fichier il permet d'autoriser ou non la lecture du fichier et pour un répertoire la possibilité de lister son contenu.
Même si nous n'avons pas les droits en lecture sur un répertoire il nous est tout à fait possible d'accéder aux fichiers ou répertoires contenus à l'intérieur (si bien entendu les droits sur ces fichiers/répertoires nous le permettent). En revanche, il faut absolument connaître leur nom (ou le deviner en brute force par exemple mais ceci est un autre sujet).
$ id
uid=1001(time0ut) gid=1001(time0ut) groupes=1001(time0ut)
$ ls -l
total 1
drwx--x--x 1 root root 4096 Dec 1 directory_not_readable
$ ls directory_not_readable
ls: cannot open directory_not_readable: Permission denied
$ cat directory_not_readable/file_readable
Je peux lire le contenu !

Droit en écriture
Le droit en écriture noté w permet pour un fichier et pour un répertoire d'autoriser ou non la modification de leur contenu. Il est important ici de bien comprendre ce que l'on entend par modification de contenu d'un répertoire. La présence ainsi que le nom d'un fichier dans un répertoire fait parti du contenu du répertoire et non du contenu du fichier. Ce qui implique les éléments suivants :
  • On peut modifier le nom d'un fichier si on a les droits en écriture sur le répertoire sur lequel il est contenu, même si nous n'avons pas les droits en écriture sur ce fichier. Inversement, nous ne pouvons pas modifier le nom d'un fichier sur lequel nous avons les droits en écriture, si nous ne possédons pas les droits d'écriture sur le répertoire.
  • On peut supprimer un fichier si on a les droits en écriture sur le répertoire sur lequel il est contenu, même si nous n'avons pas les droits en écriture sur le fichier. Inversement, il ne sera pas possible de supprimer un fichier sur lequel nous avons les droits en écriture, si nous n'avons pas les droits en écriture sur le répertoire. Tout au plus nous pourrons vider le fichier, mais nous ne pourrons pas le supprimer.

$ id
uid=1001(time0ut) gid=1001(time0ut) groupes=1001(time0ut)
$ ls -l
total 1
drwxrwxrwx 1 root root 4096 Dec 1 directory_writable
$ ls -l directory_writable
total 1
-rwxr-xr-x 1 root root 5 Dec 1 file_not_writable
$ echo "Je vais pas pouvoir ecrire !!!" >> directory_writable/file_not_writable
directory_writable/file_not_writable: Permission denied
$ rm directory_writable/file_not_writable
$ ls -l directory_writable
total 0

Comme on peut le voir dans cet exemple, nous avons les droits en écriture sur directory_writable mais pas sur le fichier contenu dans ce répertoire. Il nous est donc impossible de modifier le contenu de ce fichier, mais rien ne nous empêche de le supprimer. Par la suite il sera alors possible de le recréer avec un contenu différent (on a donc réussi à éviter la protection du fichier). Attention donc quand vous configurez les droits d'accès à ne pas oublier de placer les bons droits sur les répertoires.

Droit en exécution
Le droit en exécution sur un fichier permet comme son nom l'indique d'autoriser ou non l'exécution de ce fichier. Le droit en exécution sur un répertoire permet d'autoriser ou non l'accès au répertoire. Sans les droits en exécution il est donc impossible de se placer à l'intérieur d'un répertoire ou de le traverser pour aller dans sa sous arborescence. Il est tout à fait possible d'autoriser le droit en exécution sur un répertoire sans autoriser le droit en lecture, on pourra donc se placer dans ce répertoire, le traverser mais pas lister son contenu. Le droit d'exécution n'est pas nécessaire pour lister le contenu d'un répertoire (même si la commande ls bien qu'elle affiche le résultat fasse une erreur).
$ id
uid=1001(time0ut) gid=1001(time0ut) groupes=1001(time0ut)
$ ls -l
total 1
drwxr-xr-- 1 root root 4096 Dec 1 directory_readable
$ cd directory_readable
cd: directory_readable: Permission denied
$ ls directory_readable
ls: cannot access directory_readable: Permission denied
file
$ for i in directory_readable/*; do echo $i; done
directory_readable/file

Droits Avancés

La grande majorité des personnes qui ont déjà utilisé deux ou trois fois une machine Linux connaissent les droits que je viens de décrire. Le problème de ces droits est qu'ils sont trop simplistes et que bien souvent dans certains cas on se trouve dans l'incapacité de faire précisément ce que l'on souhaite. Pour cela il existe des droits supplémentaires assez particulier que je vais décrire ici.

Setuid bit

Dans un système Unix quand un utilisateur x exécute un programme, ce dernier possède les droits de l'utilisateur x. Par exemple quand l'utilisateur time0ut exécute le programme bashce dernier aura les droits de l'utilisateur time0ut. Jusque là tout est normal.

Comment faire quand on vient d'écrire un programme qui nécessite de faire une minuscule tâche qui a besoin de droits que ne devraient pas avoir l'utilisateur qui utilisera ce programme ? Doit on lui donner l'ensemble des droits pour effectuer cette minuscule tâche ? Bien sûr que non ! Alors comment faire ? La solution est le setuid bit.

Ce bit quand il est positionné sur un programme qui a les droits en exécution a pour conséquence que le programme n'aura plus les droits de l'utilisateur qui a lancé le programme (uid), mais les droits du propriétaire du programme (euid). Si on reprend l'exemple du programme bash, si ce dernier avait le setuid bit activé et que notre utilisateur time0ut l'exécute alors bash aurait les droits du propriétaire du programme c'est à dire les droits du root.

On voit ici le danger que le setuid bit peut engendrer. Le simple fait de positionner ce bit sur un programme comme bash donnerait l'ensemble des droits à tous les utilisateurs du système. Toute application possédant le setuid bit est donc relativement critique car la moindre vulnérabilité trouvée dans cette application peut entraîner une élévation de privilège. Dans la mesure du possible il est donc très important d'éviter le recours à cette configuration.

Le programme ping que tout le monde connaît possède habituellement le setuid bit. Il nécessite les droits du root pour forger les paquets ICMP. Sans ce setuid bit, il ne serait pas possible à un utilisateur non root d'utiliser cette commande. Un autre exemple de programme est passwd.

Le setuid bit sur un répertoire est ignoré par le système Linux (les systèmes BSD peuvent l'interpréter d'une façon similaire au setgid bit qui sera développé plus tard).

$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 32988 Nov 13 07:54 /usr/bin/passwd

Remarques
Il ne sert à rien de mettre un setuid bit sur un script (shell, perl, python...) car ce dernier est interprété.
Le setuid bit (tout comme le setgid bit) peut aussi apparaître avec un S majuscule. Dans ce cas cela veut dire que le fichier ne possède pas le droit en exécution. Si c'est un s minuscule comme dans l'exemple ci dessus, le fichier possède le droit en exécution. Le setuid sans le droit en exécution n'a à priori aucune caractéristique particulière et est donc ignoré (j'ai lu je ne sais plus où que certains Unix le setuid bit sur un fichier n'ayant pas les droits en exécution pouvait permettre de lock pour éviter les accès multiples notamment avec des systèmes de fichier réseau comme NFS).
Si vous souhaitez avoir plus d'information sur la gestion du setuid bit et que les termes de uid et effective uid ne vous sont pas étrangers, n'hésitez pas à jeter un coup d'oeil à ce lien qui décrit la gestion de ce cas.

Setgid bit

Le setgid bit suit le même principe que le setuid bit. Lorsqu'un programme possédant ce droit est exécuté, il ne possède plus les droits du groupe de l'utilisateur qui l'a appelé mais les droits du groupe auquel appartient le programme. Ce droit n'a pas de sens sur un fichier ne possédant pas les droits en exécution pour le groupe.

Par contre lorsque ce droit est appliqué à un répertoire il signifie que chaque fichier et répertoire créé à l'intérieur possédera le même groupe que le répertoire et non pas le groupe de l'utilisateur qui a créé le fichier/répertoire, comme c'est le cas par défaut. De plus chaque répertoire créé possèdera en plus le droit setgid qu'il héritera de son parent.
$ id
uid=1001(time0ut) gid=1001(time0ut) groupes=1001(time0ut)
$ ls -l
drwxr-xr-x 1 time0ut time0ut_group 4096 2008-12-02 22:18 directory_without_sgid
drwxr-sr-x 1 time0ut time0ut_group 4096 2008-12-02 22:18 directory_with_sgid
$ touch directory_without_sgid/file
$ ls -l directory_without_sgid/file
-rw-r--r-- 1 time0ut time0ut 0 2008-12-02 22:18 directory_without_sgid/file
$ touch directory_with_sgid/file
$ mkdir directory_with_sgid/directory
$ ls -l directory_with_sgid
drwxr-sr-x 2 time0ut time0ut_group 4096 2008-12-02 22:23 directory
-rw-r--r-- 1 time0ut time0ut_group    0 2008-12-02 22:18 file

Comme on peut le voir dans l'exemple ci-dessus qui illustre mes précédents propos, le fichier créé dans le répertoire sans setgid possède le groupe de l'utilisateur qui a créé le fichier, alors que le fichier créé dans le répertoire avec setgid possède le même groupe que le groupe du répertoire. On peut remarquer aussi le droit setgid activé par défaut sur le répertoire créé.

Sticky bit

Le dernier droit que l'on verra dans ce billet est le sticky bit qui apparaît en lieu et place du droit en exécution pour la classe d'utilisateur other sous forme d'un t ou d'un T. Comme pour le setuid et le setgid la majuscule signifie que le droit en exécution n'est pas positionné alors que la minuscule signifie qu'il l'est.

Le sticky bit sur un fichier n'est plus utilisé dans la majorité des systèmes Unix et ne l'a même jamais été sur Linux. Le positionnement de ce bit permettait à un exécutable d'avoir son code placé directement en swap quand celui ci n'est pas utilisé. De cette façon le lancement du programme se fait plus rapidement. Il était souvent positionné sur les programmes utilisés fréquemment comme les éditeurs de texte.

Le sticky bit positionné sur les répertoires est par contre toujours utilisé de nos jours sur le répertoire /tmp par exemple.
$ ls -ld /tmp
drwxrwxrwt 8 root root 4096 Nov 6 /tmp

Comme je l'ai dit précédemment avoir les droits en écriture sur un répertoire nous permet de modifier le contenu de ce répertoire (ajout de fichier, suppression de fichier, modification du nom de fichier...). Cela veut dire qu'il serait possible de supprimer n'importe quel fichier du répertoire /tmp, même ceux qui ne nous appartiennent pas. Le sticky bit est utilisé pour éviter cela. Quand le sticky bit est positionné sur un répertoire, seul le possesseur du répertoire, le possesseur du fichier et l'utilisateur root peuvent renommer ou supprimer ce fichier, même si le droit en écriture est positionné sur ce répertoire.

Quelques commandes utiles

Je finis ce billet par quelques commandes se rapportant aux droits ou au propriétaire/groupe propriétaire sur les fichiers et répertoires.

Modification du propriétaire/groupe propriétaire

La commande chown permet de changer le propriétaire d'un fichier et la commande chgrp permet de changer le groupe propriétaire d'un fichier. Je vous renvoie aux man de ces commandes pour de plus amples informations.

chown [OPTION] user[:group] file
chgrp [OPTION] group file

Il est possible de changer le user ET le groupe avec la commande chown d'un fichier ou d'un répertoire. Les deux commandes acceptent l'option -R qui permet d'appliquer la modification à toute une sous arborescence ce qui peut s'avérer très utile.

Modification des droits

La modification des droits sur les fichiers se fait avec la commande chmod. Cette commande permet de configurer les droits de plusieurs façons différentes. Il est possible de le faire avec une notation symbolique que j'ai développée avant ou avec une notation octale.

chmod [OPTION] permissions file

La notation littérale prend la forme de : classe_d'utilisateur opérateur permission.

classe_d'utilisateur peut être égal à u pour le propriétaire, g pour le groupe, o pour les autres et a pour tout le monde.

operateur peut être égal à + pour ajouter des droits, - pour les enlever ou = pour mettre des droits stricts.

permission peut être égal à r pour lecture, w pour écriture, x pour exécution, s pour le setuid/setgid bit et t pour le sctiky bit.

Voilà quelques exemples de commandes :

# Suppression du droit en écriture pour toutes les classes d'utilisateur
chmod a-w file

# Ajout du droit en exécution pour le propriétaire
chmod u+x file

# Ajout du droit en lecture pour le groupe et suppression de ce même droit pour other
chmod g+r,o-r file

# Positionnement des droits lecture/écriture pour le propriétaire, du droit de lecture pour le groupe et suppression de tous les droits pour other
chmod u=rw, g=r, o= file

La notation octale ne permet pas d'enlever des droits ou d'en ajouter. Elle permet juste de mettre des droits stricts. Le fonctionnement est décrit dans le tableau suivant.
Classe user Classe group Classe other
Classe d'utilisateur u g o
Droits rwx rw- r--
Binaire 111 110 100
Octal 7 (1x2^2 + 1x2^1 + 1x2^0) 6 (1x2^2 + 1x2^1 + 0x2^0) 4 (1x2^2 + 0x2^1 + 0x2^0)

$ ls -l
total 0
-rwxrwxrwx 1 time0ut time0ut 0 2008-12-02 23:47 file
$ chmod 750 file
$ ls -l file
-rwxr-x--- 1 time0ut time0ut 0 2008-12-02 23:47 file

Si l'on souhaite mettre les droits spéciaux, il suffit de rajouter un chiffre au début : 1 pour le sticky bit, 2 pour le setgid bit et 4 pour le setuid bit (les combinaisons sont possibles).

$ ls -l file
-rwxr-x--- 1 time0ut time0ut 0 2008-12-02 23:47 file
$ chmod 1750 file
$ ls -l file
-rwxr-x--T 1 time0ut time0ut 0 2008-12-02 23:47 file
$ chmod 5750 file
$ ls -l file
-rwsr-x--T 1 time0ut time0ut 0 2008-12-02 23:47 file
$ chmod 6750 file
$ ls -l file
-rwsr-s--- 1 time0ut time0ut 0 2008-12-02 23:47 file


Droits par défaut lors de la création d'un fichier/répertoire

Lorsqu'un fichier est créé sur le disque il a des droits par défaut qui sont fonctions d'un masque. Les droits qui en résultent sont le résultat de l'opération suivante : droits_demandés & !masque. La modification du masque se fait grâce à la commande umask.

Si l'on souhaite enlever par défaut les droits en écriture/exécution pour le groupe et tous les droits pour les autres donc aboutir à des droits du style rwxr----- qui en binaire se traduit par 111 100 000. Il suffit de prendre l'inverse en binaire, donc 000 011 111 qui se traduit en octal par 037.

$ umask
0000
$ touch file1
$ ls -l
total 0
-rw-rw-rw- 1 time0ut time0ut 0 2008-12-02 23:43 file1
$ umask 037
$ touch file2
$ ls -l
total 0
-rw-rw-rw- 1 time0ut time0ut 0 2008-12-02 23:43 file1
-rw-r----- 1 time0ut time0ut 0 2008-12-02 23:43 file2

Ici le droit en exécution n'est pas mis tout simplement car la commande touch ne le positionne pas. Comme on peut le voir il est aussi possible de spécifier des droits spéciaux.


Recherche de fichiers en fonction de leurs droits

Voilà quelques commandes qui peuvent être très utiles lors de l'audit d'un système Unix par exemple. Elles sont basées sur la commande find associé à l'option -perm.

L'option -perm en fonction de comment est marqué les permissions qui suivent ne se comporte pas de la même façon. Si les permissions qui suivent ne sont précédées d'aucun opérateur alors cela signifie que l'on cherchera l'ensemble des fichiers/répertoires possédant exactement les droits demandés. Ces droits pouvant être précisés en octal ou en symbolique.

Si l'opérateur - précède les droits, alors find cherchera les fichiers/répertoires possédant tous les droits précisés (le fichier peut en avoir plus, il faut juste qu'il ait les droits demandés par l'option).

Si l'opérateur / précède les droits, alors find cherchera les fichiers/répertoires possédant au moins un de ces droits.

Voilà quelques exemples de commandes de recherche utile :
# Recherche des répertoires possédant les droits en écriture pour tout le monde
find / -type d -perm -o=w -print
find / -type d -perm -002 -print

# Même chose avec les fichiers
find / -type f -perm -o=w -print
find / -type f -perm -002 -print

# Recherche de fichiers possédant le setuid bit ou le setgidbit
find / -type f -perm /u=s,g=s -print
find / -type f -perm /6000 -print

Pour plus d'informations sur la commande find reportez vous à son manuel (man find).

Ce billet se termine. Il sera certainement suivi dans le futur par d'autres sur des sujets proches comme par exemple les ACL ou sur les attributs que l'on peut mettre sur les fichiers/répertoires sur le système de fichier ext2/3 (lsattr, chattr...).

samedi 29 novembre 2008

C'est parti !

Voilà je me lance !


Moi aussi je tombe dans la tendance du blog à mon plus grand étonnement.
Je me retrouve confronté à un gros problème : la mémoire ! Je n'ai aucune mémoire et du coup à chaque fois que j'ai un problème en informatique ou que je fais quelques recherches pour satisfaire ma curiosité je réalise que j'oublie très rapidement les informations que j'ai trouvées. Alors ces derniers temps j'écris toutes ces informations dans des fichiers textes et un collègue m'a suggéré de faire partager ces informations avec les internautes.
L'idée ne m'avait pas vraiment traversé la tête, mais dans le fond c'est vraiment pas si bête que ça. Premièrement ça me permettra d'avoir un avis extérieur (qui est toujours bon à prendre) et deuxièmement ça m'obligera à structurer un peu mes idées et à bien les présenter.
Ce blog ne se présente donc pas comme une bible exempte d'erreurs sur les sujets que je vais traiter, mais beaucoup plus comme les résultats de problèmes auxquels je suis confronté, ou de résumé sur les sujets qui m'intéressent.

Les sujets qui seront abordés dans ce blog seront à priori très orientés sécurité informatique, système (plus particulièrement Unix) et réseau. Rien ne dit que par moment je ne parlerai pas d'autres choses, mais dans l'absolu ce blog tournera autour de ces trois sujets qui me passionnent. 

En espérant que mes sujets vous intéressent et qui sait peut être vous apprendrez deux ou trois trucs qui vous serviront par la suite !

Bienvenue !