Visual Studio Code est selon un sondage de Stack Overflow l’IDE le plus apprécié, il a fait l’objet de recherche de sécurité et a pu être un vecteur de compromission. Cet article détaille succinctement les recherches faites par d’autres sur cet IDE, présente le modèle de confiance de l’IDE, et décris les conséquences potentielles d’une trop grande confiance dans les dossiers ouverts.

Note : Cet article est aussi disponible en anglais 🇬🇧.

Vulnérabilités découvertes

Des recherches ont déjà permis de trouver plusieurs vulnérabilités, à la fois sur l’éditeur, mais aussi sur les extensions mises à disposition sur le marketplace de Microsoft.

Des vulnérabilités critiques ont ainsi été trouvées, pour en citer quelques exemples :

Une liste plus complète des vulnérabilités affectant VS Code est disponible ici. Comme visible sur cette liste, de nombreuses vulnérabilités récentes (avril 2023 pour la dernière RCE) sont remontées et peuvent être utilisées par des acteurs malveillants afin de compromettre des postes de développeur.

Extension – Vecteur d’attaque connu

Comme de nombreux éditeurs de texte, VS Code dispose d’un grand nombre d’extensions activement utilisées, ces dernières peuvent faire l’objet de vulnérabilité, mais des extensions malveillantes sont aussi utilisées pour compromettre des utilisateurs. L’avantage de ce vecteur de compromission est qu’une fois l’extension installée, le mode restreint (voir plus bas) n’empêche pas les actions malveillantes de l’extension.

Avant publication sur le marketplace, Microsoft réalise un scan antiviral sur l’extension. Puis, en cas de report d’application malveillante, Microsoft effectue une vérification et supprime ladite extension. L’extension est blacklistée afin que les éditeurs l’ayant déjà installée la supprime. Des informations sur l’extension et son développeur sont aussi affichées afin d’avoir confiance en l’extension.

Référence : Can I trust extensions from the Marketplace?.

Ces précautions ne sont toutefois pas toujours suffisantes. En janvier 2023, l’équipe de recherche Aqua Nautilus a découvert qu’il était aisé de créer et de publier une extension malveillante imitant une existante. Pour démontrer les potentialités de ce vecteur d’attaque, ils ont réalisé un PoC en déposant une imitation d’une extension populaire. En 48h leur extension "malveillante" a été installée un millier de fois à travers le monde.

En mai 2023, c’est Check point, via leur produit CloudGuard Spectral, qui a découvert une utilisation active d’extension malveillante ayant été téléchargées ~45k fois.

L’extension Prettier-Java a ainsi été imitée par une extension malveillante prettiest java qui dérobait les données à caractères personnelles des utilisateurs.

Exploitation de la configuration

Jusqu’ici, les exploitations présentées abusent de la confiance des utilisateurs en des extensions ou des vulnérabilités découvertes dans l’éditeur ou les extensions installées.

Dans tous les cas, l’attaque a besoin que l’utilisateur installe une extension ou ouvre des fichiers malveillants.

La question est donc de savoir si en l’absence de vulnérabilité ou d’extension malveillante des risques subsistent et lesquels ?

Mode restreint et workspace

Avant de détailler les mauvaises configurations ou les abus de confiance possible, il est important de parler du workspace trust (confiance dans l’espace de travail), le modèle de confiance de VS Code.

Depuis la version 1.57, la fonctionnalité workspace trust a été ajoutée pour adresser la CVE-2021-34529 (une RCE). Le workspace trust défini un mode restreint qui désactive un certain nombre de fonctionnalités et de configuration au sein d’un workspace tant que l’utilisateur n’indique pas explicitement que le workspace est de confiance.

Un workspace est la collection d’un ou plusieurs dossiers qui sont ouverts dans une fenêtre VS Code (instance). Dans la plupart des cas, un seul dossier est ouvert en tant qu’espace de travail. L’ouverture d’un workspace dont le dossier n’est pas un dossier approuvé ou un sous-dossier d’un dossier approuvé verra s’ouvrir cette fenêtre :

