Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
supernote-obsidian-plugin-PoC — PoC — path traversal via une synchronisation d'appareil malveillante dans le plugin Supernote Obsidian (GHSA-3gx3-r874-5pp4, CVE-2026-86999, CVSS 5.6). | Kitploit
Outils/GitHubGitHub/squeeze440/supernote-obsidian-plugin-poc
Analyse des VulnérabilitésExploitationExploitation d'Applications WebVirtualisation de SécuritéTests d'IntrusionArticles et Recherche
GitHubsqueeze440/supernote-obsidian-plugin-poc

supernote-obsidian-plugin-PoC

PoC — path traversal via une synchronisation d'appareil malveillante dans le plugin Supernote Obsidian (GHSA-3gx3-r874-5pp4, CVE-2026-86999, CVSS 5.6).

Voir le dépôt
16il y a 19 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Résumé

Statut CVE : demandé, en attente d'attribution. Cette découverte est publiée sous GHSA-3gx3-r874-5pp4. À l'attribution du CVE, ce dépôt sera renommé CVE-YYYY-NNNNN-supernote-obsidian-plugin-PoC et cette bannière sera remplacée par le lien CVE.

ChercheurDostxodjayev Abdullox (@squeeze440)
AvisGHSA-3gx3-r874-5pp4
CVSS 3.15.6 (Moyen)
FaiblesseCWE-22, CWE-73

Résumé

Une traversée de chemin (Path Traversal) dans la fonctionnalité de synchronisation automatique de l'appareil du plugin Obsidian Supernote (Unofficial) (philips/supernote-obsidian-plugin) v2.9.1 permet à un appareil « Supernote » malveillant ou compromis (ou à un attaquant sur le chemin réseau/sur le LAN usurpant l'IP de l'appareil appairé) de faire écrire par le client Obsidian de la victime un nouveau fichier arbitraire partout où le processus de bureau peut écrire — y compris en dehors du dossier de synchronisation configuré et en dehors du coffre lui-même — via un champ uri forgé dans la réponse de listage de répertoire de l'appareil.

Produit

