Skip to content

Linux Attitude

Le libre est un état d'esprit

Archive

Tag: Système

Niveau :      
Résumé : syslog | openssl dgst

Vous êtes vous déjà posé la question de la sécurisation de vos logs ? Sont-ils accessibles ? modifiables ? Peut-on détecter une falsification ?

Comment faire pour que les logs ne soient pas altérés par une personne de peu de principes ? Je vous propose une solution qui n'est pas une solution miracle, mais c'est une solution qui sera une brique de plus dans votre défense en profondeur.

Nous allons signer cryptographiquement les logs pour que tout altération devienne visible comme le nez au milieu de la figure.

Signature et validation des logs

Je vous au préparé pour cela deux programmes (lien en fin d'article), l'un pour signer les logs, l'autre pour les valider. Bien sûr, on ne va pas signer les fichiers de logs directement, ça laisserait tout le temps à un attaquant de les modifier avant la signature. Nous allons plutôt nous insérer dans le système syslog pour disposer des lignes au fur et à mesure. Mais nous n'allons pas non plus signer toutes les lignes, ce serait trop lourd. Nous allons plutôt signer des blocs de lignes, par exemple une signature toutes les 100 lignes, sans oublier un timeout pour éviter que 99 lignes restent en mémoire trop longtemps..

Enfin une des fonctionnalités importante de ces outil est le chaînage. Le chaînage est le fait d'utiliser la signature du bloc précédent comme faisant partie du bloc suivant. Ceci garanti qu'il ne peut y avoir suppression ou ajout d'un bloc eu milieu d'une chaîne de blocs. Et tant qu'on y est nous pouvons aussi chaîner les fichiers pour obtenir le même résultat au niveau fichier.

Au final toute modification, ajout ou suppression de ligne entraine l'invalidation de la signature. Toute modification, ajout ou suppression de bloc ou de fichier de log entraine l'invalidation de la signature.

Voici donc un exemple d'usage sous forme de pipe :

$ openssl genrsa -out key.pem 1024 # il nous fait une clé de signature
$ echo "Log important" | signlogger -k key.pem -f logfile

Notez que c'est utilisable avec syslog puisque celui-ci vous permet d'utiliser un pipe à la place d'un fichier. Je ne détaille pas cela ici car cela dépend du sylog que vous utilisez (syslogd, syslog-ng, rsyslog ...).

Et pour vérifier que votre fichier de log n'a pas été modifié ?

$ openssl rsa -in key.pem -pubout > pubkey.pem # on récupère la version publique de la clé
$ signvalidator -k pubkey.pem -f logfile

Si vous voulez utilisez cet outil avant logger ou avant l'envoi à un serveur centralisé, il faudra modifier signvalidator pour qu'il ignore les éléments ajoutés par syslog dans la vérification de la signature (date, pid, ...).

Usage

Dans la vraie vie quand on parle de sécurité, il faut se demander de quoi on veut se prémunir.

Signer les logs a pour but d'éviter qu'on puisse modifier les logs a posteriori, puisqu'on n'empêche personne de transformer les logs avant qu'ils ne soient envoyés à syslog. Mais toute personne qui a accès en écriture aux logs a posteriori, a les mêmes droits que le processus qui écrit les logs. Il a donc accès au système de signature.

Mais alors qu'a-t-on gagné ?

Tout d'abord, un difficulté légèrement accrue pour un attaquant, c'est pas grand chose, mais ça peut toujours servir. Ensuite, il nous suffit maintenant de séparer les droits du système de chiffrement de ceux du système d'écriture pour enfin détecter la modification par une personne possédant les droits d'écriture.

Pour cela vous avez plusieurs moyens à votre disposition :

  • utiliser des pipes et des des utilisateurs séparés pour la signature et pour l'écriture
  • utiliser l'attribut append only des fichiers de log pour interdire toute modification du fichier a posteriori (sauf par root qui peut retirer l'attribut)
  • utiliser un medium read only pour écrire les logs
  • utiliser un HSM pour interdire la réutilisation de la clé
  • déporter les logs vers un serveur syslog

Ou toute combinaison de ceux-ci.

Vous remarquerez que ces techniques ont déjà pour but d'empêcher la modification des logs a posteriori. La signature n'apporte qu'une preuve supplémentaire.

Mais prenez l'exemple du serveur syslog centralisé. On ne peut plus modifier les logs depuis le client, mais on le peut toujours depuis le serveur. La signature, si elle est effectuée côté client permet d'apporter une garantie supplémentaire puisqu'il faut cette fois un accès coté client ET côté serveur pour effecture la modification.

Si on y ajoute l'append only, il faut être root, si on y ajoute le HSM, il faut disposer d'une carte à puce ou d'un mot de passe, si on y ajoute un media read only, il faut disposer d'un accès physique pour le modifier. Et chacun de ces éléments peut être géré par une personne différente pour rendre impossible toute modification par une unique personne malintentionnée.

