
Artefacts de recherche pour les attaques par canal auxiliaire de notification de fichiers sur Linux, Windows et macOS, démontrant la fuite via inotify/FSEvents, le timing des frappes clavier et l'empreinte de sites web.
Ce dépôt contient les artefacts (encore en cours de révision !) pour l'article « File Notification Attacks: Templating and Exploiting Side-Channel Leakage from the File-Notification Systems on Linux, Windows, and macOS », accepté à CCS '26.
Consultez le site web avec les démos à l'adresse : https://inoti.fyi/
Lisez l'article à l'adresse : https://snee.la/pdf/pubs/file-notification-attacks.pdf ou http://inoti.fyi/pubs/file-notification-attacks.pdf
Dans le cadre de l'évaluation des artefacts à CCS'26 (encore en cours !), nous avons fourni une VM Debian 13 + KDE Plasma 6 avec un noyau pré-patché. Cette VM n'a pas été utilisée pour produire les résultats d'évaluation de l'article et n'est pas destinée à reproduire leur magnitude exacte. Ce dépôt pourra être mis à jour pour intégrer les relectures et retours de nos évaluateurs d'artefacts. Nous rendrons la VM publiquement accessible lorsque notre évaluation d'artefacts sera terminée.
Nous avons employé Claude (Opus 4.8) pour envelopper notre code dans des artefacts correctement documentés et performants (par exemple, celui pour Windows était un peu lent). Cependant, le code, les scripts et les makefiles qu'il a générés étaient basés sur
Les instructions ci-dessous pour tester le code Linux sont spécifiques à
l'exécution de commandes dans la VM. Veuillez plutôt consulter le code dans
Linux/.
La VM existe purement par commodité, afin que le montage de chaque attaque ne nécessite pas une configuration d'environnement à partir de zéro ni une rétrogradation du noyau. Le mécanisme sous-jacent démontré dans la VM est identique à celui décrit dans l'article, mais veuillez noter que nous n'avons pas utilisé la VM pour produire les chiffres rapportés dans l'article. Les timings absolus peuvent différer en raison de l'environnement virtualisé et du matériel sous-jacent.
Les résultats sont reproduits dans une VM Debian 13 (linux-vm/), installée à
partir de l'ISO live officielle Debian avec KDE Plasma 6 (Wayland) installé avec
un noyau antérieur au correctif
fsnotify.
inotify-tools, les en-têtes de développement Qt6 et pkexec sont installés.
Rien d'autre n'est mis à jour, et le noyau n'est jamais touché après
l'installation. Veuillez NE PAS exécuter apt upgrade ni tenter de mettre à
jour le noyau. Cette image de VM est délibérément ancienne, n'est pas à jour
et ne dispose pas des derniers correctifs de sécurité. Cette image de VM est
uniquement destinée à une validation et des tests rapides !
Le code, les attaques et les démonstrations situés dans la VM sont reproduits
dans Linux/.
Remarque : Nous indiquons sous quel utilisateur exécuter les commandes en
haut de chaque bloc de commandes. Il y a [host], qui est la machine hôte qui
exécute la VM, [user] qui est la victime des attaques dans la VM, et
[spyuser] qui doit être configuré et qui sera l'attaquant dans la plupart des
attaques Linux.
L'image disque est fournie sous le nom linux-vm-upload.qcow2, compressée avec
zstd. Renommez-la en linux-vm.qcow2 avant d'exécuter run.sh (qui attend ce
nom de fichier) :
# Run As: [host]
cd linux-vm/
mv linux-vm-upload.qcow2 linux-vm.qcow2
./run.sh
La lecture d'un qcow2 compressé avec zstd nécessite qemu-img/qemu-system-x86_64
version 5.2 ou supérieure (2020+), vérifiez avec qemu-img --version. Si vous
êtes bloqué sur un QEMU plus ancien et qu'il échoue à ouvrir l'image, décompressez-la
d'abord en un qcow2 plat :
qemu-img convert -O qcow2 linux-vm-upload.qcow2 linux-vm.qcow2
4 cœurs, 4 Go de RAM, affichage graphique. Les identifiants sont :
root, mot de passe password,user, mot de passe password,spyuser, mot de passe password (ne vous connectez pas en tant que spyuser !)La VM fournie exécute déjà un noyau vulnérable et pré-patché
(6.12.43+deb13-amd64), donc aucune rétrogradation n'est nécessaire pour
l'utiliser. Vous aurez besoin de QEMU pour exécuter cette image (qui dispose
d'une interface graphique). L'artefact se trouve à
/home/user/Linux-File-Notification-Attacks dans la VM.
Une seule commande configure tout à neuf dans la VM : (i) un compte spyuser
non privilégié (non-sudo), (ii) sa propre copie du répertoire d'artefacts (un
compte non privilégié distinct ne peut autrement pas traverser le répertoire
personnel de user), (iii) et tous les scripts rendus exécutables dans les deux
copies.
# In the VM, Run As: [user]
sudo bash ~/Linux-File-Notification-Attacks/setup_attacks.sh
Chaque attaque ci-dessous s'exécute en tant que spyuser (su - spyuser, mot
de passe password), sauf auth-ui-redress, qui s'exécute en tant que user
(expliqué ci-dessous).
Démontre que les notifications d'opérations sur fichiers sont délivrées pour des fichiers qui ne peuvent pas être lus directement, tant que leur répertoire parent est lisible.
# Run As: [spyuser]
# To switch to spyuser, in a new terminal type `su - spyuser`. The password
# is `password`.
cd ~/Linux-File-Notification-Attacks/unreadable-file-bypass
./watch-syslog.sh
Laissez-le s'exécuter, puis générez une ligne de journal depuis un autre
terminal en tant que user :
# Run As: [user]
logger "hello"
Cette image Debian 13 n'a pas rsyslog, donc il n'y a pas de fichier
/var/log/syslog comme montré dans l'article. Le script se rabat sur la
surveillance de /var/log/journal/<machine-id>/ à la place. C'est la même idée,
car les fichiers .journal surveillés appartiennent à root (utilisateur) et
systemd-journal (groupe), dont aucun n'est spyuser.
Mesure le délai de notification d'inotify.
# Run As: [user], ensure numpy is installed (or pip3)
sudo apt install python3-numpy
# Run As: [spyuser]
cd ~/Linux-File-Notification-Attacks/temporal-resolution
./run.sh
watcher ouvre une surveillance inotify sur un fichier de test et horodate
chaque IN_ACCESS qu'il reçoit. accessor lit ce même fichier 1000 fois avec un
délai aléatoire de 5 à 10 ms entre les lectures, en horodatant lui-même chaque
lecture. stats.py compare les deux enregistrements d'horodatage et affiche le
délai moyen/écart-type/minimum entre le moment où la lecture a lieu et l'arrivée
de la notification, c'est-à-dire la résolution temporelle d'inotify.
Pas l'attaque complète de l'article, mais juste la primitive de preuve de
concept du filtrage sur laquelle l'attaque est construite : pour chaque touche
pressée n'importe où sur le système, afficher une notification horodatée, sans
jamais lire /dev/input directement.
# Run As: [spyuser]
cd ~/Linux-File-Notification-Attacks/inter-keystroke-timing
make
./find-keyboard.sh
Tapez dans n'importe quelle fenêtre (peut-être un nouveau terminal en tant que
user). Chaque frappe affiche une ligne KEYPRESS. La fenêtre de suppression
(que nous avons choisie heuristiquement pour cette démonstration, 130 ms) fusionne
plusieurs événements IN_ACCESS générés par une seule pression physique de touche.
En pratique, nous avons remarqué que cette fenêtre diffère selon le matériel
(par exemple, claviers mécaniques, styles de frappe).
Si la détection automatique choisit le mauvais périphérique (ou aucun), vérifiez
/proc/bus/input/devices et exécutez-le directement avec ./build/keystroke-notify /dev/input event4.
Nous démontrons la capacité à détecter quand
(pkexec)[https://polkit.pages.freedesktop.org/polkit/] est exécuté, et à
dessiner en outre une fausse fenêtre par-dessus. Comme nous l'avons montré dans
la section 4.4.3, cette « attaque d'habillage de l'interface d'authentification »
est possible sur KDE Plasma 5 et 6 avec Wayland. Nous exécutons cette attaque
dans le modèle de menace d'un attaquant avec le même utilisateur : le socket
Wayland est limité à la session connectée, et un compte non privilégié distinct
ne peut pas dessiner dessus.
Sur une installation KDE standard, pkexec est tiré par le bureau, mais cette
ISO live est une image plus légère, et ne l'a donc pas installé. Par conséquent,
nous l'avons installé manuellement tout en (essayant de) garder l'image de la VM
petite.
# Run As: [user]
cd ~/Linux-File-Notification-Attacks/auth-ui-redress
make
./inotify-watcher-with-gui
Laissez-le s'exécuter dans un terminal. Depuis un autre terminal (le répertoire
n'a pas d'importance), déclenchez une véritable invite pkexec, par exemple
pkexec ls. Le surveillant voit l'accès à /usr/bin/pkexec et dessine une
fausse boîte de dialogue « Authentication Required » (window-launcher) à
l'écran par-dessus la vraie. Saisir du texte dans la fausse boîte de dialogue et
cliquer sur Authenticate affiche le texte saisi dans le terminal du surveillant,
puis la ferme. Veuillez noter que la fausse fenêtre est délibérément différente
de la vraie fenêtre pour faciliter la comparaison.
Surveiller les répertoires de polices pendant le chargement d'une page révèle quels fichiers de polices elle a touchés. Différents sites chargent différentes polices, donc l'ensemble des chemins affichés pendant le chargement d'une page est déjà une empreinte, sans avoir besoin de timing ni de classifieur pour cette version minimale.
D'abord, en tant qu'utilisateur, ouvrez Firefox (cliquez dessus via l'icône dans
le dock du gestionnaire de tâches en bas de l'écran), et assurez-vous qu'aucun
site web n'est ouvert. Ensuite, dans un terminal en tant que spyuser :
# Run As: [spyuser]
cd ~/Linux-File-Notification-Attacks/website-fingerprinting-fonts
./compare-fonts.sh
Cela compile font-spy qui commence à surveiller les répertoires de polices
utilisés par Firefox. Le script compare-fonts vous invite à visiter deux sites
web.
D'abord, visitez un site web (peut-être wikipedia.com) et attendez quelques secondes qu'il se charge, ouvrez un nouvel onglet, fermez l'ancien onglet (avec le site web), puis appuyez sur ENTRÉE dans le terminal.
Ensuite, faites de même avec un autre site web (peut-être reddit.com) : visitez le site web et attendez quelques secondes qu'il se charge, ouvrez un nouvel onglet, fermez l'ancien onglet, puis appuyez sur ENTRÉE dans le terminal.
Le script devrait afficher la différence de polices accédées par site web. Notez que dans l'article, nous avons aussi utilisé l'information temporelle, c'est-à-dire quand la police a été accédée. Pour une simple preuve de concept, nous ignorons cette information et affichons simplement la différence entre les deux ensembles d'accès aux polices. Bien que l'ensemble exact des accès aux polices puisse différer entre les exécutions, certains fichiers de polices sont toujours et uniquement accédés par un site web.
Notez que les sites web peuvent changer au fil du temps, et donc les accès aux
fichiers de polices peuvent différer. Au moment de la rédaction de cet artefact,
nous remarquons que Wikipédia accède toujours à
/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf et que Reddit
accède toujours à
/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf.
Un appareil physique ou un émulateur exécutant une version d'Android dont le
modèle de stockage limité (Scoped Storage) permet encore d'enregistrer un
FileObserver (l'enveloppe Java autour d'inotify) sur les répertoires de
médias partagés de WhatsApp, et un second appareil/compte pour jouer le rôle de
l'expéditeur du message. Compilez soit la source fournie (Android/source/),
soit installez directement l'APK fourni (Android/app-release.apk).
Android expose la même primitive inotify utilisée dans tous les résultats Linux
via android.os.FileObserver. La section 5.4.3 montre qu'une application non
privilégiée et sans permissions peut enregistrer un tel observateur sur les
répertoires de médias de WhatsApp et, à partir du seul flux d'événements
open/close/access qui en résulte, déduire que des médias privés ont été reçus,
sans détenir aucune permission qui lui permettrait de lire le contenu lui-même.
Lancez l'application et déclenchez l'action de rafraîchissement ; le service
d'observation s'attache et commence à émettre des entrées périodiques de
signal de vie. Faites défiler jusqu'en bas de la vue des journaux et continuez à
rafraîchir jusqu'à ce que des entrées répétées ObserverService: Still Running apparaissent, confirmant que la surveillance est active et stable.
Depuis un second compte, envoyez une image ou un document à la conversation
observée et, si ce n'est pas déjà en cache, téléchargez-le sur l'appareil
observé. Cela produit une rafale de lignes de journal d'événements de fichiers ;
immédiatement après la dernière entrée ObserverService: Still Running avant la
rafale, le journal devrait montrer des événements open/close/access dont les
chemins correspondent au fichier reçu, démontrant que son arrivée est observable
purement à partir des métadonnées de notification du système de fichiers.
Nous fournissons le code source qui peut être compilé avec msys2. Sinon, le fichier exe (Windows/firefox-fingerprint/monitor.exe) peut également être utilisé.
Une machine Windows (ou VM) avec MSYS2 installé, et la
chaîne d'outils MinGW-w64 g++ (pacman -S mingw-w64-ucrt-x86_64-gcc, exécuté
depuis un shell MSYS2). Firefox installé.
Cette preuve de concept utilise
ReadDirectoryChangesW
pour surveiller récursivement tout C:\, et n'affiche que les événements dont
le chemin contient http (répertoires de stockage par origine que Firefox nomme
d'après le schéma/hôte du site, par exemple sous ses dossiers cache/IndexedDB).
Aucun droit administrateur n'est requis pour surveiller un répertoire que vous
pouvez lister. Ce stockage par origine est écrit à chaque chargement de page,
donc surveiller depuis l'extérieur du processus du navigateur révèle tout de
même quel site vient d'être visité.
Utilisez soit l'exe que nous fournissons (Windows/firefox-fingerprint/monitor.exe), soit compilez depuis un shell MSYS2 UCRT64 :
# Run in an MSYS2 UCRT64 shell
cd Windows/firefox-fingerprint
g++ -municode -static -O2 -o monitor.exe monitor.cpp
Utilisez g++, pas gcc. Exécutez également monitor.exe depuis un terminal
(pas en double-cliquant dessus), sinon aucune console n'est attachée pour
afficher la sortie.
Le surveillant s'exécute en tant que second compte local non privilégié, distinct de celui qui navigue. D'abord, créez ce compte via les Paramètres :
attacker, et un mot de passe, puis Suivant.Cela crée un compte local (non lié à un compte Microsoft, sans connexion réseau), avec des privilèges standard (non administrateur) par défaut.
Ensuite, placez monitor.exe quelque part où le nouveau compte peut réellement
le lire et l'exécuter. Copiez plutôt le binaire compilé dans le répertoire
public, lisible par tous :
copy monitor.exe C:\Users\Public\monitor.exe
Maintenant, depuis votre compte principal (victime), lancez-le sous le compte
attacker sans changer de bureau ni vous déconnecter, en utilisant runas :
runas /user:attacker "cmd /k C:\Users\Public\monitor.exe"
Saisissez le mot de passe d'attacker lorsque vous y êtes invité. cmd /k
(plutôt que d'exécuter monitor.exe directement) garde la fenêtre de console
ouverte pour que vous puissiez observer sa sortie, tandis que simplement
runas /user:attacker C:\Users\Public\monitor.exe fonctionne aussi, mais sa
fenêtre se ferme dès que le processus se termine. C'est purement par commodité.
Laissez la fenêtre monitor.exe s'exécuter, puis, de retour dans votre compte
principal, ouvrez Firefox et visitez quelques sites web différents, par exemple,
arstechnica.com et reddit.com.
Chaque ligne affichée est une création/modification/renommage de fichier sous un
chemin de stockage correspondant à http. Différents sites obtiennent différents
répertoires d'origine, et donc l'ensemble des chemins touchés pendant le
chargement d'une page est déjà une empreinte.
Pour simplifier, nous utilisons fswatch,
un outil CLI existant, minimal et largement utilisé qui enveloppe l'API native
FSEvents. Un attaquant peut aussi utiliser l'API FSEvents sans cet outil.
Installez fswatch, ou compilez depuis les sources :
brew install fswatch
Surveillez /Applications récursivement, en tant qu'utilisateur non privilégié :
fswatch -xr /Applications
Laissez-le s'exécuter, puis, depuis le Finder ou un navigateur, téléchargez et
installez Zoom (ou toute autre application), puis désinstallez-la (vous devrez
peut-être aussi vider la corbeille). fswatch affiche chaque chemin rapporté par
FSEvents sous /Applications au fur et à mesure. Pour une évaluation rapide, le
même utilisateur peut surveiller le répertoire. Sinon, vous pouvez créer un
nouvel utilisateur et utiliser fswatch en tant que cet utilisateur.
Publié sous la licence MIT.