philips/supernote-obsidian-plugin (« Supernote (Unofficial) »), un plugin communautaire Obsidian.md qui synchronise les notes d'un appareil physique Supernote à encre électronique dans un coffre via le serveur HTTP local « Browse and Access » de l'appareil (http://<device-ip>:8089, sans authentification, par conception de la fonctionnalité de l'appareil).

Version testée

  • Plugin : v2.9.1, commit 48db5bf4dcfb100632c84699c830c1309da1abb9
  • Sous-module supernote-typescript : commit 195415b3a1f74147... (non impliqué en lui-même — le bug se trouve entièrement dans le code de planification de synchronisation propre au plugin)
  • Application hôte : Obsidian desktop 1.13.4 (binaire réel, testé dynamiquement)

CVSS v3.1 estimé

5.6 Moyen — CVSS:3.1/AV:A/AC:H/PR:N/UI:R/S:C/C:N/I:H/A:N

  • AV:A — le serveur HTTP de l'appareil est en clair, non authentifié, et configuré par une simple adresse IPv4 (IP_VALIDATION_PATTERN, src/settings.ts:6) ; y accéder en tant que « l'appareil » nécessite une position réseau adjacente au LAN (AP pirate, usurpation ARP, ou revendication de l'IP), et non un accès distant arbitraire.
  • AC:H — l'exploitation dépend du fait que l'attaquant occupe déjà cette position réseau lorsque le plugin de la victime communique avec directConnectIP:8089 ; il ne s'agit pas d'un déclenchement distant en un seul coup.
  • UI:R — nécessite que la victime exécute « Sync supernote notes now » (ou que le basculement de synchronisation automatique soit déjà activé) alors qu'elle pointe vers le point de terminaison contrôlé par l'attaquant.
  • S:C — le composant vulnérable est un plugin Obsidian limité au coffre ; l'écriture atterrit entièrement en dehors du coffre, sur le système de fichiers hôte sous-jacent, ce qui constitue une portée de sécurité différente.
  • C:N — il s'agit d'une primitive en écriture seule ; rien n'est relu par l'attaquant.
  • I:H — des octets contrôlés par l'attaquant atterrissent à un chemin choisi par l'attaquant avec un nom de fichier choisi par l'attaquant. Réserve limitative : writeBinaryAt() (src/syncEngine.ts:40-47) ne prend la branche create que pour les chemins non déjà suivis dans le manifeste de synchronisation propre au plugin, et Vault.createBinary() d'Obsidian refuse lui-même d'écraser silencieusement un fichier qui existe déjà physiquement au chemin résolu (confirmé empiriquement — voir PoC) — il s'agit donc de « planter un nouveau fichier n'importe où », et non d'« écraser n'importe quel fichier existant ».
  • A:N — aucun impact sur la disponibilité démontré.

Détails

runDeviceSync() (src/syncEngine.ts:100-196) liste les fichiers de l'appareil appairé via scanDeviceSupernoteTree() (src/FileListModal.ts:53-68), qui parcourt récursivement le listage de répertoire HTTP de l'appareil lui-même et conserve toute entrée dont le name correspond à /\.(note|spd)$/i (src/FileListModal.ts:46,63). Le champ uri de chaque entrée — une chaîne distincte et contrôlée indépendamment dans le même objet JSON renvoyé par l'appareil — n'est jamais validé par rapport à name ni par rapport à quoi que ce soit d'autre.

Cet uri brut est ensuite injecté directement dans deviceUriToVaultPath() (src/deviceSync.ts:153-161) :

const INVALID_FILENAME_CHARS = /[\\:*?"<>|]/g;   // deviceSync.ts:144

export function deviceUriToVaultPath(syncFolder: string, deviceUri: string): string {
    const segments = deviceUri
        .split('/')
        .filter((s) => s.length > 0)
        .map((s) => s.replace(INVALID_FILENAME_CHARS, '_'));

    const cleanRoot = syncFolder.replace(/^\/+|\/+$/g, '');
    return cleanRoot ? `${cleanRoot}/${segments.join('/')}` : segments.join('/');
}

INVALID_FILENAME_CHARS supprime \ : * ? " < > | mais ne supprime ni ne rejette jamais les segments de chemin ... Un uri d'appareil /../../PWNED.txt survit intact et est joint au dossier de synchronisation configuré (par défaut "Supernote sync") pour produire vaultPath = "Supernote sync/../../PWNED.txt".

syncEngine.ts:128 calcule ce vaultPath à partir de l'uri brut du listage, puis ensureFolder()/writeBinaryAt() (syncEngine.ts:146-148, 21-47) le transmettent directement à app.vault.getAbstractFileByPath() / createBinary() / modifyBinary() sans aucune vérification de traversée. La résolution de chemin propre à Obsidian normalise alors les segments .. par rapport au répertoire réel du coffre sur le disque, faisant atterrir l'écriture au-dessus du dossier de synchronisation — et, avec suffisamment de segments ../, au-dessus de la racine du coffre entièrement, sur le système de fichiers hôte, dans la portée de permissions de l'utilisateur du système d'exploitation.

Vérification des pairs : tous les autres points d'écriture dans le coffre de cette base de code (src/main.ts — capture de miroir d'écran, import PDF/markdown, « attach to note », DownloadListModal dans src/FileListModal.ts:245-246) construisent leur chemin de destination via app.fileManager.getAvailablePathForAttachment(file.name) d'Obsidian lui-même, qui ne consomme jamais que le champ name de l'appareil et n'est pas exploitable de cette manière. deviceUriToVaultPath() dans la fonctionnalité de synchronisation automatique plus récente est le seul point d'écriture qui fabrique à la main un chemin à partir du champ uri de l'appareil, et c'est celui qui a omis la désinfection des .. — un cas typique de « vérifié sur tous les pairs sauf celui-ci ».

L'interface de paramètres du plugin lui-même déclare : « La commande de synchronisation n'écrit jamais en dehors de ce dossier » (src/settings.ts, description du dossier de synchronisation) — ce PoC falsifie directement cette garantie.

Preuve de concept

Confirmé dynamiquement de bout en bout contre un binaire Obsidian 1.13.4 desktop réel et non modifié (Xvfb + fluxbox + xdotool + scrot), exécutant le main.js compilé réel du plugin — aucun mockage du code du plugin.

Télécharger l’outil