Vue lecture

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
✇I Learned

Syncthing, la synchronisation de fichiers dopée aux stéroïdes

Qui a déjà utilisé différents ordinateurs sait la complexité que représente la synchronisation de fichiers entre de ceux-ci. Cet article traite justement de la question, via un logiciel, Syncthing, qui permet de régler ce souci de façon assez magique 🪄.

🧱 Architecture des systèmes de synchronisation

Il existe principalement deux architectures permettant la synchronisation des fichiers que je vais vous décrire.

➡️ Client/Serveur

C'est l'architecture la plus classique, proposée par de gros acteurs du secteur comme Google, Dropbox, Apple ou encore Nextcloud. Le principe est relativement simple, tous les fichiers sont uploadés vers un serveur chez l'opérateur de cloud. Lorsque l'on utilise un autre appareil, les changements sont téléchargés des serveurs de cet opérateur.

Un schéma montrant un exemple d'architecture client/serveur

C'est le modèle le plus répandu pour une raison, c'est le plus simple à mettre en place, et ça l'était encore plus il y a quelques années. Cependant, depuis, un autre modèle devient de plus en plus commun.

🕸️ Mesh

Cet autre modèle, ce sont les réseaux maillés, ou mesh. Plutôt que de s'appuyer sur un serveur central, qui peut se retrouver inopérant à n'importe quel moment, on utilise tous les appareils à la fois comme serveur et comme client. Cela permet à cette topologie d'être beaucoup plus résiliente.

Une schéma montrant un exemple d'architecture mesh

On peut voir sur ce schéma que même si l'ordinateur principal n'est pas en capacité d'accéder à certains appareils directement (parce que ceux-ci n'ont pas accès à internet par exemple) cela ne pose aucun problème car, chacun d'entre eux étant interconnecté. Les modifications finissent par être propagées partout.

On a aussi un autre avantage de taille, si deux appareils sont sur le même réseau local, ils n'auront pas à passer par Internet. Ce qui permet d'accélérer grandement la vitesse de mise à jour entre les appareils.

C'est ce modèle qu'utilise Syncthing, le logiciel dont nous allons traiter ici.

📦 Syncthing

Syncthing est un logiciel libre créé en 2013, il est activement supporté, compte quelque 80 000 utilisateurs, et a depuis sa création, permit de transférer 4,785 Po (4 785 000 Go) ! Il s'appuie sur un protocole appelé BEP (Block Exchange Protocol) que je vais tâcher de vous décrire ici.

BEP est un protocole qui s'appuie sur une structure de données assez simple, chaque appareil (device) a une liste de dossiers (folder). Ces dossiers sont découpés en plus petits blocs entre 16 Ko et 2 Mo. Syncthing stocke le hash de chacun de ces blocs, et échange cette liste de hash avec les autres appareils afin de savoir si la version d'un dossier stocké est à jour.

Un exemple de dossier découpé en blocs

Si le hash d'un des blocs n'est pas le même, l'appareil va alors synchroniser ce bloc avec l'autre appareil ayant la version plus récente.

Il existe trois modes d'échanges entre les appareils, send only, receive only, et send & receive. Le premier est particulièrement utile sur un ordinateur qui voudrait envoyer des sauvegardes vers un serveur par exemple, l'ordinateur ne veut pas recevoir de fichier du serveur, juste en envoyer. À l'inverse, dans ce cas, le serveur serait en receive only. Le mode send & receive est tout particulièrement utile pour synchroniser, par exemple, le dossier ~/Documents entre deux ordinateurs, permettant à l'un et l'autre d'effectuer des modifications sur un document et d'être toujours synchronisé.

Toute l'ingéniosité de Syncthing repose dans son optimisation, le protocole principalement utilisé pour le transfert de fichier est Quic, un parfait compromis entre la robustesse de tcp et la vitesse d'udp. Syncthing optimise aussi grandement le transfert en lui-même, en permettant par exemple de ne pas retransférer certaines données si elles sont déjà présentes dans d'autres fichiers. Par exemple, si je veux synchroniser mon ~/Dev, et que j'ai dedans plusieurs projets en JS, plutôt que de télécharger le dossier node_modules à chaque nouveau projet créé sur une machine distante, le logiciel va copier les fichiers déjà existant sur le disque pour des bibliothèques qui auraient déjà été téléchargées par exemple.

Ces optimisations permettent un gain de bande passante assez incroyable. D'après les statistiques de Syncthing récoltées sur l'ensemble des appareils ayant autorisé la télémétrie, la réutilisation des données d'autres fichiers aurait permis d'économiser 8 % de bande passante !

Totals to date Transferred    34.62 PiB (38.72%) Saved by renaming files  2.1 PiB (2.35%) Saved by resuming transfer  4.29 PiB (4.80%) Saved by reusing data from old file    40.23 PiB (45.00%) Saved by reusing shifted data from old file  827.11 TiB (0.90%) Saved by reusing data from other file    7.36 PiB (8.23%)

Cet article touche à sa fin, j'espère que vous en savez maintenant un peu plus sur Syncthing, pour finir j'aimerais vous donner une dernière astuce. Si vous comptez utiliser Syncthing entre deux ordinateurs que nous n'utilisez pas en même temps (ex. un ordinateur portable pour les cours et un fixe chez soi) je ne pourrais que vous conseiller de mettre Syncthing sur un NAS, un VPS ou même un simple Raspberry Pi fera l'affaire, cela permettra de synchroniser les fichiers même si un des deux ordinateurs n'est pas allumé. Merci d'avoir suivi cet article ! 😄

✇I Learned

Comment fonctionne la compilation de programme

Dans cet article je vais vous parler de la compilation d'un programme informatique, quelles sont ses "phases" et leurs utilité, et tout ce qui se cache derrière tout ça.

Initialement cet article devait traiter de la compilation, de l'interprétation et de la semi interprétation, mais il y'a tellement de chose à dire que vous parler de tout ce bon monde dans un seul est unique article serait un enfer pour vous, alors j'ai décidé de faire un article pour chacun de ces sujets.

La Compilation

Alors, premièrement qu'est ce que c'est la compilation ?

La compilation permet, en bref, de transformer/traduire le code source d'un programme en langage machine pour qu'il puisse être exécuté par votre processeur.

Pourquoi ne pas directement progammer en langage machine alors ?

Je pense que vous êtes des êtres humains (sinon faudrait complètement revoir nos statistiques sur le blog). Le langages machine, comme son nom l'indique, c'est du langage pour la machine, et vous en ête pas une ... ~~en tout cas pas encore~~ il vous faut donc une alternative au langage machine pour nous, un langage qui se rapproche du language humain pour que ce soit plus simple de lire et/ou écrire du code.

Le premier language créé pour "humaniser" le langage machine, c'est le langage d'assemblage ou plus couramment dit: "language d'assembleur". Voici un exemple du fameux "Hello world !" en language d'assembleur sous Linux 64bits

bits 64
global main

section .data
Hello db "Hello world !", 10, 0

section .text

main:
    push rbp
    mov rbp, rsp
    mov rax, 1 ; syscall write
    mov rdi, 1 ; stdout
    mov rsi, Hello
    mov rdx, 15 ; size of "Hello world!\n" + nullbyte
    syscall
    leave

Je ne vais pas vous expliquer qui fait quoi dans ce code, les commentaires reste assez explicite et de toute façon ce n'est pas l'objet de cet article.

Et le language machine correspondant (de la section main) ressemble à ceci:

55                          
48 89 e5            
b8 01 00 00 00      
bf 01 00 00 00      
48 be 28 40 40 00 00
ba 0f 00 00 00      
0f 05                
c9

Vous voyez c'est le jour et la nuit, même si le language d'assemblage reste assez austere, ca reste humainement plus lisible que du language machine.

Languages moderne

Heureusement aujourd'hui les languages de programmation ont changé notamment grace à la venue du language B dont le language C s'est inspiré et qui a ensuite inspiré quasiment tout les autres languages suivant celui-ci. Si vous jettez un oeil aux langages précédant le langage B ; Fortran, Cobol, vous remarquez qu'ils restent plus ou moins similaires au language d'assembleur.

Exemple de "Hello world !" en C:

#include <stdio.h>

int main() {
    printf("Hello world !");

    return 0;
}

C'est tout de suite plus agréable que le language d'assembleur !

Les étapes de la compilation

Bon, maintenant que vous avez compris que c'était plus drôle d'écrire avec un language autre que le language machine, je vais vous parler des différentes phases de la compilation.

Les 3 plus grosses phases (les plus souvents présentées dans les schémas) sont:

  • La phase préprocesseurs
  • La compilation
  • L'édition de liens

Ce sont les plus grosses étapes, mais il y'en a d'autres.. pleins d'autres qui se passent avant, pendant et après ces 3 là.

Le prétraitement

Cette phase permet de substituer des macros dans le code. Prenons les exemples suivants

#include <stdio.h> #define TOTO 42

Lors de cette phase, tout le contenu du fichier stdio.h est inséré dans le fichier source.

Tous les TOTO sont remplacés par 42.

Il existe aussi des préprocesseurs "conditionnels" (if, else, ...) qui sont souvent utilisés, par exemple lorsque le programme est en developpement on peut écrire des macros qui permettent d'ajouter du code pour faciliter le débug du programme, mais lors de la publication de la version "finale" du programme, on peut ommetre certains codes pour ne pas surcharger le code source avec du code en plus.

Exemple:

#if DEBUG
    assert(var == false)
    assert(var2 > var3)

    printf("Tout est correct");
#endif

Si lors de la compilation on spécifie la macro DEBUG le code au dessus sera pris en compte dans le code source.

Mais si on ne spécifie pas cette macro, la phase de prétraitement passera outre ce code la.

L'analyse lexicale

Et oui, très souvent oublié dans les petits schémas récapitulatifs, il y'a une analyse lexicale. Elle est réalisée en parcourant le code source en une seul fois.

Cette phase permet de verifier si les mots existent dans le language et à quel unité de lexique ils appartiennent puis les "découpes" de sorte à former des "token".