A vous de choisir votre niveau de sécurité !

En détail

Je vous colle ici l'usage complet des commandes (c'est du perl pour ceux qui veulent savoir)

$ signlogger --help
Usage:
    signlogger [options]

      Options
            --key|-k keyfile         Use private key for signing (PEM encoded)
            --file|-f file           Log to file instead of stdout
            --lastsig|-l line        Use line as last signature (used for chaining)
            --initfile|-i file       Use last line of file as last signature (used for chaining)
            --blocksize|-b lines     Insert signature each "lines" count (default 50)
            --timestamp|-t seconds   Insert signature each "seconds" seconds (default 30mn)
            --help|-h                This help

$ signvalidator --help
Usage:
    signvalidator [options]

      Options
            --key|-k keyfile        Use public key for validation (PEM encoded)
            --file|-f file          Read file instead of stdin
            --lastsig|-l line       Use line as last signature (used for chaining)
            --initfile|-i file      Use last line of file as last signature (used for chaining)
            --help|-h               This help

Et pour les télécharger :

Niveau :      
Résumé : debsums ; dpkg -S ; apt-get install --reinstall

Si vous avez bidouillé une debian en installant un logiciel sans passer par dpkg par exemple, ou si quelqu'un vous a fait une mauvaise blague et qu'il y a des problèmes dans les logiciels installés, alors il y a un moyen pour vérifier si le problème vient d'un fichier modifié :

$ apt-get install debsums
$ debsums -c

Debsums est un outil debian qui fait un hash de tous les fichiers installés par des paquets debian et le compare au hash provenant du paquet original. L'option -c permet de lister tous les fichiers qui posent problème. Cela ne vous prémunit pas des attaquants qui pourraient aussi modifier la base des paquets, mais c'est utile pour toute manipulation plus ou moins volontaire du système.

Une fois la liste des fichiers modifiés récupérée, il nous reste à trouver dans quel paquet se trouvait le fichier en question :

$ dpkg -S /bin/ls # nous indique que ls est dans le paquet coreutils

Et maintenant passons à l'étape réparation :

# retélécharge et réinstalle tous les binaires d'un paquet déjà installé
$ apt-get install --reinstall lepaquet

Et pour ceux qui voudraient faire une réinstallation complète de leur distribution :

$ dpkg --get-selections | grep install | awk '{print $1}' | xargs  apt-get install --reinstall --yes

Mais comme dit le commentaire ci-dessous cela ne marche que si vous ne faite pas de pinning et si votre distribution est à jour. La commande suivante permet de ne pas changer les versions des paquets :