Demande de confiance à l'ouverture d'un workspace

La configuration d’un workspace est définie dans le fichier .vscode/settings.json de la racine du dossier pour un workspace simple. Pour les workspaces multi-dossiers un fichier avec l’extension .code-workspace porte la configuration. Les formats de ces fichiers sont les suivants :

// settings.json pour la configuration globale ou le workspace
{
  "<setting>":"valeur"
}

// <workpsace>.code-workspace pour la configuration du multi-root workspace
{
  "folders": [{"path": "."}],
  "settings": {
    "<setting>":"valeur"
  }
}

D’un point de vue offensif, la configuration pour le multi-root workspace a moins de chance d’être appliquée car l’utilisateur doit explicitement ouvrir le workspace multi-dossier.

La configuration d’un workspace vient écraser la configuration globale usuellement stockée ici :

  • Windows : %APPDATA%\Code\User\settings.json
  • macOS : $HOME/Library/Application\ Support/Code/User/settings.json
  • Linux : $HOME/.config/Code/User/settings.json

Le mode restreint, permet donc de bloquer un certain nombre de fonctionnalités et configuration dont les plus dangereuses seront détaillées par la suite.

Pour visualiser l’ensemble des configurations bloquées, on peut utiliser le tag @tag:requireTrustedWorkspace dans la recherche du menu des configurations :

Recherche des configurations désactivées en mode restreint

Il est à noter qu’indépendamment du mode restreint, certaines options de configuration ne sont pas supportées dans un workspace pour des raisons de sécurité, car elles changent le chemin d’exécutables :

  • git.path
  • terminal.external.windowsExec
  • terminal.external.osxExec
  • terminal.external.linuxExec

Tâches

Les tâches permettent de programmer des actions par exemple pour le build d’un projet. Elles sont désactivées en mode restreint. Des tâches par défaut existent, mais il est possible de configurer des tâches personnalisées.

De plus, l’option de configuration "task.allowAutomaticTasks": "on" permet l’exécution automatique des tâches selon leur condition.

Nous avons donc les conditions qui permettent une exécution automatique de code si un utilisateur ouvre un dossier malveillant hors du mode restreint :

  • Créer un fichier de configuration de workspace .vscode/settings comme suivant :
{
  "task.allowAutomaticTasks": "on",
}
  • Créer une tâche custom dans le fichier .vscode/tasks.json à la racine du workspace, comme suivant :
{
  "version": "2.0.0",
  "tasks": [{
    "label": "Tâche malveillante",
    "type": "shell",
    "osx": {
      "command": "<payload>",
    },
    "linux": {
      "command": "<payload>",
    },
    "windows": {
      "command": "<payload>"
    },
    // cache le terminal
    "presentation": {
      "reveal": "silent" // ou "never"
    },
    "runOptions": {
      "runOn": "folderOpen"
    },
  }]
}

À l’ouverture du dossier contenant ces fichiers, la tâche sera exécutée automatiquement et déclenchera la charge utile contenu dans l’attribut command en fonction du système d’exploitation cible (osx, windows ou linux). La valeur de l’attribut command doit contenir la commande complète avec ces arguments, car la tâche s’exécute dans un shell, comme spécifié dans l’attribut "type": "shell".

Mais, il est aussi possible de lancer un processus hors d’un shell. Dans ce cas la commande sera de la forme suivante :

"linux": {
  "command": "<chemin vers binaire>",
  "args": [
    "arg1", "arg2"
  ]
},

Enfin, la tâche peut être associée à un groupe, notamment le type build, ce qui l’exécutera si l’utilisateur utilise le raccourci Ctrl+Shift+B. Pour cela l’option suivante doit être ajoutée au fichier tasks.json dans une tâche :