Unité de lexique

  • identifiants: une_variable, une_fonction, x, etc...
  • mots-clefs: if, while, return, for, extern, auto, static, etc...
  • ponctuation: }, (, ;
  • opérateurs: +, <, =, <=, ==, etc...
  • littéraux 42, 69.0f, "hello", 0xb00b

Une fois l'analyse lexicale faites les "tokens" sont générés. Par exemple, prenont le code suivant:

int ma_variable = 32 + 8 + 2;

On se retrouve avec les tokens suivant:

int : mot-clef du type entier ma_variable : identifiant = : opérateur d'affectation 32 : entier littéral + : opérateur d'addition 8 : entier littéral + : opérateur d'addition 2 : entier littéral ; : fin de l'initialisation

Dans l'analyse lexicale il se passe encore plein d'autre chose comme le "balayage" et "L'évaluation" mais qui sont justes des étapes intermédiaires pour arriver à l'objectif de l'analyse léxicale.

En conclusion, l'analyseur lexical vérifie si les mots existent bien et les transforme en token pour l'analyseur syntaxique.

Par exemple en language Francais: Loubala n'est pas correcte, ce mot n'existe pas dans la langue Française.

L'analyse syntaxique

L'analyse syntaxique suit directement l'analyse lexicale et permet de vérifier si les mots/groupes de mots forment des "phrases" conforme du language en analysant les tokens générer par l'analyse lexicale.

Si on reprend l'exemple avec le Francais: Manger boire. Cette suite de mot est lexicalment correct, ces mots existent dans la langue Française, mais synaxiquement fausse car ils ne forment pas une phrase correct en Francais.

L'analyseur syntaxique genère un arbre de syntaxe abstraite (ASA) qui sera utilisé pour l'analyse sémantique.

Arbre de syntaxe abstraite

ASA

Analyse sémantique

Cette phase suit immediatement l'analyse syntaxique. Ici, on analyse l'ASA fourni par l'analyseur syntaxique. L’objectif de cette phase est de vérifier que toutes les phrases écrites dans l’ASA ont un sens dans le language utilisé.

Par exemple dans la langue Francaise: L'avion manges des fruits.

  • Le lexique est correct, chaques mots utilisé existent dans la langue Francaise.
  • La syntaxe est également correcte, c'est une phrase conforme à la langue Francaise.
  • Mais sémantiquement fausse car la phrase ne veut rien dire.

C'est lors de l'analyse sémantique que le compilateur génère la table des symboles qui permet, dans les grandes lignes, de ranger les identificateur avec leur type, l'emplacement mémoire, la portée, la visibilité, etc.

Three Address Code

Le "Thee Address Code" (TAC) est une optimisation de compilation qui permet de traduire chaque instruction en maximum 3 opérandes (comme en language d'assembleur).

Par exemple, si on reprend le code suivant:

ma_variable = 32 + 8 + 2

en TAC cela donnerait:

t1 = 32 + 8
t2 = t1 + 2
ma_variable = t2

L'optimisation du code

Ici le code est optimisé (il peut aussi l'êtres avant la génération de code intermédaire 'TAC')

Language Assemblage

Le code est ensuite traduit en langage d'assembleur (qu'on a vu dans la première section de cet article)

Assembleur

Avant dernière étape, le langage d'assembleur est ensuite passé à un suspense assembleur pour être re suspense assemblé !

Ce qui nous donne un fichier "objet" contenant du code machine.

Édition de lien

Enfin nous voila à la dernière étape ! L'édition de lien.

Cette étape permet de lier plusieur fichiers objet qui on été générés par le compilateur.

Quand un programme dépend d'autre fichier, notamment de la librairie standard du language (la libc par exemple), il faut spécifier à votre programme où se trouve le code de printf ou fgets ou tout autre fonction se trouvant dans la librairie standard, car ce que vous incluez avec le préprocesseurs include c'est juste les déclaration des fonctions et autre macro, donc votre main a connaissance de la fonction printf il sait qu'elle type de donnée la fonction retourne, le type et nombre d'arguments que la fonction a besoin, mais vous n'avez pas le code de la fonction, le code est dans la librairie libc.

Il faut donc lier cette librarire a votre programme et cela ce fait avec l'éditeur de lien.

Schéma récapitulatif

En résumé nous avons ce schéma: schema

C'est fini pour cet article, j'espère qu'il vous a plu, je pense avoir parlé du plus important, il se passe bien évidemment d'autre chose lors de la compilation mais c'est plus pour de l'optimisation ou parce que le language utilise des choses plus complexes comme le polymorphisme avec les templates ou les fonctions inlines etc (qui sont comme des macro-fonctions mais substitué lors de la compilation et non lors de la phase prétraitement). Mais j'estime avoir parlé du plus important et du plus basique.

✇I Learned

Découverte des permissions sous Linux

En utilisant Linux, vous avez probablement rencontré des erreurs telles que "permission denied" (permission refusée). Souvent des erreurs du genre sont frustrantes, pourquoi le système que j'ai installé me refuse l'accès ? Le but de cet article est de comprendre en détail le fonctionnement des permissions sous Linux et de vous aider.

Pour parler de droit sous Linux, il faut bien comprendre que tout est fichiers, que ce soit les configurations, les périphériques ou encore les informations sur un pid. Comme tout est fichier, les droits d'accès à chacun sont donc primordiaux. Par exemple, un utilisateur non privilégié qui accède à /dev/sda (dans le cas où votre disque est sda) serait dramatique.

Permission de base

Pour pallier à ces soucis, Linux dispose de droits plutôt basiques se limitant à :

  • read : autoriser à lire le fichier
  • write : autorise à écrire le fichier
  • execute : autorise à exécuter le fichier

Pour les dossiers, c'est la même chose mise à part que execute autorise à traverser le dossier et read permet de lister les fichiers. On peut prendre un exemple :

% ls -l
total 8
-rwx------. 1 raiponce raiponce 32 19 mar 16:17 f
-rw-r-----. 1 raiponce pascal   0 19 mar 16:15 b
-rwxr-xr-x. 1 raiponce raiponce 32 19 mar 16:16 c

Notation droit linux

On voit tout de suite l'utilité des lettres mises en gras plus haut. Elles sont utilisées pour visualiser les droits. Sous Linux de base, il y a 3 groupes de permissions :

  • utilisateur
  • groupe
  • tout le monde

Dans notre exemple, le fichier f est lisible, modifiable et exécutable par raiponce, pour le fichier. b est lisible et modifiable par l'utilisateur (ici raiponce) et lisible pour le groupe (ici pascal). Pour c tout le monde peut lancer et lire, mais seule raiponce peut modifier.

Les 2 principaux utilitaires pour gérer les droits de manière basique sur les fichiers sont chmod et chown. Pour chmod on peut l'utiliser soit en lui disant quel droit ajouter ou enlever à un fichier ou répertoire, par exemple :

chmod g+rw f

Ajoute les droits de lecture et écriture au groupe propriétaire sur le fichier f.

Une autre méthode consiste à utiliser des "nombres" ou chaque chiffre corresponds à une catégorie de droit (utilisateur, groupe, tous) et des permissions.

Droit Valeur en lettres Valeur en nombre
Aucun droit --- 0
exécution seulement --x 1
écriture seulement -w- 2
écriture et exécution -wx 3
lecture seulement r-- 4
lecture et exécution r-x 5
lecture et écriture rw- 6
tous les droits rwx 7

Vous l'avez probablement remarqué, mais ce ne sont que de simple addition, par exemple pour rw c'est le résultat de 2+4, il suffit donc de retenir le numéro lié à chaque droit et non tout le tableau.

Reprenons donc un exemple, donnons donc accès au groupe pascal en lecture et à l'utilisateur raiponce en lecture écriture aux fichiers x, ce qui nous donnera la suite de commande :

chown raiponce:pascal x #On met l'utilisateur raiponce et le groupe pascal propriétaire
chmod 0640 x #On donne les droits : rw-r-----

Masquage

Un autre aspect important est le "masquage", cela permet de définir les permissions pour les nouveaux fichiers ou dossiers. On peut voir le masque d'un dossier via umask -S. Le masque est une soustraction, par exemple umask 022 donnera les permissions 644 sur un fichier et 755 sur un dossier. Cela peut paraitre étrange, les permissions du fichier devrait être 755 non ? En fait, le masque par de la valeur 666 et non 777 (il faut donc manuellement donner les droits d'exécuter, le masque ne peut le faire) mais reste 777 pour les dossiers. Par exemple, si on veut que les nouveaux fichiers aient comme droit rw-r----- (640) on va pouvoir faire : umask 027, ce qui donnera aux dossiers les permissions 750.

Attributs spéciaux

Sous linux il existe des permissions plus poussée et fine pour donner certains droit à des binaires. Cela permet d'éviter de devoir lancer en root (root est le "super-utilisateur", c'est à dire qu'il a presque tous les droits).

Setuid et Setgid

Ces droits permettent à un binaire de se lancer en tant qu'une autre personne. Par exemple, si le fichier i_am_root est propriété de root il pourrait lancer un shell en root. Il est donc primordial de ne pas donner le setuid (souvent abrégé suid) ou setgid sur n'importe quel fichier. Bien sûr la plupart des programmes qui requiert un suid ou guid rajoutent des règles pour limiter les utilisateurs pouvant utiliser entièrement la commande (on peut le voir dans le code de passwd par exemple). Pour rajouter un suid ou sgid c'est toujours la commande chmod qui le permet. Par exemple : chmod ug+s y rajouteras un suid et guid au fichier y. On peut aussi utiliser la notation à base de nombre, pour ça il faut utiliser 4 chiffres au lieu des 3 pour les permissions simple. 2 signifie un setguid et 4 un setuid, l'équivalent du chmod montré juste au dessus serait donc chmod 6755 (dans le cas ou les permissions du fichier sont rwxr-x-rx).

Sticky bit

Un autre attribut qui peut être intéressant c'est le sticky bit. Il permet d'autoriser uniquement l'utilisateur propriétaire ou root de modifier, renommer ou supprimer. Un des usages courrants est le dossier /tmp, de nombreux dossiers y sont créer en pouvant être écrit par plusieurs personnes mais ne doivent pas être supprimé. On peut voir via ls -l si un fichier le présente :

drwxrwxrwt.  2 root     root      80 31 mar 13:13 .X11-unix

Ici on peut voir qu'il est présent, c'est la notation t qui l'indique. Pour le retirer on peut utiliser chmod pour le supprimer, avec la syntaxe classique : chmod +t pour ajouter, -t pour retirer ou via la notations en nombre, il est le numéro 1 donc par exemple chmod 1666 fichier.

Capabilities

Certaines actions sous Linux ne peuvent pas être faites en tant que simple utilisateur et pour éviter de devoir lancer en tant que root, ce qui est regrettable niveau sécurité, Linux possède ce qu'on nomme des capabilities. Elles permettent par exemple d'autoriser à un programme d'écouter un port en dessous de 1024. On peut lister celles présente sur un fichier via getcap. Par exemple pour ping on aura : /usr/bin/ping cap_net_raw=ep qui permet d'utiliser des socket raw. On peut voir dans la page de man : capabilities(7) la liste de celles-ci et leurs descriptions. Pour donner une capabilities à un binaire, on peut utiliser setcap. Par exemple setcap 'cap_net_bind_service=+ep' listener donne le droit à listener d'écouter sur un port plus faible que le 1024.

Chattr

chattr est un utilitaire qui permet d'attribuer certaines options à des fichiers ou dossiers, par exemple l'attribut i qui permet de rendre un fichier non modifiable, supprimable et aucun lien ne peut être fait vers lui. La commande à une syntaxe proche de chmod : chattr +i fichier pour donner l'attribut i et -i le retirer. Il existe d'autres options pouvant être intéressantes, je vous laisse lire la man page de chattr(1).

J'espère que cet article moins poussé techniquement que d'habitude vous auras plus, ça commençait à faire longtemps qu'on n'avait plus rien sorti 😅. On va essayer de vous sortir des articles d'ici pas trop longtemps, pour ne rien spoiler il y a un gros article qui ne parle pas directement d'informatique en préparation ;).

✇I Learned

À quoi sert initramfs ?

Pour la faire courte

Initramfs est un système de fichier monté dans la RAM lors de l'initialisation du noyau (kernel).

Un peu plus de détails

Initramfs est présenté sous forme d'archive cpio, c'est en quelque sorte l'ancêtre de tar.

Pourquoi ne pas utiliser tar ?? 🧐

Tout simplement parce que le code était plus facile à mettre en œuvre dans Linux et qu'il prend en charge des fichiers de périphériques, contrairement à tar.