$ dpkg -l | grep ^ii | awk ‘{print $2″="$3}’ | xargs apt-get install -reinstall -s -t release-cible

Niveau :      
Résumé : atime, ctime, mtime, crtime

Je constate que je n'ai jamais fait d'article sur les dates de fichier, c'est bien dommage car on me pose souvent la question. Voila qui va régler ce malentendu.

ctime et mtime

Unix depuis très longtemps ne stocke pas la date de création d'un fichier (contrairement à windows). A la place il stocke 3 dates au format timestamp unix. Les plus difficiles à comprendre sont mtime et ctime. Mais en réalité c'est simple, il suffit d'apprendre leur nom :

  • mtime : modification time, date de dwœernière modification du contenu du fichier
  • ctime : change time, date de dernier changement des métadonnées du fichier (par exemple le propriétaire)

Rien que pour vous, j'ai un moyen antimnémotechnique : M comme Contenu et C comme Métadonnée. Je ne sais pas vous, mais moi ça marche.

Attention, la modification du contenu d'un fichier modifie sa date de modification, qui est une métadonnée ... Elle modifie donc aussi sa date de changement. En conséquence de quoi on a toujours ctime >= mtime.

atime

Historiquement unix a eu l'idée originale de stocker la date de dernier accès à un fichier, le atime (access time). Ça a l'air cool, mais en réalité c'est une fausse bonne idée car elle interfère avec la notion fondamentale de lecture. En effet, pour mettre à jour le atime, chaque lecture impliquera une écriture.

Plus le temps passe plus le atime est problématique. Ça a commencé avec les sites web qui avaient des problèmes de performance à cause de la mise à jour du atime lors de la lecture des fichiers. On a alors inventé la possibilité de désactiver le atime au montage (option noatime).

Puis ça continue avec le SSD, écrire le atime implique une écriture toute petite à chaque lecture de fichier, ce qui implique la modification d'un inode et donc d'un block disque. Et avec le fonctionnement du SSD cela implique la lecture et la réécriture d'un gros bloc de données, donc des problèmes de performances. Puisque le atime reste utilisé par quelques applications (aussi rares soient-elles), on a inventé l'option relatime, qui ne met a jour le atime que s'il était égal ou antérieur au ctime. Ça permet de détecter une lecture depuis la dernière modification tout en faisant sauter un grand nombre de mises à jour du atime (mais pas toutes).

Le problème suivant intervient avec les snapshots, lorsqu'on utilise des snapshots de disques (à travers LVM ou à travers un serveur de VM), on se retrouve à mettre à jour le disque de snapshot et donc occuper de l'espace disque rien qu'en le lisant. Le summum étant atteint avec btrfs. Si vous faites un snapshot avec btrfs il ne vous prendra quasiment aucune place sur le disque. Si vous faites un find sur ce snapshot, la mise à jour du atime va quasiment remplir l'espace disque du snapshot d'une copie complète des données originales.

Conclusion, oubliez le atime ...

crtime

Comme je vous l'ai dit, windows stocke la date de création, c'est donc tout naturellement que les linuxiens ont voulu la même fonctionnalité. C'est enfin chose faite avec ext4. En effet, ext4 a profité de l'agrandissement de la taille des inode (de 128 à 256) pour stocker plus d'informations, celles-ci incluent la date à la nanoseconde près et la date de création.

Cool, mais comment fait-on ?

Malheureusement, les outils habituels n'ont pas encore été mis à jour pour récupérer cette information. Il nous faut donc le faire à la main :

# d'abord on récupère le numéro d'inode du fichier
$ stat --format "%i" /chemin/vers/le/fichier
# puis on récupère la date de création
$ debugfs -R 'stat <123456>' /dev/partition | grep crtime

Notez que ça ne marche que sur des partitions ayant des inodes de 256 octets, ce qui exclue les systèmes de fichiers mis à jour depuis ext2 et ceux venant d'un ext3 avec des inodes de 128 octets.

Niveau :      
Résumé : /etc/inittab ; /etc/gdm.conf ; /etc/sshd.conf

Pour ceux qui voudraient essayer le parachutisme, je vous le conseille, c'est très fort ! Par contre ça vous empêche d'écrire des articles ...

Vous venez de faire un chroot et vous voulez pouvoir vous connecter dessus comme s'il s'agissait de votre machine locale ?
Pas de panique, c'est tout simple.

Pour cela nous allons regarder 3 méthodes différentes de connexion à votre chroot : le terminal local, ssh et l'environnement graphique. Mais avant tout préparons le chroot à ressembler à une distribution normale.

$ mount --bind /dev $CHROOT_BASE/dev
$ mount --bind /proc $CHROOT_BASE/proc
$ mount --bind /sys $CHROOT_BASE/sys

Terminal local

Pour se connecter en local à votre machine, vous utilisez les consoles disponibles (alt-Fx ou ctrl-alt-Fx si vous êtes en mode graphique). Vous en avez 6 à disposition.

Pour faire simple, nous allons juste faire en sorte que les consoles 4 à 6 redirigent dans le chroot tandis que les 1 à 3 resteront dédiées à la machine principale.

Il suffit de modifier /etc/inittab :

# /etc/inittab
1:2345:respawn:/sbin/getty tty1
2:2345:respawn:/sbin/getty tty2
3:2345:respawn:/sbin/getty tty3
4:2345:respawn:chroot <chroot_base> /sbin/getty tty4
5:2345:respawn:chroot </chroot_base><chroot_base> /sbin/getty tty5
6:2345:respawn:chroot </chroot_base><chroot_base> /sbin/getty tty6

Et là, soit vous redémarrez (bof on n'est pas sous windows) soit vous forcez init à relire sa configuration :


continue reading...

Correction  : j'ai modifié cet article car le système pour rendre le rootage permanent ne fonctionnait pas !

Niveau :      
Résumé : adb shell

Il y a peu je me suis offert un téléphone android. Devinez quoi ... c'est un linux (pas GNU pour une fois, plutôt un dalvik/linux).

Seule ombre au programme, je ne suis pas root dessus. C'est pas très fair play de la part du vendeur sachant que le téléphone m'appartient. Comment faire pour supprimer les applications installées par le fabriquant et qui me cassent les *** à se lancer sans me demander mon avis ?

Ma première mission est donc de devenir root.

Les habitués des OS de bureau auront l'idée de toucher au bootloader pendant qu'il boote. Bonne idée, mais sur une telle machine le bootloader est assez sobre, et plutôt protégé, ne parlons pas du bios. J'ai donc ignoré cette technique pour passer à une méthode plus courantes pour les bidouilleurs de tout poil : exploiter une faille de sécurité.

C'est donc grâce aux failles de sécurité que je vais avoir le droit d'accéder au système de ma propre machine ! Autrement dit, c'est parce que le fabriquant protège mal le système qu'il m'a vendu que mes droits de consommateur sont respectés ...


continue reading...

Niveau :      
Résumé : /proc/sys/fs/binfmt_misc/register

Exécution

Savez-vous qu'on peut rendre n'importe quel fichier exécutable sous linux ? Bien sûr il suffit de faire un chmod +x, mais le noyau risque de vous envoyer balader si le fichier n'est pas réellement exécutable.

Mais je parle ici de rendre exécutable n'importe quel fichier, un jar, un source en C, un MP3 ...

Mais comment quoi que donc !?

Pour exécuter un fichier, le noyau lit les premiers octets du fichier et vérifie qu'ils correspondent à un format binaire (binfmt) connu. Il existe un système pour ajouter des formats binaires à ceux déjà supportés dans le noyau (en gros les elf et les scripts). Il s'agit du format misc.

Pour savoir si ce format est supporté chez vous, ce qui est très probable, lancez la commande :

$ cat /proc/sys/fs/binfmt_misc/status

S'il n'est pas supporté, il faut charger le module et monter le répertoire :

$ modprobe binfmt_misc
$ mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc 

continue reading...

Niveau :      
Résumé : zdump ; zic

Le temps est absolu

Le temps est quelque chose de sensible. Si mon serveur est en retard il va croire que la personne qui vient de s'authentifier sur mon site essaie de me flouer en me donnant une date invalide. S'il est en avance, il va croire qu'il n'est pas venu depuis longtemps et va le déconnecter.

Il est donc important d'être toujours à l'heure, car l'heure c'est l'heure et quand il est pas encore l'heure c'est pas l'heure et s'il n'est plus l'heure ce n'est toujours pas l'heure. Vous me suivez ?

Mais pour une fois je ne vais pas vous parler de l'heure selon NTP, mais l'heure selon Saint Matthieu, enfin presque.

Supposons que, grâce à votre professionnalisme, votre machine soit à l'heure, voire à la seconde, grâce à NTP. Supposons que vous vouliez connaitre cette heure. Que faites-vous ? Vous la demandez au noyau (via time ou gettimeofday), et il vous la donne en UTC ...

Mais en pratique vous voulez l'heure de chez vous, celle qui dit que le soleil va se coucher dans la belle province. Bien sûr la libc va faire la conversion pour vous (via localtime, mais voyons comment elle fait.

Enfin presque

La date et l'heure s'expriment de plusieurs façons. L'heure UTC est la version "absolue"', c'est à dire qu'elle ne dépend pas des différentes régions de la planète où l'on se place. Mais tous les pays ne l'entendent pas de cette oreille et veulent chacun définir leur heure. Définition qui peut changer dans le temps ...

Pour faire la conversion, il faut donc connaître toutes ces règles. Heureusement des acharnés on fait ce travail de récupération et les ont déposées dans /usr/share/timezone sur le système de fichier.

Vous croyez qu'il n'y à que 24 fuseaux horaires ? Faux il y en a un peu plus. Maintenant comptons les timezone :

$ find /usr/share/zoneinfo/ -type f | wc -l
1764

Imaginez le temps qu'il a fallu pour compiler ces données ...

Vous constaterez que ce sont des fichiers binaires. La libc les lit directement (pour en savoir un peu plus, man tzfile et man tzset), mais pour nous humains ? On utilise zdump

$ zdump -v Europe/Paris

Vous y verrez les changements d'heure une seconde avant et une seconde après chaque changement. Remarquez qu'il y a plus d'information dans le binaire que dans le dump qui ne fait qu'afficher les dates de saut temporel.

Pas du tout

Mais aujourd'hui est un grand jour, je vais faire ma propre nation (une de plus). J'y édicterai un nouvel horaire, UTC+1,25 et heure d'été en UTC +0,75. Le changement se fera à MON anniversaire.

Il faut donc que je crée un fichier de zone correspondant à mon pays. Prenons le source suivant :

# règles de changement d'heure
Rule peck 2010 max odd Mar 6 4:00 -0:30 -
Rule peck 2010 max odd Sep 6 4:00 0 -
# définition de l'heure standard dans la zone
Zone peck 1:15 peck PCK

Et on le compile avec zic :

# notez que j'ai récupéré yearistype dans le source de tzdata
# il permet l'usage de odd dans mon fichier de règles
$ /usr/sbin/zic -d . -y "sh yearistype.sh" peck

Il suffit maintenant de le déposer dans /usr/share/timezone et voilà ce qu'on peut obtenir :

$ TZ=peck LC_TIME=C date
Mon Mar  7 17:48:02 PCK 2011
# notez la différence (UTC+x et PCK)
$ TZ=peck LC_TIME=fr_FR date
lundi 7 mars 2011, 17:48:37 (UTC+0045)

Votre timezone perso !

Pour des exemples complets et complexes de zones, vous pouvez regarder le source du paquet tzdata. C'est votre référence, mais je doute que vous ayez à y toucher prochainement !