"group": {
  "kind": "build",
  "isDefault": true
}

Débogage

VS Code propose des fonctionnalités de débogage, l’IDE inclut par défaut le débogage pour Node.js et les langages transposés en JS (TypeScript par ex.). En mode restreint le débogage n’est pas autorisé.

Les infos de débogage sont spécifiées dans le fichier .vscode/launch.json pour un workspace. Le débogage se lancera si un utilisateur utilise le raccourci F5 ou le lance depuis les menus concernés.

L’utilisation légitime du débogueur ici ne nous intéresse pas. La documentation de Microsoft détaille toutefois son utilisation.

Les options de débogage changeront d’un débogueur à l’autre, mais certaines options doivent obligatoirement être implémentées :

  • type : le type de débogueur à utiliser. Chaque extension de débogueur installée introduit un type : node pour le débogueur Node.JS intégré, par exemple, ou php pour l’extension PHP.
  • request : le type de demande. launch et attach sont les types supportés.
  • name : le nom personnalisé, affiché dans le menu de débogage.

De plus, des attributs optionnels sont utilisables pour tous les débogueurs.

L’attribut preLaunchTask permet de spécifier une tâche à lancer avant le début de la session de débogage. Cet attribut est intéressant, car il ne perturbe pas le fonctionnement normal du débogueur.

La configuration suivante, dans un fichier .vscode/launch.json, permet de lancer la tâche test avant la session de débogage :

{
    "version": "0.2.0", "configurations": [{
        "name": "Node malicious debug",
        "type": "node",
        "request": "launch",
        "preLaunchTask": "test",
    }]
}

La tâche configurée peut ensuite lancer une commande comme vu dans la partie Tâches de cet article.

L’attribut runtimeExecutable est aussi présent pour de nombreux débogueurs et permet de spécifier le chemin de l’exécutable afin d’obtenir une exécution de code lors du débogage. La variable ${workspaceFolder} indique que le dossier utilisé est celui du workspace, permettant de spécifier un exécutable de notre choix.

Ci-dessous, l’exemple d’une configuration utilisant cette option :

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Node malicious debug",
      "type": "node",
      "request": "launch",
      "windows": {
      "runtimeExecutable": "${workspaceFolder}/test.ps1"
    },
    "osx": {
      "runtimeExecutable":"${workspaceFolder}/test.sh"
    },
    "linux": {
      "runtimeExecutable":"${workspaceFolder}/test.sh"
    },
      // cache la console
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

L’attribut internalConsoleOptions permet de ne pas afficher la console ce qui indiquerait l’exécution de notre programme.

Modification de l’environnement

Dans la configuration du workspace, l’attribut terminal.integrated.env.linux permet de modifier les variables d’environnement sur un système Linux. Il serait ainsi possible de modifier la variable PATH pour contrôler les exécutables lancés depuis le terminal intégré : "terminal.integrated.env.linux": {"PATH":"valeur"}.

Cela suppose que le workspace ne soit pas en mode restreint et que le terminal intégré soit utilisé.

Conclusion

Pour conclure, le vecteur d’attaque privilégié pour compromettre les utilisateurs de l’IDE semble avoir été l’installation d’extensions malveillantes. En effet, le marketplace permet de rapidement diffuser l’extension et le mode restreint ne protège pas dans ce cas de figure.

Plusieurs vulnérabilités récentes permettant des exécutions de code à distance ont aussi été découvertes, apportant un risque de sécurité complémentaire pour des développeurs.

L’abus de confiance ou la mauvaise configuration du mode restreint pourrait permettre, via la diffusion préalable de dossier malveillant, de compromettre un poste. À défaut d’utilisation réelle, ce vecteur reste un bon moyen de croissanter 🥐 ses collègues de boulot 😊.

À propos de l’auteur

Article écrit par Alexandre RIPOTEAU alias Vunnm, Ingénieur en Test d’Intrusion chez ACCEIS.