L'archive contient les fichiers, scripts, bibliothèques, fichiers de configuration, et d'autres qui peut ou pourrait être utile au noyau pour monter le vrai système de fichier racine root. Cette dernière est ensuite compressée avec gzip et est stockée au côté du noyau Linux qui est sous le nom "vmlinuz" dans /boot/ (pour de l'UEFI) ou à la racine / pour du BIOS.

vmlinuz ? 🤨

Oui, c'est le nom du binaire du noyau Linux, vmlinuz est compressé en Bzip (pour ma part). En réalité, vmlinuz cache un vmlinux qui est lui le binaire du noyau, (le z à la place du x de Linux c'est tout simplement pour préciser qu'il est compressé (zip) Je vous laisse lire cet article qui explique un peu ce que je vous explique ici, mais le plus intéressant étant "l'histoire" du nom "vmlinuz".

À quoi ressemble le contenu d'un initramfs

Voyons ça étape par étape (si jamais l'envie vous prend de regarder votre initramfs (si vous en avez un)).

D'abord on copie notre initramfs dans un dossier, dans/tmp pour jouer l'immersion à fond 🤓 (/tmp étant NORMALEMENT monté en tmpfs, comme le système de fichier connu de Linux et dans lequel sera extrait le contenu de notre initramfs)

Si vous exécutez la commande file sur votre initramfs, vous verrez :

initramfs-linux.img: Zstandard compressed data

Il faut donc le décompresser, avec l'outil zstd ou, comme moi, utiliser zstdcat pour afficher le contenu décompressé et envoyer la sortie (stdout) vers l'entrée (stdin) de cpio qui permet de désarchiver un fichier cpio.

Si vous n'êtes pas root, vous n'avez certainement pas le droit de lire le dit fichier, exécutez donc la commande si dessous avec sudo ou doas, ou alors donnez-vous les droits de lecture (avec chmod).

zstdcat initramfs-linux.img | cpio -i

Si la commande file vous retourne: is ASCII cpio archive (SVR4 with no CRC), c'est que votre initramfs a un microcode ajouté (rien de méchant). Effectuez ces commandes:

cpio -t < initramfs.img >/dev/null Cette commande va vous retourner la taille du microcode, pour pouvoir ensuite le passer avec la commande dd.

dd if=initramfs.img of=initramfs_no_microcode.img bs=512 skip=<OFFSET> (remplacer <OFFSET> par la taille du block retourné par la commande précédente).

Puis effectuez: zcat initramfs_no_microcode.img | cpio -i

Si vous listez le contenu de votre dossier vous verrez quelque chose de familier, une hiérarchie à la Unix avec les répertoires de base :

ilearned:/tmp   ls -l
total 8708
lrwxrwxrwx 1 ownesis ownesis       7 14 févr. 11:32 bin -> usr/bin
-rw-r--r-- 1 ownesis ownesis    2510 14 févr. 11:32 buildconfig
-rw-r--r-- 1 ownesis ownesis      64 14 févr. 11:32 config
drwxr-xr-x 2 ownesis ownesis      40 14 févr. 11:32 dev
drwxr-xr-x 3 ownesis ownesis     160 14 févr. 11:32 etc
drwxr-xr-x 2 ownesis ownesis      60 14 févr. 11:32 hooks
-rwxr-xr-x 1 ownesis ownesis    2093 14 févr. 11:32 init
-rw-r--r-- 1 ownesis ownesis   13140 14 févr. 11:32 init_functions
lrwxrwxrwx 1 ownesis ownesis       7 14 févr. 11:32 lib -> usr/lib
lrwxrwxrwx 1 ownesis ownesis       7 14 févr. 11:32 lib64 -> usr/lib
drwxr-xr-x 2 ownesis ownesis      40 14 févr. 11:32 new_root
drwxr-xr-x 2 ownesis ownesis      40 14 févr. 11:32 proc
drwxr-xr-x 2 ownesis ownesis      40 14 févr. 11:32 run
lrwxrwxrwx 1 ownesis ownesis       7 14 févr. 11:32 sbin -> usr/bin
drwxr-xr-x 2 ownesis ownesis      40 14 févr. 11:32 sys
drwxr-xr-x 2 ownesis ownesis      40 14 févr. 11:32 tmp
drwxr-xr-x 5 ownesis ownesis     140 14 févr. 11:32 usr
drwxr-xr-x 2 ownesis ownesis      60 14 févr. 11:32 var
-rw-r--r-- 1 ownesis ownesis       2 14 févr. 11:32 VERSION

Je vous laisse vous balader dans les différents répertoires disponible. Par exemple dans bin qui pointe vers (usr/bin), vous verrez des outils comme :

  • bzip
  • mount
  • fsck.ext4
  • tftp qui a un article dédié ici 😜
  • lsmod
  • rmmod

Et beaucoup d'autres encore...

la plus part des outils présent dans initramfs sont disponible via un seul et même binaire qui est busybox

Processus de démarrage

On commence à partir du chargeur d'hamorcage (bootloader), GRUB par exemple.

  1. GRUB charge Linux et l'image initramfs dans la mémoire puis démarre le noyau (Linux).
  2. Linux vérifie la présence d'un initramfs, s'il en trouve il crée un système de fichier tmpfs et y extrait et monte l'initramfs.
  3. Dans ce même système de fichier (tmpfs), le noyau exécute le script init.
  4. Le script init monte le système de fichier racine root, en chargeant des modules du noyau utile pour le montage grace au différents scripts/programme et autres utilitaires présent dans l'initramfs (au besoin) et monte aussi les systèmes de fichiers comme /var et /usr.
  5. Une fois la racine monté, le script init commute la racine de tmpfs vers le système de fichier précédemment monté.
  6. Une fois la racine changée, le script init exécute le binaire /sbin/init pour continuer le processus de démarrage (en lançant des services/démons pour lancer le système).

Utilité d'un initramfs

Un initramfs n'est pas obligatoire, si on installe une distribution Linux qui permet de compiler sa propre version du noyau ainsi que sa configuration, une image initramfs n'est pas nécessaire, car le système est connu d'avance. Dans d'autres distributions, il y'a beaucoup d'inconnues pour le noyau, comme le type de système de fichiers par exemple, ce qui demande de charger certains modules dans le noyau ou d'avoir besoin de certains scripts/programmes. Généralement, ce sont les modules Linux qui pousse l'utilisation d'un initramfs.

Mais par exemple, imaginez une infrastructure ou tous les dossiers /home sont sur une autre machine, Linux est normalement incapable à lui tout seul de pouvoir se connecter à une machine distante sur le réseau de l'entreprise, pour ce faire, il utilise initramfs, qui possède toute une panoplie d'outils comme le paquet iproute, dhcp, mount, etc qui va permettre de monter un nfs (par exemple) depuis la machine distante qui partage les dossiers utilisateurs.

Conclusion

L'initramfs est un "mini" système de fichier compressé contenant toute une hiérarchie de système Linux avec des outils utiles pour le montage du système de fichier racine de votre machine, mais il n'est pas obligatoire.

bibliographie: - wiki.gentoo.org - fr.linuxfromscratch.org - wiki.debian.org - wiki.archlinux.org

✇I Learned

Comment fonctionne le protocole FTP ?

Pour transférer des fichiers sur internet avant HTTP il existait un protocole qui se voulait assez simple : FTP (file transfer protocol).

FTP se base sur TCP, par défaut le serveur écoute le port 21. Le client FTP qui va se connecter au serveur envoie une commande FTP au serveur. Par exemple pour récupérer un fichier sur le serveur :

RETR example.txt

Pour transférer les données FTP utilise un second canal. Il a 2 modes de connexions pour ce canal, actif et passif.

En mode actif le client écoute sur un port précis, contacte le serveur FTP en lui disant de répondre sur le port et le serveur FTP initialise une connexion de données sur ce port.

Le souci avec ce mode de fonctionnement est qu’il ne fonctionne pas avec du NAT ou un pare-feu restrictif sur les connexions entrantes.

Les données envoyées par le serveur sont bloquées par le Firewall en mode passif

Un autre mode pour palier à ces soucis existe, le mode passif. Pour ce mode-là le client envoie la commande PASV, le serveur envoie alors en retour une IP et un numéro de port que le client utiliseras pour répondre. ss Les données ne sont pas bloquées par le firewall en mode actif

FTP demande par défaut une authentification, une parade utilisée pour permettre un accès au fichier par n’importe qui est le FTP anonyme. Le principe est d’utiliser l’utilisateur anonymous sans mot de passe pour accéder aux ressources.

Le protocole FTP souffre de nombreux problèmes de sécurités et est en voie de disparition. Par exemple de base FTP n’a aucun chiffrement, il y a cependant FTPS qui a vu son apparition, c’est simplement FTP au-dessus de TLS.

✇I Learned

Comment fonctionne Wayland ?

L’affichage graphique d’un système d’exploitation est très complexe, si l’on veut avoir plusieurs fenêtre et application affichée en même temps en harmonie un logiciel qui gère les différents périphériques d’entrées et de sorties, l’isolation de chacun d’elle pour éviter qu’une application puisse récupérer les données d’une autre. Le but de cet article est d’essayer de comprendre le protocole Wayland qui vise à remplacer le vieillissant X11.

En résumer, Wayland (comme X11) sert à rajouter une couche d’abstraction pour les applications pour ne plus avoir à tout réinventer systématiquement.

Son mode de fonctionnement est client serveur. Le compositeur contrôle KMS et Evdev.

Evdev c’est la gestion des périphériques d’entrée sous Linux. Chaque périphérique se voit attribué dans /dev/input des fichiers qui permettent de recevoir les événements. Wayland utilise libinput (qui lui accède à evdev via libevdev) pour recevoir les entrées, la détection des nouveaux périphérique utilise udev. Le compositeur se charge d’envoyer au client les entrées. Une grosse avancée en sécurité par rapport à X11 est que les entrées ne sont pas envoyées à touts les clients, mais seulement celui concerné.

Pour la sortie vidéo chaque application envoie directement un buffer vidéo, un buffer c'est ce qui reçu par le gpu pour concevoir l’image le compositeur n’a plus qu’à assembler les différents buffers pour composer l’image finale, au compositeur, le compositeur s’occupe de gérer les fenêtres et de composer l’image complète avant de la renvoyer à KMS. KMS est le module kernel qui s’occupe de gérer l’affichage.

Schéma de l'architecture de Wayland

(source : https://wayland.freedesktop.org/architecture.html)

Le souci qui peut se poser est la rétrocompatibilité avec les applications X11, pour résoudre ce souci xwayland existe, c’est une couche de compatibilité. Xwayland s’occupe de faire un serveur X minimaliste pour les applications.

Xwayland est un intermédiaire entre les applications utilisant X11 et Wayland

(source : https://wayland.freedesktop.org/docs/html/ch05.html)

✇I Learned

Les différents type de sauvegarde (Backup).

Est-ce que ça vous est déjà arrivé de vous dire :

"Si seulement je faisais des sauvegardes"

ou

"Heureusement que j'ai fais des sauvegardes"

Si vous avez connu ou connaissez toujours la première situation, cet article est fait pour vous. Peut-être vous ne savez pas comment faire, quelle stratégie adopter ou quel outil utiliser.

Dans cet article je vais vous présenter les 3 types de sauvegarde connus, comment ils fonctionnent, comment les réaliser/ mettre en place et quel outil sont à disposition pour le faire.

La sauvegarde complète

La sauvegarde complète, c'est la plus simple, vous sauvegardez la totalité d'un dossier ou d'un système de fichier. Vous vous en doutez, si votre disque ou dossier fais 500Go, il faudra sauvegarder les 500Go à chaque fois ce qui est peut-être plus ou moins long ; surtout si vous utilisez un cloud ou un serveur distant pour sauvegarder tout ça. Déjà, il y a la limite de stockage qui peut vous limiter, ou une bande passante limitée, une sauvegarde journalière ou hebdomadaire sera compliqué. Heureusement il reste 2 autres types de sauvegarde que je vais vous présenter.

La sauvegarde incrémentielle

Une sauvegarde incrémentielle commence par une sauvegarde complète et se basera ensuite sur la sauvegarde précédente pour comparer les fichiers à sauvegarder (vérifier si un fichier à été modifié/créé). Par exemple (pour une sauvegarde journalière) :

Le lundi, on effectue une sauvegarde complète (ça sera la seule et unique sauvegarde complète). Le mardi, on effectue une sauvegarde et comme dit plus haut, une sauvegarde incrémentielle se base sur la sauvegarde précédente pour comparer les fichiers, donc on utilisera la sauvegarde de lundi (qui est la sauvegarde complète) pour comparer les fichiers qu'on envoie, et la sauvegarde du mardi sera constitué seulement des fichiers qui on été modifiés ou créés depuis la dernière sauvegarde. Le mercredi, on se base toujours sur la dernière sauvegarde effectuée, cette fois ci on compare alors la sauvegarde de mardi. Et ainsi de suite...

Petit point important sur cette sauvegarde, si vous avez bien suivi, et je suis sûr que c'est le cas, vous êtes sûrement dit :

Mais attend, si la sauvegarde incrémentielle se base sur la sauvegarde précédente pour comparer les fichiers, si dans la sauvegarde du mardi, on a seulement 3-4 fichiers, la sauvegarde du mercredi va contenir tous les fichiers qu'on envoie SAUF les fichiers déjà présents dans la sauvegarde du mardi (ci ces fichiers n'ont pas étaient modifié).

Et vous avez raison ! Pour les 3 du fond qui n'ont pas compris ou qui ne se sont pas posé cette question, un schéma vaut mieux que 1000 mots :

Imaginons, nous sommes lundi et je compte sauvegarder mon dossier personnel qui contient ces fichiers-ci :

/home/ownesis/:
    - password.txt.gpg
    - fat.md
    - socks.md
    - 13_reasons_why_i_hate_ramle.txt
    - tftp.md
    - ipv4.md

Je sauvegarde tout ça dans /media/usb/backup_lundi (C'est la première sauvegarde, sauvegarde complète). /media/usb/backup_lundi contient alors exactement tous les fichiers contenus dans /home/ownesis/.

Le mardi, je modifie fat.md, et crée le fichier backup.md. De ce fait lors de la sauvegarde, seul ces deux fichiers cités plus haut seront sauvegardés dans /media/usb/backup_mardi.

/media/usb/backup_mardi:
    - fat.md
    - backup.md

Vient maintenant le mercredi, je modifie le fichier backup.md. Lors de la sauvegarde, il va donc comparer mon /home/ownesis/ actuel avec /media/usb/backup_mardi/. Et là, c'est le drame ! Dans /home/ownesis j'ai des fichiers qu'il n'y a pas dans /media/usb/backup_mardi, du coup, il va les sauvegarder, pareil pour les fichiers backup.md que j'ai modifié, il n'y a que fat.md qui lui a été inchangé qui ne sera pas dans /media/usb/backup_mercredi, et ça sera ce scénario pour toutes les sauvegardes suivantes, un jour sur deux il y aura seulement 2-3 fichiers et le lendemain tout le dossier sauf ces 2-3 fichiers de Hier (s'ils sont inchangés).

/media/usb/backup_mecredi:
    - password.txt.gpg
    - socks.md
    - 13_reasons_why_i_hate_ramle.txt
    - tftp.md
    - ipv4.md
    - backup.md

C'est totalement chaotique comme scénario, du coup pour remédier à ce problème, il existe deux solutions :

  • Copier à chaque fois les fichiers inchangés de la sauvegarde précédente dans la sauvegarde actuelle (mais ça risque de consommer beaucoup de place à la longue car ca reviendrait à faire une sauvegarde complète).
  • Utiliser des liens physiques sur les fichiers inchangés de la sauvegarde précédente dans la sauvegarde actuelle.

Un lien physique ?

Les Liens sous Unix et Unix like.

Pour faire simple il existe 2 types de liens - Lien physique. - Lien symbolique.

Un lien physique, c'est le fais de faire pointer un ou plusieurs noms de fichier vers le même inode d'un fichier.

Un inode ? quèsaco ?

Pour faire très court et simple, un inode est propre à un système de fichier Linux/Unix, chaque fichier a son propre inode, c'est un numéro unique qui identifie chaque fichier du système de fichier. Il est possible de voir l'inode d'un fichier avec la commande ls -i fichier, ou avec la commande stat fichier.

toto.txt -> inode: 69420
toto_phylink.txt -> inode: 69420

toto.txt et toto_phylink.txt pointent tous deux vers le même inode 69420, si je modifie le contenu de toto_phylink.txt je vais aussi modifier le contenu de toto.txt et inversement. Si je supprime un des noms de fichier, cela n'entraine pas la suppression du second, si plus aucun nom est associé a un inode, le fichier et donc "supprimé".

Fun fact: lorsqu'on "supprime" un fichier sous linux avec rm, celui ci utilise l'appel système unlink (2).

Il existe aussi les liens symboliques, ils ont le même rôle, faire un "alias" mais au lieu de pointer vers l'inode, ils pointent vers le nom du fichier qui pointe vers l'inode du fichier, exactement comme ferait un "raccourci" sous Windows.

toto.txt -> inode: 69420
toto_symlink.txt -> toto.txt

Il existe donc deux types de lien, le lien physique renvoie directement vers l'inode correspondant tandis que le lien symbolique renvoie vers le fichier d'origine.

Il est possible de créer de tel lien (physique et symbolique) avec la commande ln (1).

Bon, c'est bien beau tout ça mais en quoi ça va nous aider pour la sauvegarde incrémentielle ?

Lorsqu'on comparera les fichiers actuels avec la sauvegarde précédente, au lieu de sauvegarder que les fichiers modifiés/créés, on va aussi créer des liens physiques des fichiers inchangé présent dans la précédente sauvegarde dans la sauvegarde actuelle, ce qui permettra, pour la prochaine sauvegarde, de comparer la sauvegarde précédente, mais aussi les fichiers inchangés qui précèdent cette précédente sauvegarde, etc. Ceci va nous éviter de se retrouver dans la situation vu plus haut, car mercredi on ne comparera non plus les malheureux 2 petits fichiers de mardi avec les 7 fichiers actuels, mais les 2 fichiers + les 6 autres fichiers de la sauvegarde précédant la sauvegarde du mardi (le lundi donc).

Oui, 6 fichiers et non les 7, car le fichier fat.md est présent dans la sauvegarde de mardi.

Du coup la sauvegarde du mercredi, on se retrouve avec seulement le fichier backup.md qui a été modifié et 7 liens physiques qui pointent vers les mêmes inodes des fichiers de mardi.

Si on reprend exactement les mêmes scénarios de la sauvegarde de lundi, mardi et mercredi en employant l'astuce des liens physiques, on se retrouve avec ceci :

/media/usb/backup_lundi:
    - password.txt.gpg                  (inode 1)
    - fat.md                            (inode 2)
    - socks.md                          (inode 3)
    - 13_reasons_why_i_hate_ramle.txt   (inode 4)
    - tftp.md                           (inode 5)
    - ipv4.md                           (inode 6)


/media/usb/backup_mardi:
    - password.txt.gpg                  (inode 1)
    - socks.md                          (inode 3)
    - 13_reasons_why_i_hate_ramle.txt   (inode 4)
    - tftp.md                           (inode 5)
    - ipv4.md                           (inode 6)
    - fat.md                            (inode 7) <- ici le fichier a é modifié, donc nouvel inode.
    - backup.md                         (inode 8) <- ici, un nouveau fichier à é créé donc, nouvel inode aussi.

/media/usb/backup_mercredi:
    - password.txt.gpg                  (inode 1)
    - socks.md                          (inode 3)
    - 13_reasons_why_i_hate_ramle.txt   (inode 4)
    - tftp.md                           (inode 5)
    - ipv4.md                           (inode 6)
    - fat.md                            (inode 7)
    - backup.md                         (inode 10) <- ici, le fichier a é modifié, donc nouvel inode.

De ce fait, pour la sauvegarde de jeudi, on comparera la sauvegarde de mercredi avec les anciens fichiers qui ont toujours le même inode qui date de la sauvegarde de lundi, mais avec le fichier fat.md qui pointe vers l'inode 8 (créé dans la sauvegarde de mardi) et du fichier backup.md qui pointe vers l'inode 10 (créée dans la sauvegarde de mercredi). Et on économise de la place, car les fichiers inchangés ne sont pas copié mais "pointé/lié" grâce aux liens physiques.

Pfiou, on en a vu des choses tout ça juste pour faire une sauvegarde incrémentielle, mais courage, c'est bientot fini.

La sauvegarde différentielle

Une sauvegarde différentielle ressemble à la sauvegarde incrémentielle, mais ne paniquez pas, elle est beaucoup plus simple à comprendre. On commence aussi par effectuer une sauvegarde complète. Mais contrairement à la sauvegarde incrémentielle qui compare la dernière sauvegarde effectuée, la sauvegarde différentielle elle, se comparera toujours avec la première sauvegarde (la complète). Du coup, plus besoin de liens symboliques ou physiques vu qu'on se basera sur la même sauvegarde, on ne copiera que ce qui est nouveau ou modifié par rapport à la sauvegarde complète. Il est quand même possible d'utiliser des liens physiques avec ce type de sauvegarde, pour que les fichiers inchangés de la première sauvegarde (sauvegarde complète) soient "lié" dans la nouvelle, mais ça reste facultatif. Ce type de sauvegarde consomme plus de place que la sauvegarde incrémentielle, mais ça restera toujours moins que plusieurs sauvegardes complètes.

Différence entre sauvegarde différentielle et incrémentielle

Quelles sont donc leurs différences si au final, avec l'incrémentielle et les liens physiques, on se met à comparer la totalité d'une sauvegarde (comme la différentielle) ?

La seule différence, c'est que la différentielle se basera toujours sur la première sauvegarde complète et l'incrémentielle sur la sauvegarde précedente. Ce qui veux dire que dans le cas d'une différentielle, si on crée ou modifie un fichier, que ce soit le mardi, mercredi ou autres jours, ces fichiers seront toujours copiés (même si inchangé par la suite), car ils ne sont pas présents où sont différents par rapport à la première sauvegarde. Tandis que l'incrémentielle, les fichiers seront créer une fois et s'ils ne changent pas, lors de la prochaine sauvegarde, ils ne seront pas copiés mais "liés", car je le répète, l'incrémentielle se basera sur la dernière sauvegarde et non pas la première.

Outils mis à disposition

rsync, le meilleur outil de sauvegarde (selon moi), bon, il faut aimer la ligne de commande, RTFM et faire des scripts, mais si tout cela ne vous fait pas peur, je ne peux que vous le conseiller. Vous pouvez utiliser l'option --compare-dest=REP pour de la sauvegarde différentielle, en comparant votre sauvegarde complète REP. Ou l'option --link-dest=REP pour de la sauvegarde incrémentielle, il créera les liens physique tout seul en comparant le dossier REP.

Duplicati, je ne l'ai personnellement pas testé, mais j'ai vu que des bons retours dessus, il permet de faire de la sauvegarde complète et/ou incrémentielle.

borgbackup, pareille, je n'ai pas pu le tester (j'ai essayé, mais j'avais du mal avec son utilisation) mais il a l'air puissant il a beaucoup d'options et pareil j'ai eu de bon retours sur cet outil, il permet la sauvegarde incrémentielle et complète.

Sinon si vous êtes vieux jeu, pour de la sauvegarde complète, rien ne vaut le simple cp (1) pour de la sauvegarde local.

Voilà, c'est tout ! J'espère que vous avez apprécié cet article et que vous savez maintenant quel sont les possibles stratégies qu'on peut adopter pour gérer ces sauvegardes.

Quelques mentions honorables du scénario "j'aurais dû faire des backups..."

  • Ajouter un espace en trop lors d'un rm -rf et supprimer /var fichier.txt au lieu de /var/fichier.txt.
  • Formater la mauvaise partition... aïe.
  • Utiliser find (1) pour chercher des fichiers présents dans un répertoire en adéquation avec l'option -exec shred -zvu {} \; et utiliser le chemin / au lieu de .
  • Faire une option "clean" dans un Makefile, la tester et d'avoir supprimé les seuls et uniques fichiers source du projet.

Quelques mentions honorables du scénario "Heureusement je fais des backups"

  • Supprimer par mégarde, la totalité de son Windows.
  • Mauvaise manipulation de git.

Sources: it-connect, rsync (1)

✇I Learned

C'est quoi un Active Directory

C'est quoi un Active Directory

Active Directory est un système au cœur des réseaux Windows et ce depuis 1996. Véritable incontournable de la sécurité informatique, il est devenu en quelques années une cible de choix pour les attaquants. Mais avant tout, il est nécessaire de comprendre ce qu’il est. Cet article destiné aux néophytes présentera, sans entrer dans trop de détails, comment il fonctionne.

Composants

Un active Directory est composé de trois services principaux :

  • Un DNS intégré.
  • Un serveur Kerberos.
  • Un serveur LDAP.

Le premier permet d’identifier clairement les machines dans un Active Directory en leur attribuant un nom. Ce nom dérive du nom du domaine, spécifié lors de la création d’un Active Directory (testlab.local par exemple)

Le second est un élément clé. En effet Kerberos permet d’authentifier les différents objets du domaine. Pour cela il procède par un système d’échange de tickets en 3 étapes, pour obtenir le ticket principal d’accès nommé TGT ("Ticket Granting Ticket"). En premier lieu, l’utilisateur par exemple, va effectuer une demande de d’authentification (KRB_AS_REQ) auprès du serveur d’authentification appelé KDC pour Key Distribution Center. Cette demande contient entre autres le hash NT (dans le langage de Kerberos il est aussi appelé RC4) de l’utilisateur, qui est un hash de son mot de passe (si vous voulez plus de détails sur l’algorithme utilisé, la fin de cet article vous éclairera). Puis ce dernier va retourner une réponse nommée AS_REP dans le cas où les identifiants sont valides, et cette réponse contiendra le TGT. Une fois ce fameux TGT obtenu, un utilisateur (ou une machine) s’en sert pour acquérir des TGS ("Ticket Granting Service") qui garantissent l’accès à un service sur une autre machine de l’environnement. Ces différents tickets ont un certain temps limite d’utilisation, une sorte de date de péremption qui est soigneusement réglée dans les paramètres de l’Active Directory. Pour ceux qui souhaiteraient plus de détails, je recommande chaudement cette article de Pixis.

fonctionnement de Kerberos

Le dernier élément est l’annuaire LDAP. Son rôle est aussi crucial que le second. Il centralise la base de données contenant tous les objets de l’Active Directory. Ainsi, il possède une architecture similaire à une arborescence partant de l’élément centrale de tout Active Directory, le domaine qui est traité en tant qu’objet (pour un domaine nommé testlab.local, l’arbre commence à DC=testlab,DC=lab). Chaque objet possède des propriétés qui sont exposées dans l’annuaire. Ainsi, il est une mine d’informations gigantesque et expose toutes les données nécessaires au bon fonctionnement de l’environnement. Que ce soient les GPOs qui sont en application sur le domaine, des ordinateurs ou d’autres objets. Entre ces derniers, il existe des relations de privilèges et de droits, qui sont des prolongements des ACLs et ACEs du modèle de sécurité de Windows (si ça vous dis rien, j’ai écris un article sur le sujet sur le blog de I Learned).

Ces services sont assurés par par un contrôleur de domaine qui est le cœur de l’environnement Active Directory. C’est à partir de lui qu’on déploie l’environnement.

Extension des domaines

Il existe une série de fonctionnalités très intéressantes qui sont mises à disposition par Active Directory. En premier lieu, les Contrôleurs de Domaine possèdent des rôles spécifiques (appelés FSMO). Chaque rôle leur permet d’assurer l’exposition d’un service clé, mais en plus avec un certain nombre de privilèges. Par exemple, l’un des rôles est le KDC que nous avons déjà vue, mais il en existe 4 autres que vous pouvez retrouver ici. La répartition de ces rôles permet un bénéfice énorme, un environnement Active Directory peut posséder plusieurs contrôleurs de domaine. Cela permet une plus grande souplesse en terme d’architecture (mais peut exposer dans le même temps plus de points faibles). En second lieu, pour que plusieurs domaines interagissent entre eux, il convient d’appliquer des « relations de confiances » entre ces domaines. De manière grossière, ils accordent aux utilisateurs certains droits dans un autre domaine (comme la lecture de l’annuaire). À remarquer qu’il n’est pas nécessaire que ces domaines aient une chose en commun, ils peuvent être différents en tous points.

Relation de confiance entre deux domaines

Il devient alors possible de combiner plusieurs domaines entre eux en un tout unique descendant d’un objet central. C’est ainsi que naissent les forêts. Par conséquent, il faut les voir comme des sortes « d’Active Directory d’Active Directory » où un domaine principal contient plusieurs sous-domaines enfants, donc différentes relations de confiances sont présentes entre ces différents sous-domaines. Les domaines deviennent donc des objets comme les utilisateurs par exemple, et des politiques très générales d’encadrement peuvent être déployées de manière très efficiente. Les ressources entre domaines différents sont désormais partagées, et des rôles de pouvoir spécifiques se mettent en place. L’exemple le plus flagrant est celui de l’Administrateur. En outre, dans un domaine unique, ce dernier est membre de trois groupes différents, bien sur, le groupe d’administrateurs local du contrôleur de domaine, le groupe « Domain Admins » et enfin le groupe « Enterprise Admins ». Ces deux groupes renvoient à deux choses différentes. Le premier concerne le domaine uniquement, alors que le second concerne la forêt dans son entièreté. Lorsque nous sommes dans une forêt, les mécanismes qui entrent en jeux sont les mêmes que dans un domaine, à la différence près que des objets d’un domaine externe peuvent interagir avec d’autres domaines. Ainsi, l’authentification Kerberos est partagée, et il en va de même pour l’annuaire LDAP.

Forêt

Vers plus de Cloud

L’une des plus grosses modifications récentes à cette architecture, est l’apport du Cloud. Le Cloud est une technologie révolutionnaire dans bien des domaines, entre autre le déploiement large de services et leur décentralisation, l’automatisation de plus en plus de tâches grâce au DevOps. C’est dans cette optique que Microsoft a pensé son infrastructure de Cloud nommé Azure. Bien sûr, comme à son habitude, Microsoft l’implémente à toutes les sauces, en premier lieu avec le DevOps (les pipelines Azure) et le stockage de données. Mais ils s’en sont également servi pour moderniser Active Directory en introduisant Azure Active Directory. Le concept en lui-même n’est pas bien différent de l’Active Directory standard, mais certains points de différences subsistent. Il n’y a plus de groupes mais des rôles, et les privilèges sont remplacés. Ils introduisent une décentralisation des applications notamment, et il existe un lien très fort entre un Active Directory standard et un Azure Active Directory, en outre ils peuvent être liés entre eux dans un même environnement.

Conclusion

J'espère que cet article vous a plu, si vous souhaitez aller plus loin, il existe énormément de ressources différentes, je pense notamment aux vidéos de Processus Thief, le blog de Pixis et de inf0sec (et éventuellement le mien) !

✇I Learned

Comment fonctionne IPFS ?

Aujourd'hui la tendance est de plus en plus à la décentralisation, dans ce mouvement, a été créé le protocole IPFS (Interplanetary File System, rien que ça oui). C'est un protocole qui a pour objectif de stocker des fichiers de n'importe quel type (image, vidéo, document texte, site web...) de façon décentralisée.

Ce protocole fonctionne en paire à paire (P2P) afin de garantir une plus grande accessibilité des fichiers hébergés.

Un changement de paradigme

Aujourd'hui sur le web, quand on fait la requête HTTP GET https://ilearned.eu/static/img/favicon.webp on va demander au serveur à l'adresse ilearned.eu le fichier contenu dans le chemin /static/img/favicon.webp. Le serveur pourrait alors nous renvoyer le favicon que nous cherchons, ou n'importe quoi d'autre, comme une photo de chaton.

Avec HTTP, on demande le contenu à un emplacement, pas un fichier spécifique directement.

Avec IPFS c'est tout à fait différent, plutôt que d'aller demander le fichier contenu à l'emplacement /static/img/favicon.webp, on va demander le hash du fichier que nous souhaitons consulter.

Si je souhaite consulter le favicon d'I Learned, je vais demander le hash (appelé CID) QmfJpxjQezydRAswGezKs9qqqM1fFAjEZRgA4VdwwCNUsw. Je suis alors sûr de recevoir l'image que j'ai demandé, et pas une photo de chaton qui aurait un CID (hash) différent (ici, QmYKfEPmNbuN9mYYmPENvpNpQ6yQQ3d1EfynYNA6qPGjTA).

Comment accéder aux fichiers ?

Savoir représenter des fichiers, c'est bien beau, mais encore faut-il pouvoir y accéder 😅. Avec IPFS, chaque nœud du réseau ont une paire de clé qui leur permet d'échanger des informations de façon chiffrée, mais aussi d'être identifié. Tous les nœuds du réseau stockent une DHT (Distributed Hash Table, table de condensats distribuée) cette table met en relation les différents nœuds du réseau et les données qu'ils partagent, mais aussi leur multiadresse. Une multiadresse, c'est une chaine de caractère qui permet de renseigner directement comment contacter un nœud, par exemple /ip4/89.234.156.60/udp/1234 indique de contacter l'adresse IPv4 89.234.156.60 en utilisant le protocole UDP sur le port 1234.

Le client demande d'abord à la DHT, puis va se connecter aux pairs

IPNS

Du fait de son fonctionnement basé sur des hash au lieu de la localisation d'un fichier, IPFS souffre d'un problème majeur. Si vous souhaitez partager avec une amie un document texte, vous devriez donner à cette amie un nouveau lien à chaque fois que le fichier change, ne serait-ce que d'un caractère. Afin de répondre à cette problématique, IPNS (InterPlanetary Name System) a été créé.

Comme nous l'avons vu plus tôt, chaque nœud du réseau a une paire de clés qui lui est propre. Vous pouvez publier un fichier spécifique à l'emplacement /ipns/cléPublique grâce à l'outil de ligne de commande de IPFS. Il est possible de générer plusieurs clés afin d'avoir plusieurs "noms de domaines".

Vous pouvez donc maintenant simplement partager votre clé publique avec votre amie, et celle-ci pourra accéder au fichier texte que vous souhaitiez partager !

Il existe aussi la possibilité d'utiliser le système de DNS "classique" en ajoutant un record TXT à l'emplacement _dnslink.YOURNDD avec pour contenu dnslink=/ipfs/CID. Ainsi, ipfs.eban.eu.org est accessible depuis IPFS à partir de l'adresse /ipns/ipfs.eban.eu.org car il contient le record suivant :

_dnslink.ipfs.eban.eu.org. 1555 IN  TXT "dnslink=/ipfs/QmQS9TDSi8RmLzM6QFaRcCkdnqUbGpXsFDG1iuyXnx9brm"

J'espère que cet article sur IPFS vous aura plu, c'est un protocole que je trouve, à titre personnel, très intéressant et prometteur à beaucoup d'égards. Il est par exemple utilisé pour stocker un clone de Wikipédia de façon décentralisée afin d'assurer que tout le monde puisse y accéder n'importe quand. Ce genre d'initiative va dans le sens d'un internet plus décentralisé, et donc moins dépendant des grosses sociétés tech (les GAFAM).

✇I Learned

TFTP, présentation et aperçu d'un protocole simple de transfert de fichier.

Aujourd'hui je vais vous présenter et vous parlez du protocole TFTP. J'imagine que vous pensez tout de suite au protocole FTP, et vous avez raison. TFTP signifie Trivial File Transfer Protocol.

Mais qu'est ce qu'il rajoute à FTP ?

Qu'est-ce qu'il enlève de FTP voulez-vous dire ? :eyes:

Oui, vous avez bien lu, TFTP, même si celui ci rajoute une lettre au protocole FTP, il retire une "plus ou moins importante" fonctionnalité a ce dernier. Il n'est pas possible d'exécuter des commandes, comme lister les fichiers, changer les droits des fichiers, se déplacer dans le système de fichier, etc. TFTP permet seulement de lire ou écrire sur le serveur distant, autrement dit, il permet seulement de récupérer ou envoyer (voir en créer dans certain cas) des fichiers (ou des courriers). Autre chose importante à savoir, il n'y a pas d'authentification des utilisateurs. Bon, vous l'aurez deviné, TFTP est un protocole de la couche application, il faut donc permettre le transport et c'est avec le protocole UDP que cela ce fait.

On utilise le protocole TFTP notamment pour la mise à jour des firmwares sur les équipements réseaux, la sauvegarde de la configuration de ces équipements réseau, mais aussi pour amorcer des stations de travail sans disque dur. C'en est tout pour la présentation de TFTP.

Maintenant rentrons dans le vif du sujet, voyons comment le protocole fonctionne : Pour commencer, le client demande une connexion au serveur TFTP, dans cette demande de connexion, le client précise si c'est pour de la lecture ou d'écriture de fichier. Le serveur accepte ou non la demande, si le serveur accepte, la connexion est de ce fait "ouverte" et le partage du fichier peut avoir lieu. Le bloc de donnée utilisé pour envoyer le fichier, que ce soit du côté client ou serveur, est d'une taille fixée à 512 octets, chaque paquet contient un bloc de données et doit être acquitté par un paquet d'accusé de réception avant l'envoie d'un prochain paquet. Pour signaler la fin d'un transfert, un paquet de données d'une taille inférieur à 512 octects doit être envoyé.

Si le client demande une connexion pour lire un fichier, il envoie l'OPcode RRQ ou l'OPcode WRQ pour écrire, le serveur envoie ensuite une réponse "positive", un accusé de réception pour acquitté la demande du client (si la demande est pour lire, le serveur envoie directement le bloc de données comme accusé de réception). Si un paquet se perd dans le réseau, le receveur sera alors mis en "timeout" et l'envoyeur devra réenvoyer le paquet. En général, un paquet d'accusé de réception contiendra le numéro de bloc du paquet de données reçu. Chaque paquet de données est associé à un numéro de bloc. Les numéros de bloc sont consécutives et le premier commence à 1. Lors d'une demande d'écriture (OPcode WRQ), l'accusé de réception à cette demande aura comme numéro de bloc de donnée 0.

Lors d'une création de connexion, chaque extrémité de la connexion choisit un TID (Transfer ID), une identification de transfert donc, pour lui-même. Les TID doivent être choisis au hasard. Chaque paquet est associé aux deux TID des extrémités de la connexion, le TID source et de destination. Ces TID sont remis à UDP comme ports source et destination. Le client, choisis sont TID (le port UDP) comme décrit ci-dessus et envoie sa requête initiale au TID 69 du serveur.

Vous l'aurez compris, le serveur TFTP écoute de base sur le port 69.

Lors de la réponse à la demande de connexion du client, le serveur choisis un TID (un autre port source), qui sera utilisé pour le reste de l'échange. À ce moment les deux extrémités de la connexion ont leurs propres TID et l'échange pour ce faire. Les hôtes doivent s'assurer que le TID source correspond toujours aux TID choisis. Si un TID ne correspond pas, le paquet doit être rejeté et un paquet d'erreur doit être envoyé à la source du paquet incorrect, sans perturber le transfert.

Paquet TFTP

TFTP prend en charge 5 types de paquets (OPcode) codé sur 2 octets, les voici: - 0x0001 RRQ (Demande de lecture) - 0x0002 WRQ (Demande d'écriture) - 0x0003 DATA (Données) - 0x0004 ACK (Accusé de réception) - 0x0005 ERR (Erreur)

Paquet de demande de lecture ou d'écriture

Le paquet RRQ/RWQ ressemble à ceci :

RRQ & RWQ headers

  • OPcode: 2 octets (0x0001 RRQ ou 0x0002 RWQ).
  • Nom de fichier : Taille variable, il correspond au nom/chemin du fichier.
  • 0: 1 octet, correspond à la fin de la chaine de caractère désignant le fichier.
  • Mode: Taille variable, voici les différents modes (insensible à la casse) :
    • 'netascii'
    • 'octet'
    • 'mail' (obsolète)
  • 0: 1 octet, correspond à la fin de la chaine de caractère désignant le Mode.

L'hôte qui reçoit le mode netascii, doit "traduire" les données dans son propre format (en modifiant la fin de ligne \r\n ou \n ou \n\r, ...) Le mode octet permet d'envoyer le fichier "tel quel".

Paquet de Données

Le paquet de Données (DATA) ressemble à ceci :

DATA header

  • OPcode: 2 octets (est mis à 0x0003 DATA).
  • # de bloc: 2octets Numéro de bloc.
  • Données: Taille variable, ce sont les données à envoyer

Le numéro de bloc commence à 1 et est incrémenté à chaque envoi. La taille des données est limité à un maximum de 512 octets, si le paquet de données n'est pas le premier et que la taille de la donnée et inférieur à 512 octets, cela correspond à la fin du fichier et du transfert.

Paquet d'acquittement

Le paquet d'accusé de réception (ACK) ressemble à ceci :

ACK header

  • OPcode: 2 octets (est mis à 0x0004 ACK).
  • # de bloc: 2 octets, correspond au numéro de bloc reçu.

Si la demande du client est une demande d'écriture (OPcode 0x0002), Le serveur acquitte la demande avec le numéro de bloc 0x0000.

Paquet d'Erreur

Le paquet d'erreur (ERR) ressemble à ceci:

ERR header

  • OPcode: 2 octets (est mis à 0x0005 ERR).
  • ErrCode: 2octets, correspond aux codes erreur suivant:
    • 0x0000 Non défini, voir le message d'erreur (le cas échéant).
    • 0x0001 Fichier introuvable.
    • 0x0002 Violation d'accès.
    • 0x0003 Disque plein ou allocation dépassée.
    • 0x0004 Opération TFTP illégale.
    • 0x0005 ID de transfert inconnu.
    • 0x0006 Le fichier existe déjà.
    • 0x0007 Aucun utilisateur de ce type.
  • ErrMsg: Taille variable, correspond a une chaine de caractère définissant le code d'erreur.
  • 0: 1 octet: Spécifie la fin de la chaine de caractère ErrMsg.

Exemple de connexion et de transfert

Voici un exemple de connexion et de récupération de fichier :

HostA récupère le fichier file.txt d'une taille de 920 octets sur HostB qui héberge un serveur TFTP.

Exchange schema

HostA:4242 (OPcode=RRD; file=file.txt; mode=netascii)  --> HostB:69
HostB:9090 (OPcode=DATA; BLOCK=1; [512 bytes data...]) --> HostA:4242
HostA:4242 (OPcode=ACK; BLOCK=1) --> HostB:9090
HostB:9090 (OPcode=DATA; BLOCK=2; [408 bytes data...]) --> HostA:4242
HostA:4242 (OPcode=ACK; BLOCK=2) --> HostB:9090

Ici, 4242 et 9090 correspond au TID/Port UDP de HostA et HostB respectivement.

Serveur / Client TFTP

Vous pouvez télécharger le daemon tftpd et le client tftp avec les paquets suivant: tftpd-hpa et tftp-hpa. Le client Curl intègre aussi le protocole TFTP: Upload: curl -T file.txt tftp://HOST Donwload: curl -o file.txt tftp://HOST/FILE

Voilà, c'est fini j'espère que cet article vous a plu et que vous avez compris l'utilité et le fonctionnement de TFTP.

Conclusion

TFTP est donc un protocole simple permettant uniquement le transfert (et la création dans certain cas) de fichier, il fonctionne sur UDP. Il ne propose pas d'authentification, ni de chiffrement (mais il est possible de passer par un serveur SOCKS, donc Tor :eyes:). C'est une sorte de FTP plus léger et plus simple à programmer/mettre en place, il ne permet pas l'exécution de commande, mais seulement le transfert de fichier. Contrairement aussi à FTP, il n'y a pas de mode dit "passive" ou "active", vu que le protocole utilise UDP. Le choix de ce protocole de transport permet aussi une meilleure rapidité, même si les limites de taille de bloc sont limité à 512 octet, en moyenne, en partant du principe que l'entête IPv4 n'a pas d'option, la taille MAXIMUM THÉORIQUE (ma théorie) ne devrait pas dépasser les 558 octets:

  • Trame Ethernet : 14 octets
  • Entête IPv4 : 20 octets
  • Entête UDP : 8 octets
  • Entête TFTP: 516 octets (OPcode + # bloc + bloc maxi)

Total: (14 + 20 + 8 + 516) = 558

UDP ajoute la rapidité, mais le fait que la taille des blocs est limitée à 512 octets, qu'entre chaque envoi de bloc il faut attendre l'accusé de réception et, qui plus est, que l'accusé de réception ou le bloc de données peut se perdre dans le réseau, la durée peut varier, surtout pour des fichiers volumineux (ces problèmes là peuvent intervenir aussi avec TCP, mais celui-ci reste beaucoup plus fiable).

Source: RFC 1350 - doc. Ubuntu

✇I Learned

FAT, comment fonctionne un système de fichier

Aujourd'hui je vais vous parler du système de fichier FAT (File Allocation Table). Avant de commencer, qu'est-ce qu'un système de fichier ? Il peut désigner deux choses :

  1. La hiérarchie d'un système d'exploitation, par exemple sous les Unix like comme BSD, Linux, macOS, le système commence a la racine /. Sous Windows, le système commence depuis C:\.

  2. L'organisation du fichier dans un support de stockage (volume physique ou logique), et il en existe tout un tas de type différent : NTFS, FAT, FAT32, ext4fs, zfs, ...

Ici on va parler de la 2ᵉ définition et de FAT. Ce système de fichier a été utilisé pour le système Windows, on le retrouve aussi parfois sur des clés USB. La table d'allocation indexe le contenu d'un fichier se trouvant dans un support de stockage avec son emplacement dans ledit support. Il faut savoir que les "blocs" qui constituent un fichier ne peuvent pas être stockés de manière contiguë sur le disque, le fichier est "fragmenté". Une table d'allocation permet d'indexer et de retrouver chaque fragment du fichier. Le système FAT est un système sur 16 bits et permet de nommer un fichier avec un nom d'une longueur de 8 caractères et d'une extension de 3 caractères. On appelle ce système FAT16 (16 pour les 16 bits).

8 caractères + les 3 caractères d'extension, c'est... ridicule. Pour remédier à ce "problème", Windows 95, qui utilise le système FAT16, avait une version "amélioré" de celle ci, le VFAT (Virtual FAT). Ce système contrairement au FAT16, était un système 32 bits et permettait d'enregistrer un fichier avec un nom de 255 caractères de long.

Revenons sur notre système 16 bits. Que signifie les 16 bits ? C'est le nombre maximum de cluster que peut adresser le système de fichier.

Un cluster ? qu'est-ce donc ?

Pour faire simple, un cluster est un groupe de secteurs, c'est dans ces clusters que sont stocké les données d'un fichier.

Et qu'est ce que c'est qu'un secteurs ?

Un secteur est la plus petite unité physique de stockage sur un support de donnée.

Pour notre exemple, on va partir du principe qu'un secteur a une taille de 512 octets. Un cluster a une taille fixée de secteurs (4, 8, 16, 32, ...). Pour déterminer la taille maximum d'une partition FAT16 il faut multiplier la taille d'un cluster avec la taille d'un secteur, partons du principe que nous avons un cluster de 32 secteurs, 32 * 512 = 16 384. Maintenant, il suffit de multiplier ce nombre par le nombre de clusters maximum géré par le système de fichier (2^16 = 65536): 16 384 * 65536 = 1073741824 (~1Go)

Un fichier occupe un cluster, même une partie de fichier. En gros, si on reprend notre exemple plus haut, sur des secteurs de 16 384 octets, si un fichier fait 20 000 octets, les 16 384 premiers octets du fichier seront stocké dans un cluster entier, mais les 3616 derniers octets du fichier seront stocké dans un autre cluster lui aussi de 16 384 octets, (16 384 - 3616) = 12 768, on perd donc 12 768 octets ! Ces octets-là ne pourront pas être utilisés par un autre fichier. Alors vous l'aurez surement compris, plus un cluster est petit en taille, moins il y a de gaspillage de place. En moyenne, on estime qu'un fichier gaspille la moitié d'un cluster... aïe.

Le système FAT est composé de 3 grandes sections :

  1. Le secteur de boot, contenant le BPB c'est le premier secteur de la partition.
  2. Les tables d'allocation
  3. Le répertoire racine

On ne va pas s'attarder sur le secteur de boot.

Le répertoire racine, pour faire simple, c'est lui qui va stocker le nom du fichier, sa taille, ses attributs, la date et heure de création, de modification etc ; et le plus important, le numéro du premier cluster.

Il faut imaginer une Table d'allocation comme un tableau de "nombres" indexé par un numéro de cluster. Chaque "nombres", correspond à une information concernant le cluster :

Nombres Description
0x0000 Cluster vide
0x0001 Cluster réservé
0x0002 - 0xFFEF Cluster utilisé, pointant vers le cluster suivant
0xFFF0 - 0xFFF6 Valeurs réservées
0xFFF7 Mauvais cluster
0xFFF8 - 0xFFFF Cluster utilisé, dernier cluster

On pourrait imaginer la table d'allocation suivante :

Cx = Cluster n°x

Deux fichier, un sur plusieurs clusters et un second sur un seul

Un fichier qui utilse les clusters 2, 3 et 5 et un autre fichier le cluster 6.

Voilà, c'est fini pour cet article, j'ai essayé d'être plus simple possible pour que vous ayez l'idée de comment fonctionne et à quoi peut ressembler un système de fichier. Pour plus de détails je vous invite à lire les sources ci-dessous, plus complète, notamment celle de Wikipédia.

Source : Wikipedia (File Allocation Table) - Commentcamarche (FAT16 et FAT32)

✇I Learned

Les bases de registres Windows

Les registres Windows sont un composant vital du système d'exploitation. En effet, ils contiennent l'ensemble des paramètres que le système doit appliquer à chaque démarrage, mais exposent aussi des informations cruciales que certains programmes doivent pouvoir disposer. Dans cet article, nous explorerons le fonctionnement des registres Windows et des interactions élémentaires avec ceux-ci.

Les registres, c'est quoi

Apparus en 1990 avec Windows 3.1 (et oui, c'est ancien), les bases de registres (en anglais "registry hives"), sont des bases de données hiérarchisées comportant l'ensemble des paramètres de Windows (bien que Microsoft préfère l'appellation registre Windows). Ainsi, ils fournissent un accès très rapide à un ensemble de fonctionnalités. À ce titre, nous retrouvons des informations sur les différents services présents sur le système, les applications installées, les utilisateurs du système, ou bien des paramètres de sécurité comme le mode de langage restreint de PowerShell. Par conséquent, il est possible de modifier le comportement de ces paramètres, en éditant les valeurs associées. Pour accéder aux registres de Windows, trois possibilités. La première, l'utilitaire regedit.exe, natif à l'OS, il propose une interface intuitive qui présente les chemins comme des arbres. Regedit.exe La seconde possibilité est d'accéder aux registres au moyen des APIs mises à disposition par Microsoft avec C/C++/C#. La dernière est l'accès avec une ligne de commande, principalement PowerShell (même si certains outils sont disponibles pour le CMD). En outre, pour naviguer au travers des différents espaces de stockage d'informations, PowerShell se base sur ce que l'on appelle des PSDrive. Ils sont une généralisation de ce qu'une invite de commande appelle disque, et peuvent contenir tous types d'informations. Ainsi, les disques physiques comme le C:\, les partages SMBs, des répertoires particuliers (par exemple C:\Users\Lancelot, le point bonus ici est que le PSDrive est cloisonné, on ne pourra pas aller en C:\Users dans ce cas), et les registres sont des éléments susceptibles d'être des PSDrive. La cmdlet Get-PSDrive vous informe des actuels PSDrive montés. Dans l'exemple ci-dessous, on utilise PowerShell pour se rendre dans la ruche HKCU. Exploration des registres avec PowerShell Pour savoir ce que sont HKCU etHKLM, sont devons nous intéresser à la structure des registres.

Architecture

Comme mentionné dans la partie précédente, les registres sont souvent présentés sous forme d'arborescence. A ce titre, on les identifie sous forme de chemin démarrant à une classe. Il en existe deux principaux:

  • HKLM, pour HKEY_LOCAL_MACHINE, qui contient l'ensemble des paramètres du système d'exploitation. Cette classe est composée de plusieurs autres : SAM (pour "Security Account Manager") qui regroupe l'ensemble des paramètres de sécurité de l'OS, y compris les condensats de mots de passe des utilisateurs, SOFTWARE qui rassemble les informations sur les logiciels présents sur la machine, SYSTEM qui contient les paramètres du système d'exploitation tel que les configurations des différents services, et enfin HARDWARE qui expose les informations qui concernent le matériel physique de la machine, le type d'UEFI, le BIOS embarqué ou bien encore le processeur. Il est à noter que ces données sont écrites en C:\Windows\System32\Config par des fichiers nommés : SAM, SOFTWARE, SYSTEM (HARDWARE étant directement chargé en mémoire).
  • HKU, pour HKEY_USER, contient l'ensemble des informations relatives aux différents utilisateurs enregistrés sur le système d'exploitation. Les différents SIDs par exemple (identifiants de sécurité unique), les dossiers de fichiers temporaires, le nom d'utilisateur, ou encore les paramètres de bureau et de l'UI. Cette classe est sauvegardée à différents endroits qui dépendent de l'utilisateur. En effet, en raison de sa nature, les données que HKU exhibe doivent être accessibles à l'utilisateur de notre session. Ainsi, la majeure partie des informations sont écrites dans %USERPROFILE%\Ntuser.dat (où %USERPROFILE% désigne le chemin vers le dossier courant de notre utilisateur).

Auxquelles viennent s'adjoindre un certain nombre d'autres classes, qui sont des raccourcis pour des sous-classes des deux premières:

  • HKCU, HKEY_CURRENT_USER, est une sous-branche de HKU qui concerne l'utilisateur avec lequel notre session est enregistrée.
  • HKCC, HKEY_CURRENT_CONFIG, est une sous-classe de HKLM (HKLM\System\CurrentControlSet\Hardware Profiles\Current) qui recense des informations sur le matériel physique actuellement utilisé et sa configuration.
  • HKCR, HKEY_CLASSES_ROOT, est un mixe entre deux sous-classes de HKLM (HKLM\Software\Classes et HKCU\Software\Classes) qui contient les informations sur les applications enregistrées pour des tâches spécifiques, par exemple avec quoi ouvrir quel type de fichier (représenté par l'extension de celui-ci, sous Windows).
  • HKPD, HKEY_PERFORMANCE_DATA, qui concentre les informations relatives aux performances des applications, programmes et autres en cours d'exécution. Cette classe n'est pas sauvegardée, les données sont collectées directement auprès des programmes. Cachée par regedit, cette classe reste néanmoins accessible à l'aide des APIs Windows.

Il en existe d'autres classes mais beaucoup plus anecdotique que vous pouvez trouver ici.

Les données contenues dans les registres doivent bien être écrites à un endroit. Si vous disposez de droits suffisant (l'accès Administrateur, ou bien des privilèges d'accès), vous pourrez les retrouver dans le System32. Si vous êtes plus un linuxien dans l'âme, vous pouvez comparer les registres Windows avec le dossier /etc. Toutes les classes ne sont pas enregistrées physiquement, mais si c'est le cas, elle est alors appelée "ruche" (de l'anglais "Hive"). Certains exemples sont donc évident d'après les informations que nous avons, SYSTEM, SAM sont des ruches.

Par la suite, on ajoute après des antislash les sous-classes, un peu comme les chemins de répertoires plus classiques pour Windows. Un chemin en entier est appelé clé. Alors une ou plusieurs valeurs y sont associées. Ainsi, les données sont structurées à l'aide de table, une clé, à laquelle on associe une ou plusieurs valeurs qui est d'un type particulier. Les types principaux étant les suivants:

  • REG_NONE, indique une valeur inexistante.
  • REG_SZ, est une chaîne de caractère (son encodage étant UTF-16 LE par défaut pour tous les systèmes Windows).
  • REG_EXPAND_SZ, est une chaîne de caractère qui représente une variable d'environnement.
  • REG_BINARY, une donnée en format binaire, quelle qu'elle soit.
  • REG_DWORD, un nombre de 32 bits.
  • REG_LINK, représente un lien symbolique vers une autre clé de registre.
  • REG_QWORD, un nombre de 64 bits.

Bien sûr, pour des usages plus précis, il existe d'autres types que vous pouvez retrouver ici. De surcroît, parfois les clés contiennent d'autres clés qui sont alors appelées sous-clés.

D'un point de vue sécurité, il faut comprendre que les registres sont considérés, comme la quasi totalité des objets Windows, en tant que "Securable Object". Il en découle que des ACLs peuvent être placées pour restreindre les accès. Ainsi, il existe des privilèges qui permettent de modifier le comportement de sa session vis à vis des registres. Ces privilèges sont SeRestorePrivilege et SeBackupPrivilege qui permettent de lire et modifier sans permission des clés de registres (pour plus d'informations). Lorsqu'un utilisateur ne possède pas le droit de voir une classe ou une clé, elle apparaît vide de contenu dans regedit.exe, sinon c'est plutôt un beau message d'accès interdit !

ACL de HKLM

Fonctionnement

Lors du démarrage de Windows, le noyau du système va instancier et charger les différents registres (si la classe n'est pas une ruche, il va dynamiquement la créer, comme HARDWARE par exemple, si la classe est une ruche, les données seront simplement chargées des fichiers du disque). Puisque ces registres exposent des données relatives à la vie du système, le noyau va appliquer les configurations renseignées (ou les différents programmes démarrés comme smss.exe). Si par exemple un certain nombre de services sont enregistrés, alors le noyau les démarrera dans leur ordre d'importance et de vitalité. Lorsqu'un utilisateur se connecte, les informations de HKCU seront appliquées pour faire apparaître les icônes du bureau.

Les registres peuvent naturellement être modifiés, en fonction du niveau de privilège de l'utilisateur (ou du programme). Pour reprendre un exemple précédemment cité, si un Administrateur souhaite ajouter des services à la machine (comme le démarrage d'applications de télémétrie à l'instar de Sysmon). Pour cela il existe un certain nombre d'options mais le plus pratique étant, les GPO (pour "Group Policy Object", j'ai écris un article à leur sujet) qui permettent un déploiement large, rapide et efficace. Mais également, pour un usage plus individuel, avec les fichiers REG. Ces derniers sont des fichiers dont l'apparence est semblable au CSV. Ils possèdent la syntaxe suivante:

[Ruche\Clé\Sous-clé]
"nom de la clé"=<type de la valeur>:<valeur>

Lorsqu'ils sont exécutés, ils modifient les clés renseignées. Attention cependant, ils sont très répandu mais peuvent parfois contenir des malwares, alors prudence avant de les utiliser, surtout s'ils proviennent de sources inconnues. Pour accéder en ligne de commande aux registres, vous pouvez utiliser l'utilitaire Reg.exe depuis l'invite de commande ou PowerShell. La syntaxe est assez simple, mais elle nécessite que vous possédiez le chemin complet de la clé. Voici un exemple assez modeste qui montre les variables d'environnement par défaut de tous les utilisateurs. Lecture d'une clé de registre avec Reg.exe Il est également possible d'utiliser les Cmdlets natives à PowerShell, celles prédestinées à cette usage étant Get-Item/Get-ItemProperty: Lecture d'une clé de registre avec PowerShell Aussi, vous pouvez vous placer dans le PSDrive du registre, et vous pourrez naviguer dans celui-ci exactement comme si vous étiez dans un dossier !

Pour créer une clé, on peut utiliser Reg.exe de la manière suivante:

Reg.exe ADD [Clé] /V [nom de la valeur] /d [données associées] /t [type]

Par exemple ajoutons la valeur Hello de type REG_SZ contenant "toto" à la clé HCKU\Test: Ajout d'une clé avec Reg.exe Nous pouvons faire de même avec PowerShell. En premier lieu, nous créons la clé avec New-Item, puis on ajoute la valeur avec New-ItemProperty: Ajout d'une clé avec PowerShell Pour modifier une clé. Avec Reg.exe on fait comme si nous voulions créer une nouvelle clé, et on ajoute le flag /f pour forcer la réécriture de la clé. Avec PowerShell, rien de plus simple, on utilise la Cmdlet Set-ItemProperty:

Set-ItemProperty -Path "HKCU:\Test" -Name "Hello" -Value "hey"

Attention cependant, car le type de la valeur sera inchangé. S'il faut le changer, on supprime la clé et on la refait.

Pour supprimer une clé avec Reg.exe, rien de plus simple: Reg.exe DELETE [Chemin de la clé] Avec PowerShell on utilise Remove-Item ! Suppression d'une clé avec PowerShell Évidemment, les exemples ici sont volontairement simplistes, et un usage bien plus avancé de ces outils est possible.

Conclusion

Cet article touche à sa fin, j'espère que cet article vous aura plu et aura permis d'apporter des lumières sur les zones d'ombres que pouvaient représenter les registres Windows. Si l'univers de l'OS de Microsoft et sa sécurité vous intéresse, n'hésitez à aller consulter mon blog ou bien les autres articles que j'ai publiés sur I Learned !

✇I Learned

La blockchain, comment ça marche vraiment ?

Ces derniers temps, on entend beaucoup parler de la blockchain comme étant le remède à tous nos maux. Dans cet article nous allons nous pencher sur le fonctionnement technique de cette fameuse blockchain et voir en quoi elle peut (ou non 😏) être utile.

Une blockchain, ça veut dire quoi ?

Une blockchain, car il en existe plusieurs, est une chaine de blocs liés ensemble cryptographiquement. Cela permet donc de créer une chaine de confiance non falsifiable, notamment utile dans le cadre des cryptomonnaies.

Afin de les lier entre eux, chaque bloc de la chaine contient le hash du bloc précédent, ce qui permet de s'assurer que la chaine n'est pas falsifiée.

Une chaine de blocs avec à l'intérieur de chacun le hash du précédent

Si un attaquant cherchait à ajouter un bloc a posteriori, il serait tout de suite détecté. La chaine de blocs a aussi pour avantage d'être vérifiable par n'importe qui ayant à sa disposition un ordinateur capable d'exécuter des fonctions de hashage.

Une chaine de blocs avec à l'intérieur de chacun le hash du précédent, sauf le troisième qui est un intrus

Comment ça fonctionne concrètement ?

Vous l'imaginez bien, la vision présentée ci-dessus est grandement simplifiée. Dans les fait, les blockchain publiques sont confrontées à des problématiques comme le fait que le réseau puisse être saturé par une arrivée massive de paquets. Pour éviter cela, a été créée la méthode du Proof of Work.

Afin de complexifier la création d'un bloc, la méthode du Proof of Work (PoW) requiert d'ajouter un champ à notre bloc que l'on remplira de données aléatoirement jusqu'à ce que le hash du paquet commence par un nombre donné de 0 (et donc soit d'une certaine taille). Pour le bitcoin par exemple à date d'écriture de cet article, pour qu'un paquet soit valide, il faut que son hash commence par 19 zéros. Cette valeur est déterminée en fonction des 2016 derniers blocs minés (et change donc très fréquemment) afin d'assurer qu'il n'y ai toujours en moyenne qu'un bloc validé toutes les dix minutes. Cette méthode se base donc sur la complexité calculatoire des fonctions de hashage. Un bloc a la structure suivante

ID Du bloc - Hash du bloc précédent - Données - Proof of Work - Hash de ce bloc

Le problème de cette méthode, c'est qu'elle est très énergivore, elle implique d'avoir des fermes entières de "minage" (qui ne sont donc en réalité que des machines qui calculent des hash) qui consomment beaucoup d'électricité afin de garantir la sécurité de la blockchain. Entre le mineurs, la conccurence est rude et au final, seul le travail d'un mineur sera récompensé, toutes les autres fermes ont donc travaillé, et consommé beaucoup d'électricité pour... rien. À l'heure d'une prise de conscience généralisée autour de l'urgence climatique, cette méthode semble donc inadaptée.

Afin de répondre aux problématiques, notamment environnementales, que pose le Proof of Work, a été créé le Proof of Stake.

Contrairement au Proof of Work, cette méthode ne se base pas sur la complexité cryptographique des fonctions de hashage, mais sur une quantité de cryptomonnaie mise sous séquestre. Les mineurs mettent sous séquestre une certaine quantité de cryptomonnaie, plus on a mis d'argent sous séquestre, plus on augmente ses chances d'être choisit aléatoirement pour valider le bloc, et donc de toucher une récompense.

Le problème de ces deux systèmes, et c'est encore plus flagrant avec le Proof of Stake, est que les personnes qui peuvent investir le plus au début, les "riches", auront plus de chances d'être choisit pour valider un bloc, et donc de devenir encore plus "riche". Ce genre de système est pûrement capitaliste (fondé sur la possession d'un capital en cryptomonnaies), et donc pas forcément souhaitable 👀.

Afin d'éviter ces travers, la blockchain Polkadot a mis en place un système très intéressant appelé Nominated Proof of Stake. Avec ce système, les mineurs sont appelés validateurs, ces validateurs sont élus et ont, comme avec les autres modes de fonctionnement pour rôle de valider les différents blocs. Afin de désigner les validateurs, des nominateurs indiquent les candidats au rôle de validateur en qui ils ont confiance, et mettent sous séquestre une quantité de cryptomonnaies pour les supporter. Si un candidat qu'ils ont soutenu est élu validateur, ils reçoivent une part des gains (ou des sanctions) de ce validateur. Ce fonctionnement donne donc à chacun, riche ou pas, une voix égale, ce qui permet de rendre ce système bien moins inégalitaire. Néanmoins ce système n'est pas exempté de problèmes, un personne riche pourrait par exemple créer une multitude de comptes pour les faire voter pour lui, et remporter la mise à chaque fois mais aussi peser plus que les autres dans le processus de décision relatif à la blockchain, et donc de pouvoir changer les règles à son avantage.

Je vous invite à lire cet article pour plus d'informations

Conclusion

Pour conclure, les blockchain sont des systèmes très intéressants permettant de créer une forme de confiance numérique vérifiable par tout le monde. Cela représente donc une avancée considérable dans l'émancipation des grosses plateformes centralisées qui dominent actuellement le monde de l'informatique. Il faut néanmoins rester vigilant-es, les blockchains ne sont que des outils, il ne faut donc pas en attendre autre chose qu'un outil.

✇I Learned

Fonctionnement du démarrage d'un système Android

Les smartphones occupent une place de plus en plus importante, pour beaucoup d'usage ils remplacent même les machines de bureau plus classiques. La question de la sécurité du système embarqué dans ces machines est donc relativement importante, je vais, dans cet article, me pencher sur Android.

Démarrage d'Android

Pour bien comprendre les vecteurs d'attaques, il faut comprendre comment le système fonctionne. Le processus de démarrage est un élément indispensable au bon fonctionnement d'un système et de sa sécurité.

Lorsque le bouton "Power" est appuyé, Un code présent dans la rom est éxecuté, la ROM est l'endroit ou sont stockées les informations utiles au démarrage de l'appareil, est lancé. Ce programme est chargé d'amorcer le "bootloader", le bootloader est un programme qui se lance avant le noyau, il est chargé d'initialiser certains composants, il s'occupe aussi du lancement du noyau et de lui passer différentes options. Cette partie est comparable à l'amorçage en UEFI (ou BIOS).

Le noyau s'occupe de monter les différentes partitions et systèmes de fichiers spéciaux comme /dev pour ensuite, démarrer le système d'initialisation (init). L'init c'est le premier programme qui est lancé, il s'occupe de lancer un certain nombre de logiciels. Systemd, par exemple, est un init. Un des logiciels intéressants qui est lancé se nomme "native daemons"

Boot d'android Native daemon lance plusieurs processus dont un qui est Zygote.

Zygote est lancé dans une VM Android RunTime (ART), ART c'est la machine virtuelle android pour lancer du code Java, Zygote s'occupe de lancer un processus nommé System Server, il lance aussi d'autres processus par exemple il précharge les classes Java. ART n'est pas la seule application lancée par native daemon, native daemon permet de lancer directement en "userland" des processus.

Un processus lancé en userland signifie qu'il est lancé avec des droits utilisateur classique et sans accès avec des privilèges élevés au kernel.

Quand un utilisateur clique sur l'icone d'une application l’événement est routé vers l'Activity Manager (lancé par le system server) c'est ce service qui va gérer les permissions de l'application et la démarrer en l'isolant dans un utilisateur spécifique. Une application n'a donc pas accès au stockage des autres applications ou de l'utilisateur (sauf s'il l'a autorisé) et n'a accès qu'aux permissions que l'utilisateur lui a autorisées.

Un souci se pose maintenant, tout est proprement isolé et le minimum tourne avec des privilèges élevés, mais comment vérifier que les fichiers n'ont pas été modifiés et qu'une application est bien celle qu'elle prétend ?

Vérification du démarrage

Pour commencer, pour le processus de boot il est vérifié via une technologie nommée "Verified Boot". Verified boot est l'équivalent mobile de Secure Boot, il y existe plusieurs "état" :

  • Verrouillé
  • Verrouillé avec une chaine de clés personnalisées
  • Ouvert

Verrouillé signifie qu'il y a une vérification au démarrage des signatures cryptographique des éléments présents dans /boot, les clés peuvent être celle de base du constructeur, ou bien avec une chaine différente (l'utilisateur qui a remplacé le système par exemple). D'ailleurs c'est justement cette partie là que certains constructeurs bloque et qui empêche de modifier la ROM (c'est le cas par exemple d'huawei, xiaomi, et bien d'autre).

Procédure vérification

Le bootloader et le kernel sont tout deux signés par une clé privée et vérifié par l'ordiphone sur base d'une clé publique stockée dans une partie matérielle accessible uniquement en lecture (en réalité c'est modifiable, mais souvent il faut effectuer une action depuis le système, pour éviter qu'un attaquant modifie facilement). Verified boot permet aussi d'empêcher le "downgrade" du système vers une version précédente en notant la version actuelle dans une partie elle aussi en lecture seule, cette protection empêche notamment de profiter d'une faille présente dans une vielle version de pouvoir être exploitée.

Verified boot permet d'éviter un kernel ou bootloader corrompu, mais les partitions systèmes restent vulnérables à une modification, pour éviter ça dm-verity est utilisé. Ce mécanisme se base sur le framework Device mapper qui est directement géré par Linux (le noyau) (DM).

Device mapper permet de faire des périphériques de stockage virtuel qui peuvent avoir plusieurs propriétés spécifique, par exemple dans notre cas empêcher la lecture si le noyau détecte un bloc corrompu.

Pour vérifier que la partition n'ai pas été modifiée, il y a une vérification du bloc lu en temps réel, la vérification se base sur une arborescence de condensats.

Dm-verity hash table (source : https://source.android.com/security/verifiedboot/dm-verity)

Pour vérifier que personne n'aie modifié la table de hashs, elle est signé par une pair de clé. Cette clé est mise dans la partition boot et est elle signée par la clé utilisée pour verified boot.

Chiffrement

La partition qui contient les données utilisateurs ne peut, elle, pas être mises en lecture seule, contrairement aux partitions systèmes. Pour éviter qu'une personne puisse modifier ou lire la partition elle est donc chiffrée.

Contrairement à ce qu'on fait d'habitude, chaque fichier est chiffré au lieu d'avoir toute la partition. Les fichiers sont doncs seulement déchiffré quand ils sont lus. Le chiffrement se base sur votre système d'authentification (code pin, biométrie, etc.) comme clé. Cette clé est gardée en mémoire après avoir été tapée la première fois au démarrage du profile. Tant que le profil n'est pas déconnecté la clé reste en mémoire, c'est une source d'attaque possible (d'où l'importance d’éteindre son téléphone si on ne l'utilise pas). La consomation sur la ram ou le CPU n'est pas forcément plus important, sur du FDE on déchiffre par bloc, là ou sur du FBE on déchiffre par fichier ce qui n'est pas forcément plus lourd en RAM ou CPU.

L'avantage du FBE (file-based encryption) au lieu du FDE (full-disk encryption) est dans le cas d'une utilisation de plusieurs profiles, chaque profile aura sa clé et ne saura donc pas déchiffrer les fichiers d'un autre profile.

✇I Learned

WSL, comment ça marche ?

Depuis 2014 une nouvelle politique chez Microsoft inscrit de plus en plus l’idée OpenSource dans grand nombre de ses projets (comme .NET, PowerShell ou encore Visual Studio Code, sans oublier le rachat de github). Dans cet l’élan, Microsoft fait venir au monde WSL (pour Windows Subsystem for Linux) une capacité pour son OS de pouvoir intégrer l’écosystème de Tux. La motivation principale de Microsoft était de proposer un système permettant aux développeurs de travailler dans des conditions plus confortable sur leur système d’exploitation. Bien que les blogs et autres vidéos YouTube nous montre comment se servir de ce merveilleux outil (ou bien comment l’installer, mais je ne ferais ni l’un ni l’autre), peu explique pourtant l’essentiel : comment ça marche.

WSL1

Officiellement disponible après la mise à jour anniversaire 1607 en 2016, WSL1 a apporté de grands changements à Windows, principalement en raison de sa structure particulière. Pour émuler les commandes Linux, Windows va dans un premier temps installer deux pilotes (lxss.sys et lxcore.sys). Ces derniers vont permettre à un service nommé LXSS Manager Service de transformer les syscalls (un syscall, pour appel système étant une sorte de petite fonction qui permet la demande de réalisation d’une tâche spécifique par le système d’exploitation) Linux vers des syscalls Windows, ce qui permet, entre autre, d’utiliser bash.exe. Pour ceux qui connaissent, cela ressemble beaucoup à Cygwin mais en plus puissant et performant. Il ne s’agît donc pas d’un système de virtualisation à proprement parlé mais d’un système d’interface entre un noyau linux partiellement virtualisé et le noyau Windows (aussi connu sous le nom de Windows NT). Ainsi, il est désormais possible d’exécuter des programmes ELF sous Windows -Executable and Linkable Format, un type de fichier binaire qui s’exécute sous les systèmes Linux, sous Windows se sont des PE pour Portable Executable, il existe des variantes en fonction de l’architecture cible, x86 ou x64-. Cependant, tous les Syscalls ne sont pas implémentés notamment ceux qui concernent l’accès directe au matériel ; ce qui est la conséquence directe d’un système non-entièrement virtualisé. L’exemple le plus concret est nmap, un outil fréquemment utilisé dans les CTFs ou les pentests pour obtenir des informations sur un réseau, ou sur les ports/services d’une machine. Pour pouvoir utiliser toutes ses techniques de scans, il nécessite de faire un certain nombre d’opérations très bas niveau sur la création de paquet, et des interfaces réseaux, ce qui n’est point supporté. Une solution plausible à ce problème aurait été la virtualisation des interfaces réseaux, or comme je l’ai mentionné, WSL1 ne comporte aucune ou alors très peu de virtualisation.

Un autre problème se pose, comment faire cohabiter deux systèmes de fichiers sur un seul et même OS sans entacher l’inter-opérabilité ? La solution de Microsoft, est un système tampon constitué de deux composants, VoIFS et DriveFS. Le premier est un système qui permet le support complet des fichiers Linux, en incluant ainsi, le système de permission, les liens symboliques, les noms de fichiers qui sont en temps normaux illégaux sous Windows, et la sensibilité à la casse. Tous les dossiers Linux utilisent ce système. En revanche l’inter-opérabilité entre les applications Windows n’est pas supportée. Le second permet l’opération inverse : maintenant qu’il est possible de faire cohabiter un système Linux au sein de Windows, il faut désormais que l’environnement Windows soit accessible depuis WSL. Les disques Windows sont montés dans le traditionnel /mnt en portant leurs noms habituels (c, d, e etc). Il est très important de comprendre que le système de permission utilisé dépend de la localisation des fichiers: s’ils sont sur les disques de Windows, ce sera NTFS, s’ils sont sur WSL, ce sera le système de Linux. Par exemple, vous ne pourrez pas utiliser « chmod » sur un fichier NTFS et inversement, vous ne pourrez pas manipuler les accès des fichiers VoIFS depuis Windows car ils ne contiennent aucune structure du modèle de sécurité Windows. Par conséquent les privilèges d’accès n’auront aucun effet ! Cependant l’inverse à de l’importance, puisque bash.exe est démarré depuis Windows, il possède un token d’accès, un niveau d’intégrité (niveau de privilège accordé par l’UAC pour faire simple, ce qui différencie une simple exécution avec une exécution en tant qu’Administrateur). Il en découle que bash.exe peut créer des fichiers sur un disque NTFS en utilisant le modèle de sécurité de Windows : une DACL sera automatiquement créée grâce à DriveFS entre autre. L’utilisateur root n’a donc aucun pouvoir particulier sur le système Windows !

Côté performance, c’est assez proche d’une distribution Linux native, l’utilisation est donc très confortable. On peut résumer ce fonctionnement au travers d’un schéma :

WSL Components.webp

Ainsi, on peut voir que WSL1 apporte de grandes nouveautés, mais pose un certain nombre de problème vis à vis de son objectif premier : fournir un environnement de développement confortable pour les développeurs Linux sur Windows.

WSL2

C’est en revoyant presque intégralement la structure du noyau de WSL que Microsoft a corrigé ces problèmes. Pour commencer, finit la pseudo virtualisation du kernel (pour les plus curieux d’entre vous, le noyau Linux utilisé par WSL2 est disponible sur le github de Microsoft), et place à de la vraie virtualisation en utilisant Hyper-V, qui est le système de virtualisation Windows (ce qui offre beaucoup plus de possibilités, notamment en terme d’accès aux interfaces réseaux). Ainsi, nmap peut désormais fonctionner correctement par exemple (grâce à l’accès directe aux interfaces réseaux et aux syscalls manquant), mais la virtualisation des interfaces réseaux permet l’utilisation de VPNs (capacité qui plaît beaucoup aux joueurs de CTFs). Sauf que cette modification est drastique puisqu’il faut revoir entièrement l’interaction entre les deux systèmes. VoIFS et DriveFS sont délaissés au profit d’un disque virtuel en ext4 (type de partition qu’utilisent les systèmes Linux), et l’accès aux fichiers hôtes se fait grâce au protocole 9P, un protocole réseau qui représente des fichiers ou bien des processus d’où son utilisation pour WSL2, les disques et les accès restent identique à WSL1.

Ce changement pourrait nous inquiéter à priori concernant les performances puisque nous émulons maintenant complètement un système linux, pourtant Microsoft assure que les performances en écriture et en lecture ont été multipliés par 20. Cependant d’autres problèmes se posent, notamment quant à l’utilisation de logiciel graphique, qui n’est pour l’instant pas encore complètement et entièrement permise. En effet, pour pouvoir profiter de Firefox par exemple (depuis votre WSL), il faut installer tout un tas de dépendance comprenant un serveur XORG… et cela fonctionne. Pourtant, certains programmes utilisent les cartes graphiques non pas pour de l’affichage, mais des calculs auquel cas il n’y a aucune solution. Au vu de cette restructuration, on peut légitimement se demander ce qui diffère entre WSL2 et une machine virtuelle classique. Dans le premier cas, il s’agît d’une virtualisation hyperviseur de type 1, le second cas de type 2 (un hyperviseur étant : "une plateforme de virtualisation qui permet à plusieurs systèmes d’exploitation de travailler sur une même machine physique").

WSL%20600860b78c8340a9ad0af71995076696/image2.webp

La différence est donc majeure, WSL2 s’exécute directement sur le matériel de votre machine là où une machine virtuelle standard à besoin d’un autre hôte pour son exécution. Cela permet une chose, des performances accrues et donc une utilisation plus confortable. De plus, puisque WSL2 se base sur un hyperviseur de type 1, plus votre machine est puissante, plus votre machine WSL2 sera puissante dans l’instant, contrairement à une VM classique où il faut spécifier les quantités de matériel à utiliser.

L’article touche à sa fin, et j’espère avoir fait la lumière sur les éventuelles zones d’ombres au sujet de WSL !

✇I Learned

La puce TPM, quelle est son utilité ?

Il y a moins d'un mois Microsoft annonçait officiellement Windows 11. Cette nouvelle version à fait débat, et pour cause, beaucoup (trop) d'appareils sont incompatibles avec cette version de Windows, une des raisons avancées par Microsoft est le support manquant de TPM 2.0. Mais au fond, Qu'est ce que TPM et quels sont les changements apporté par la deuxième version de TPM.

TPM est l'acronyme de "Trusted Platform Module", c'est une puce qui permet de faire des opérations cryptographiques, ou de garder des secrets.

Cette puce est principalement faite pour générer des clés RSA – RSA est un algorithme de cryptographie asymétrique – stocker ces clés et gérer l'accès à ces dites clés. Cette puce est aussi utilisée pour Secure Boot.

Une puce TPM possède une clé RSA qui permet de l'authentifier, cette clé ne peut en théorie pas sortir de la puce.

Un des usages principaux de TPM est de stocker différents secrets, pour par exemple chiffrer un disque avec une technologie comme BitLocker sous Windows, ou Luks sous Linux. La sécurité du stockage de la clé pourrait poser question, comment s'assurer qu'un autre système ne puisse pas avoir accès a la clé de déchiffrement ? Afin d'améliorer la sécurité de cette puce, on peut configurer un PIN à entrer pour accéder à la clé de déchiffrement.

Si la clé n'est pas protégée par un PIN, la puce laissera quand même l'accès uniquement au système qui a crée la clé, même si dans certains cas particulier la vérification ne se fait pas correctement.

Comme faille de sécurité dans TPM on peut notamment citer TPM-FAIL qui permet simplement d'extraire la clé privée. Un autre problème de sécurité que présente TPM est qu'avec un accès physique il est possible d'espionner ce que la puce fait et donc d'en extraire des données confidentielles, si vous souhaitez en savoir plus, la page Wikipedia sur TPM cite d'autres failles de sécurité : https://en.wikipedia.org/wiki/Trusted_Platform_Module#Attacks.

Un autre problème de TPM qui est très répandu c'est le vecteur d'attaque physique, en observant directement sur les bus de la puce avec du matériel spécifique il est possible d'extraire les clés de la puce, ce type d'attaque se nomme cold boot atttack.

La puce TPM est divisée en plusieurs partie qu'on nomme des Platform configuration Registers qui ont plusieurs utilité, comme le stockage de clé, firmware etc.

TPM a connu des évolutions, je vais me concentrer ici seulement sur la version 1.2 et 2 de TPM. Une des avancées majeure est l'implémentation des courbes elliptiques sur la version 2, les algorithmes de chiffrement à courbe elliptique sont des algorithmes de cryptographie asymétrique, concurrents à RSA notamment, qui au lieu d'utiliser les nombres premiers utilisent des courbes elliptiques, l'avantage comparé à RSA c'est leur résistance supposée aux ordinateurs quantiques. Une autre avancée est le support de SHA256 qui est bien plus résistant que SHA1 à différent type d'attaque.

À mon avis, le fait pour Windows 11 de forcer TPM est relativement inutile, en effet BitLocker n'est pas activé par défaut, et Secure Boot ne dépends pas forcément de TPM. Le mieux serait de recommander sans pour autant forcer. TPM reste très intéressant pour éviter de taper un mot de passe au boot, qui en plus de prendre du temps peut être vu par un attaquant, et permettre de vérifier l’intégrité du démarrage en séparant la gestion des clés du bios (l'avantage est que pour changer le jeu de clés publiques il faut effacer la clé de déchiffrement). Un des soucis les plus important de TPM reste que la plupart des implémentations ne sont pas libres, une backdoor pourrait donc y être inséré par le constructeur.

Une alternative à TPM peut être des puces plus spécifique comme la puce titan de google, ou T2, mais ces deux puces restent malheureusement propriétaires.

✇I Learned

Comment faire une autorité de certification (CA) SSH ?

SSH est un protocole très répandu sur internet, il est utilisé par des millions d'entreprises et particuliers chaque jour, mais bien souvent de façon peu sécurisée. Vous connaissez peut-être les clés SSH qui permettent une meilleure sécurité que les mots de passe, mais ces clés posent un problème, et notamment en entreprise, imaginez une entreprise avec 500 ingénieurs, il faudrait, sur chaque serveur SSH, mettre les 500 clés publiques des 500 ingénieurs ! Pour remédier à cela il existe une solution que nous allons étudier dans cet article, les autorités de certification SSH.

La théorie

Le système de certificats de SSH est relativement similaire à celui de TLS (x509), une première paire de clés publiques/privées est générée, elle servira d'autorité de certification, le clé privée de cette autorité de certification doit bien évidemment rester ultra confidentielle. On va ensuite générer une autre paire de clé sur chaque client. On pourra ensuite, avec la clé privée de notre autorité de certification, signer la publique des clients afin de générer un certificat. Ainsi, n'importe quel certificat signé par notre autorité de certification peut être considérée comme "de confiance".

Principe d'une autorité de certification

Signer les clés hôte

Lors de la première connexion à un serveur SSH, le serveur envoie sa clé publique (appelée clé hôte) au client et le client doit approuver, ou non, l'authenticité de la clé envoyée par le serveur, c'est le fameux message

The authenticity of host 'XXXXX' can't be established.
ED25519 key fingerprint is SHA256:JxfJl38mBVY2jX0h/LWDuB1OtgYfgLBr3nJw/lw5GFE.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Nous avons tous pour (mauvaise) habitude de simplement entrer yes sans se poser plus de questions, mais cette habitude est très dangereuse, un attaquant pourrait usurper le serveur SSH auquel nous essayons de nous connecter ! Pour remédier à cela il existe plusieurs solutions comme SSHFP (qui est relativement similaire à TLSA, mais avec SSH) ou les autorités de certification (CA) c'est ce que nous allons détailler ici.

La première étape est donc de créer une paire de clés pour notre autorité de certification avec la commande

ssh-keygen -a 1000 -t ed25519 -f /etc/ssh/ca/id_ed25519 -C "contact+ca@eban.bzh"

L'option -a indique le nombre de tours KDF (fonction de dérivation de la clé), plus ce nombre est élevé, plus la vérification du mot de passe sera lente, mais plus la clé sera résistante au bruteforce.

-t indique l'algorithme à utiliser pour la clé, ici c'est ed25519, l'algorithme de chiffrement le plus sécurisé à ce jour supporté par SSH.

Une fois cette première paire de clé créée, nous allons pouvoir l'utiliser pour signer les clés hôtes publiques de nos serveurs SSH, la première étape est donc d'aller cherche ces clés hôtes, elles sont, sur chaque serveur SSH, dans le répertoire /etc/ssh, ici je ne génèrerait qu'un certificat en ed25519 mais la même démarche est possible avec n'importe quel algorithme supporté par OpenSSH. La clé publique hôte est donc disponible sous le chemin /etc/ssh/ssh_host_ed25519_key.pub copions-là dans le répertoire /etc/ssh/ca de la machine sur laquelle nous avons généré l'autorité de certification. On peut ensuite lancer la commande

ssh-keygen -h -s /etc/ssh/ca/id_ed25519 -n pi01,pi01.infra.eban.bzh -I pi01 -V +3650d ssh_host_ed25519_key.pub

L'option -n correspond aux principals, dans le cas d'une clé hôte, elle doit correspondre aux différents noms de domaine auxquelles la clé pourrait être associée.

-I correspond à l'ID, un identifiant unique attribué à la clé, c'est simplement son "nom".

Une fois la clé publique signée, il ne nous reste plus qu'à copier le certificat qui aura été généré dans le répertoire /etc/ssh/ca/ssh_host_ed25519_key-cert.pub sur le serveur SSH (ici nous le mettrons à l'emplacement /etc/ssh/ssh_host_ed25519_key-cert.pub) et à ajouter la ligne suivante à la fin du fichier /etc/sshd_config.

HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub

On redémarre ensuite le démon ssh avec la commande systemctl restart sshd.

Dernière étape, on va indiquer à tous les clients SSH de faire confiance aux certificats hôtes signés par notre autorité de certification en utilisant la commande

echo "@cert-authority * $(cat /etc/ssh/ca/id_ed25519.pub)" >> ~/.ssh/known_hosts

Et voilà ! Notre autorité de certification est maintenant configurée sur le serveur SSH.

Signer les clés clients

La procédure pour signer les clés des clients est relativement similaire, après avoir généré une paire de clés pour l'autorité de certification (on gardera la même que celle générée dans la partie précédente), on lance la commande

ssh-keygen -s /etc/ssh/ca/id_ed25519 -n pi -I pc01@eban.bzh -V +30d -z 1 /home/USERNAME/.ssh/id_ed25519.pub

N'oubliez pas de changer USERNAME par votre nom d'utilisateur.

Si vous obtenez une erreur, c'est probablement que n'avez pas déjà une paire de clé SSH en ed25519 vous pouvez en générer une avec la commande

ssh-keygen -t ed25519

Une fois la paire de clé générée, vous pouvez relancer la première commande.

Ici l'option -n correspond au⋅x nom⋅s d'utilisateur distant (= sur le serveur SSH) pour lesquels vous souhaitez autoriser que cette clé soit valide, cette clé ne sera donc valide que pour le nom d'utilisateur distant pi.

-z correspond au serial de ce certificat, c'est un nombre que vous devrez incrémenter si vous régénérez la clé après la durée d'expiration (ici mise à 30 jours).

Une fois cela fait, il ne nous reste plus qu'à copier la clé publique de notre autorité de certification (contenue dans /etc/ssh/ca/id_ed25519.pub) sur notre serveur SSH, ici nous la mettrons dans le fichier /etc/ssh/ca.pub et à ajouter la ligne TrustedUserCAKeys /etc/ssh/ca.pub à la fin du fichier /etc/ssh/sshd_config. On termine par redémarrer le service SSH, sudo systemctl restart sshd.

Nous avons maintenant mit en place notre autorité de certification ! On peut simplement la tester en se connectant via SSH au serveur, vous ne devriez pouvoir vous connecter sans mot de passe et n'avoir aucune demande de validation de la clé publique de la machine hôte. J'espère que cet article vous aura été utile, si vous avez des questions n'hésitez pas à nous les poser en commentaire ou sur Twitter.

❌