Bac à sable de sécurité dans Chromium

La sécurité est un objectif fondamental pour Chromium. Assurer la sécurité d'un système nécessite une compréhension complète de ses comportements face à toutes les combinaisons d'entrées possibles dans tous les états possibles. Pour une base de code aussi vaste et diverse que celle de Chromium, le raisonnement sur le comportement combiné de toutes ses parties est pratiquement irréalisable. Le bac à sable (sandbox) a pour objectif de fournir des garanties strictes sur ce qu'un morceau de code peut ou ne peut pas faire, quelles que soient ses entrées.

Le bac à sable exploite les mécanismes de sécurité fournis par le système d'exploitation pour permettre l'exécution de code sans modifications persistantes sur l'ordinateur ni accès aux informations confidentielles. L'architecture et les assurances exactes fournies par le bac à sable dépendent du système d'exploitation. Ce document couvre l'implémentation Windows ainsi que la conception générale. Les implémentations Linux et macOS sont décrites ailleurs.

Principes de conception

  • Ne pas réinventer la roue : Il peut être tentant d'étendre le noyau du système d'exploitation avec un meilleur modèle de sécurité. Il faut éviter de le faire. Il convient de laisser le système d'exploitation appliquer sa sécurité aux objets qu'il contrôle. Cependant, il est permis de créer des objets au niveau de l'application (abstractions) possédant un modèle de sécurité personnalisé.
  • Principe du moindre privilège : Ce principe doit s'appliquer aussi bien au code s'exécutant dans le bac à sable qu'au code qui le contrôle. Le bac à sable doit fonctionner même si l'utilisateur ne peut pas élever ses privilèges vers le super-utilisateur.
  • Considérer le code du bac à sable comme malveillant : Dans le cadre de la modélisation des menaces, le code est considéré comme compromis (c'est-à-dire exécutant du code malveillant) une fois que le chemin d'exécution dépasse les premiers appels dans la fonction main(). En pratique, cela peut survenir dès la première entrée externe acceptée, ou juste avant l'entrée dans la boucle principale.
  • Être réactif : Le code non malveillant n'essaie pas d'accéder aux ressources qu'il ne peut pas obtenir. Dans ce cas, le bac à sable doit imposer un impact sur les performances quasi nul. Il est acceptable d'avoir des pénalités de performance pour les cas exceptionnels où une ressource sensible doit être touchée une seule fois de manière contrôlée. C'est généralement le cas lorsque la sécurité du système d'exploitation est crorectement utilisée.
  • L'émulation n'est pas la sécurité : Les solutions d'émulation et de machines virtuelles ne fournissent pas, par elles-mêmes, la sécurité. Le bac à sable ne doit pas s'appuyer sur l'émulation de code, la traduction de code ou le patching pour assurer la sécurité.

Architecture du bac à sable Windows

Le bac à sable Windows est un bac à sable en mode utilisateur uniquement. Il n'y a pas de pilotes spéciaux en mode noyau, et l'utilisateur n'a pas besoin d'être administrateur pour que le bac à sable fonctionne correctement. Il est conçu pour les processus 32 bits et 64 bits et a été testé sur toutes les variantes de Windows entre Windows 7 et Windows 10.

Le bac à sable opère à la granularité du processus. Tout ce qui doit être isolé doit s'exécuter dans un processus distinct. La configuration minimale comprend deux processus : un contrôleur privilégié appelé le broker (courtier), et un ou plusieurs processus isolés appelés la cible. Le bac à sable est fourni sous forme de bibliothèque statique qui doit être liée aux exécutables du broker et de la cible.

Le processus broker

Dans Chromium, le broker est toujours le processus du navigateur. Il agit en termes généraux comme un contrôleur/superviseur privilégié des activités des processus isolés. Ses responsabilités sont :

  1. Définir la politique pour chaque processus cible
  2. Générer les processus cibles
  3. Héberger le service du moteur de politique du bac à sable
  4. Héberger le gestionnaire d'interception du bac à sable
  5. Héberger le service IPC (Inter-Process Communication) du bac à sable vers les processus cibles
  6. Exécuter les actions autorisées par la politique au nom du processus cible

Le broker doit toujours survivre à tous les processus cibles qu'il a générés. L'IPC du bac à sable est un mécanisme bas niveau (différent de l'IPC de Chromium) utilisé pour transférer de manière transparente certains appels d'API Windows de la cible vers le broker : ces appels sont évalués par rapport à la politique. Les appels autorisés sont alors exécutés par le broker et les résultats renvoyés au processus cible via le même IPC. Le travail du gestionnaire d'interception est de patcher les appels d'API Windows qui doivent être acheminés via IPC vers le broker.

Le processus cible

Dans Chromium, les moteurs de rendu sont toujours des processus cibles, à moins que l'option de ligne de commande --no-sandbox ait été spécifiée pour le processus du navigateur. Le processus cible héberge tout le code qui s'exécutera à l'intérieur du bac à sable, plus l'infrastructure côté client du bac à sable :

  1. Tout le code à isoler
  2. Le client IPC du bac à sable
  3. Le client du moteur de politique du bac à sable
  4. Les interceptions du bac à sable

Les points 2, 3 et 4 font partie de la bibliothèque du bac à sable qui est liée au code à isoler. Les interceptions (également appelées hooks) sont la manière dont les appels d'API Windows sont acheminés via l'IPC du bac à sable vers le broker. Il revient au broker de réémettre les appels d'API et de renvoyer les résultats, ou simplement d'échouer les appels. Le mécanisme d'interception + IPC ne fournit pas la sécurité ; il est conçu pour offrir une compatibilité lorsque le code à l'intérieur du bac à sable ne peut pas être modifié pour faire face aux restrictions du bac à sable. Pour éviter des IPC inutiles, la politique est également évaluée dans le processus cible avant de passer un appel IPC, bien que cela ne soit pas utilisé comme garantie de sécurité mais uniquement comme une optimisation de la vitesse.

Restrictions du bac à sable

À son noyau, le bac à sable s'appuie sur la protection fournie par quatre mécanismes Windows :

  • Un jeton (token) restreint
  • L'objet Job Windows
  • L'objet desktop (bureau) Windows
  • Les niveaux d'intégrité (à partir de Windows Vista)

Ces mécanismes sont hautement efficaces pour protéger le système d'exploitation, sa configuraton et les données de l'utilisateur, à condition que :

  • Toutes les ressources sécurisables aient un descripteur de sécurité non nul.
  • L'ordinateur ne soit pas déjà compromis par un logiciel malveillant.
  • Le logiciel tiers n'affaiblisse pas la sécurité du système.

Le jeton (Token)

La forme la plus restrictive d'un jeton sous Windows XP pour le bac à sable de Chromium comprend :

Groupes réguliers

  • SID de connexion : obligatoire
  • Tous les autres SIDs : refus seulement, obligatoire

Groupes restreints

  • S-1-0-0 : obligatoire

Privilèges

  • Aucun

Avec les conditions décrites, il est pratiquement impossible de trouver une ressource existante à laquelle le système d'exploitation accordera l'accès avec un tel jeton. Sous Vista, le jeton le plus restrictif est le même mais inclut également l'étiquette de niveau d'intégrité bas. Le moteur de rendu de Chromium s'exécute normalement avec ce jeton.

Par conception, le jeton du bac à sable ne peut pas protéger les ressources non sécurisables suivantes :

  • Les volumes FAT ou FAT32 montés : leur descripteur de sécurité est effectivement nul.
  • TCP/IP : La sécurité des sockets TCP/IP sous Windows 2000 et Windows XP (mais pas sous Vista) est effectivement nulle.

L'objet Job

Le processus cible s'exécute également sous un objet Job. À l'aide de ce mécanisme Windows, certaines restrictions globales intéressantes sont appliquées :

  • Interdire les modifications globales au système par utilisateur via SystemParametersInfo()
  • Interdire la création ou le changement de bureaux
  • Interdire les modifications de la configuration d'affichage par utilisateur
  • Pas de lecture ni d'écriture dans le presse-papiers
  • Interdire la diffusion de messages Windows
  • Interdire la définition de hooks globaux Windows (via SetWindowsHookEx())
  • Interdire l'accès à la table des atomes globaux
  • Interdire l'accès aux handles USER créés en dehors de l'objet Job
  • Limite d'un seul processus actif (interdit la création de processus enfants)

À l'aide de l'objet Job, le bac à sable peut également empêcher :

  • Une utilisation excessive des cycles CPU
  • Une utilisation excessive de la mémoire
  • Une utilisation excessive des E/S

Le bureau alternatif

Le jeton et l'objet Job définissent une limite de sécurité. Cependant, un fait peu compris est que les applications ayant des fenêtres sur le même bureau sont également dans le même contexte de sécurité, car l'envoi et la réception de messages de fenêtre ne sont soumis à aucune vérification de sécurité. L'envoi de messages entre bureaux n'est pas autorisé.

Dans une installation Windows standard, au moins deux bureaux sont attachés à la station de fenêtres interactive. Le bac à sable crée un troisième bureau associé à tous les processus cibles. Ce bureau n'est jamais visible ou interactif et isole efficacement les processus isolés de l'espionnage de l'interaction de l'utilisateur et de l'envoi de messages à des fenêtres fonctionnant dans des contextes plus privilégiés.

Les niveaux d'intégrité

Les niveaux d'intégrité sont disponibles sur Windows Vista et versions ultérieures. Ils ne définissent pas une limite de sécurité au sens strict, mais fournissent une forme de contrôle d'accès obligatoire (MAC). Les niveaux sont implémentés sous forme d'un ensemble spécial de SID et d'entrées ACL représentant cinq niveaux de privilèges croissants : non fiable, bas, moyen, élevé, système. Par défaut, un jeton peut lire un objet d'un niveau d'intégrité plus élevé, mais pas y écrire.

Par exemple, un jeton en mode d'intégrité bas ne peut accéder qu'aux ressources partagées suivantes :

  • Accès en lecture à la plupart des fichiers
  • Accès en écriture à %USERPROFILE%\\AppData\\LocalLow
  • Accès en lecture à la plupart des registres
  • Accès en écriture à HKEY\_CURRENT\_USER\\Software\\AppDataLow
  • Presse-papiers (copier et coller pour certains formats)
  • Appels de procédure distante (RPC)
  • Sockets TCP/IP

Le niveau d'intégrité peut être redondant avec d'autres mesures, mais il constitue un degré supplémentaire de défense en profondeur, sans impact visible sur les performances ou l'utilisation des ressources.

Politiques d'atténuation des processus

La plupart des politiques d'atténuation des processus peuvent être appliquées au processus cible au moyen de SetProcessMitigationPolicy. Le bac à sable utilise cette API pour définir diverses politiques.

Exemples de politiques appliquées :

  • Relocalisation des images (ASLR) : Pour Windows 8 et ultérieur, randomisation de l'espace d'adressage sur toutes les images du processus.
  • Arrêt sur corruption du tas (Heap) : Pour Windows 8 et ultérieur, termine le processus en cas de corruption du tas Windows.
  • ASLR ascendant à haute entropie : Pour Windows 8 et ultérieur, augmente la plage de randomisation de l'ASLR ascendant à 1 To.
  • Vérifications strictes des handles : Pour Windows 8 et ultérieur, lève immédiatement une exception sur une référence à un handle incorrect.
  • Verrouillage de Win32k.sys : Pour Windows 8 et ultérieur, via ProcessSystemCallDisablePolicy, désactive sélectivement les appels système disponibles pour le processus cible. Les processus de rendu ont désormais cela défini pour interdire les appels système Win32k, réduisant ainsi la surface d'attaque du noyau.
  • Conteneur d'application (jeton Low Box) : Pour Windows 8 et ultérieur, ajoute les attributs Low Box au jeton restreint existant, sans accorder de capacités, afin d'obtenir la protection supplémentaire d'aucun accès réseau à partir du processus isolé.
  • Désactivation des points d'extension (hooking hérité) : Pour Windows 8 et ultérieur, bloque certains vecteurs d'injection comme les DLL AppInit, les LSP Winsock, les hooks globaux de fenêtre, etc.
  • Control Flow Guard (CFG) : Pour Windows 8.1 Update 3 et ultérieur, activé dans tous les processus chrome.exe.
  • Désactivation du chargement de polices : Pour Windows 10 et ultérieur.
  • Désactivation du chargement d'images depuis des périphériques distants : Pour Windows 10 TH2 et ultérieur.
  • Désactivation supplémentaire de la création de processus enfants : Pour Windows 10 TH2 et ultérieur, si le niveau de Job est inférieur ou égal à JOB\_LIMITED\_USER, définit l'attribut correspondant.

Autres mises en garde

Le système d'exploitation peut avoir des bogues. Les bogues dans l'API Windows permettant de contourner les vérifications de sécurité régulières sont d'un intérêt particulier. Si un tel bogue existe, un logiciel malveillant pourra contourner les restrictions du bac à sable et la politique du broker.

De plus, les logiciels tiers, en particulier les solutions anti-malware, peuvent créer de nouveaux vecteurs d'attaque. Les plus problématiques sont les applications qui injectent des DLL pour activer une capacité (généralement non désirée). Ces DLL seront également injectées dans le processus du bac à sable.

Politique du bac à sable

Les restrictions appliquées à un processus cible sont configurées par une politique. La politique est une interface programmatique que le broker appelle pour définir les restrictions et les autorisations. Quatre fonctions contrôlent les restrictions :

  • TargetPolicy::SetTokenLevel()
  • TargetPolicy::SetJobLevel()
  • TargetPolicy::SetIntegrityLevel()
  • TargetPolicy::SetDesktop()

Les trois premières appels prennent un paramètre de niveau entier allant de très strict à très souple. Par exemple, le niveau de jeton a 7 niveaux et le niveau de job a 5 niveaux. La politique de bureau est binaire et ne peut être utilisée que pour indiquer si une cible s'exécute sur un bureau alternatif ou non.

L'interface de politique permet au broker de spécifier des exceptions. Une exception est un moyen de prendre un appel d'API Windows spécifique émis dans la cible et de le transférer par proxy au broker. Le broker peut inspecter les paramètres et réémettre l'appel tel quel, le réémettre avec des paramètres différents, ou simplement le refuser. Pour spécifier des exceptions, il y a un seul appel : AddRule. Les types de règles suivants pour différents sous-systèmes Windows sont pris en charge :

  • Fichiers
  • Tubes nommés
  • Création de processus
  • Registre
  • Objets de synchronisation

Exemple de règle pour les fichiers :

AddRule(SUBSYS_FILES, FILES_ALLOW_READONLY, L"c:\\temp\\logs\\d*.log")

Cette règle spécifie que l'accès sera accordé si une cible souhaite ouvrir un fichier, en accès en lecture seule, à condition que le fichier corresponde à l'expression de modèle.

Démarrage (Bootstrap) de la cible

Les cibles ne commencent pas à s'exécuter avec les restrictions spécifiées par la politique. Elles commencent avec un jeton très proche du jeton des processus utilisateur réguliers. La raison en est que pendant le démarrage du processus, le chargeur du système d'exploitation accède à de nombreuses ressources, dont la plupart sont non documentées et peuvent changer à tout moment.

Par conséquent, pendant la phase de démarrage, le processus utilise en fait deux jetons : le jeton de verrouillage (lockdown token), qui est le jeton de processus tel quel, et le jeton initial, qui est défini comme jeton d'impersonnification du thread initial. La définition réelle de SetTokenLevel est :

DefinirNiveauJeton(NiveauJeton initial, NiveauJeton verrouillage)

Après l'initialisation critique, l'exécution se poursuit à main() ou WinMain(). Ici, les deux jetons sont toujours actifs, mais seul le thread initial peut utiliser le jeton initial plus puissant. Il est de la responsabilité de la cible de se débarrasser du jeton initial lorsqu'elle est prête. Cela se fait avec un seul appel :

AbaisserJeton()

Après cet appel, le seul jeton disponible est le jeton de verrouillage et les restrictions complètes du bac à sable entrent en vigueur. Les effets de cet appel sont irréversibles. Il convient de s'assurer que tous les handles sensibles du système d'exploitation obtenus avec le jeton initial sont fermés avant d'appeler AbaisserJeton(). Tout handle fuité peut être exploité par un logiciel malveillant pour s'échapper du bac à sable.

Étiquettes: Sécurité Chromium bac-à-sable Windows jeton

Publié le 28 juin à 18h47