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é.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
gpu-instance-fingerprint — Empreinte digitale de l'GPU exact sur lequel vous exécutez, même parmi des GPU identiques, à partir de l'ordre dans lequel ses additions atomiques arrivent. Précision de 99,1 %, survit aux redémarrages, impossible à falsifier, et un appel torch.index_add_ par défaut la divulgue. | Kitploit
Outils/GitHubGitHub/divagr18/gpu-instance-fingerprint
Protection de la Vie PrivéeSécurité MatérielleArticles et Recherche
GitHubdivagr18/gpu-instance-fingerprint

gpu-instance-fingerprint

Empreinte digitale de l'GPU exact sur lequel vous exécutez, même parmi des GPU identiques, à partir de l'ordre dans lequel ses additions atomiques arrivent. Précision de 99,1 %, survit aux redémarrages, impossible à falsifier, et un appel torch.index_add_ par défaut la divulgue.

Voir le dépôt

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
Site web
27527il y a 4 joursPas encore vérifié

Distinguer des GPU identiques

Article de blog : Telling identical GPUs apart from their numerical output

Deux GPU du même modèle calculent la même somme dans un ordre légèrement différent, et cette différence suffit à les distinguer. Un petit noyau CUDA identifie sur lequel de 19 NVIDIA A40 identiques il s'est exécuté avec une précision de 99,1 %, en utilisant uniquement les nombres qu'il calcule. Il ne lit aucun numéro de série et n'utilise aucun minuteur.

  • Il survit aux redémarrages. Après un redémarrage du conteneur, les 12 mesures ont toutes correspondu à la bonne puce.
  • Il ne pouvait pas être falsifié. Un attaquant sur une puce, réglant tous les paramètres de lancement qu'il contrôle, a atteint au mieux une corrélation de 0,616 avec l'empreinte d'une autre puce. Les puces authentiques correspondent à la leur à 0,946 en moyenne, et jamais en dessous de 0,916.
  • Un appel torch.index_add_ par défaut le révèle aussi. En ne lisant rien d'autre que la sortie ordinaire de cette opération, on identifie la puce avec une précision de 100 % parmi les GPU sur le même pilote, et de 78 % entre pilotes mixtes.
  • Il fonctionne sur plusieurs modèles : A40, RTX 3090, RTX 4090 et L40S.

Pourquoi cela fonctionne : lorsque des milliers de blocs de threads se disputent la mise à jour d'un même compteur, le matériel décide qui arrive en premier. De minuscules différences de fabrication entre les cœurs d'une puce biaisent cet ordre de la même manière à chaque fois.

Le mode déterministe de PyTorch supprime la fuite de index_add_. Le dépôt contient les sondes, toutes les mesures derrière les chiffres ci-dessous, et des scripts qui reproduisent chaque résultat sur le CPU d'un ordinateur portable.

Résultats

RésultatNombreReproduire
Sonde active, 19 A40 identiques, canal P3 (sortie numérique uniquement, sans %smid)99,1 % LOO (111/112), hasard 5,3 %, séparation 4,28xanalysis/pooled_analyze.py
Sonde active, 8 A40P3 100 % LOO, séparation 4,09x, p de permutation = 0,0005analysis/analyze_puf.py
Confusion liée au pilote : 4 A40 sur le pilote identique (580.159.04)P3 100 % (6,10x), P2 100 % (5,43x)analysis/analyze_puf.py
Redémarrage : redémarrage du conteneur, même die vérifié par UUID (4 A40)100 % de ré-identification (12/12), les deux canauxanalysis/temporal_analyze.py
RTX 3090, 7 puces sur 4 versions de piloteP3 100 % LOO (4,55x), P2 100 % (8,12x), p = 0,0005analysis/cross_model_analyze.py
RTX 4090, 2 puces sur le même hôte et le même piloteP3 6/6 (12,5x), P2 6/6 (17,8x)analysis/cross_model_analyze.py
L40S, 2 pucesP3 4/4 (17,2x), P2 4/4 (13,8x)analysis/cross_model_analyze.py
torch.index_add_ passif, K=65536, 6 A40100 % même pilote (9/9), 78 % entre pilotesanalysis/passive_analyze.py
Capacité de signature passive, K=65536~217 bits indépendants (A40), ~239 (RTX 4090)analysis/roc_capacity.py
Falsification : l'attaquant balaie tous les réglages de lancement qu'il contrôlemeilleure falsification 0,616 de corrélation contre 0,92 de plancher authentiqueanalysis/forge_analyze.py
Limite : transformer vanilla fwd/bwd, GEMM dense, matmul TF32identique bit à bit entre puces, aucune fuiteanalysis/leak_analyze.py, analysis/channel_analyze.py
Défense : torch.use_deterministic_algorithms(True)canal passif éliminé ; coût de rétropropagation 2,5-3,6x ; sonde active non affectéeanalysis/defense_analyze.py

LOO = classification par plus proche centroïde en leave-one-out de mesures individuelles par rapport aux centroïdes par puce. Séparation = distance entre puces / distance intra-puce.

Comment cela fonctionne

La sonde (probes/probe_puf.py) est un petit noyau cupy. Elle lance 4096 blocs de 128 threads. Chaque thread exécute la même chaîne fixe de FMA, puis le thread 0 de chaque bloc prend un ticket auprès d'un compteur global avec atomicAdd(counter, 1). Le ticket est le rang d'arrivée de ce bloc. Rien dans l'entrée ne diffère entre les puces ; la seule chose qui varie est quels blocs arrivent en premier.

Cet ordre n'est pas aléatoire. Le distributeur de travail mappe les indices de blocs sur les SM selon un schéma quasi fixe, et chaque SM d'un die donné s'exécute légèrement plus vite ou plus lentement que ses voisins en raison des variations de fabrication. Moyenné sur 3000 lancements, chaque indice de bloc se stabilise vers un rang d'arrivée moyen qui reflète la vitesse du SM sur lequel il atterrit.

fixed kernel, fixed input
        |
        v
blocks race to atomicAdd  -->  arrival slot per block (hardware-decided)
        |
        v  average over 3000 launches
mean arrival rank per block index (P3)  /  per physical SM via %smid (P2)
        |
        v  subtract the cross-chip mean (removes the architecture)
per-chip residual  -->  nearest-centroid match against enrolled chips

Trois canaux ressortent d'une même exécution :

  • P3, rang par bloc. Emplacement d'arrivée moyen par indice de bloc. Il est lu à partir de la seule sortie numérique du noyau : pas de %smid, pas de minuteries, pas de compteurs privilégiés. C'est le canal principal.
  • P2, rang par SM. Les mêmes emplacements regroupés par SM physique via le registre %smid. Le regroupement par SM physique moyenne le bruit thermique, de sorte que P2 tient sous charge : 100 % de ré-identification (18/18) après 60 s de stress à pleine charge.
  • P1, somme marginale. Un histogramme du résultat float32 d'une réduction fixe. Il est faible (séparation de 1,20x sur 8 A40), car la somme détruit la majeure partie de l'information d'ordre.

Soustraire la moyenne entre les puces élimine tout ce que les puces partagent (architecture, pilote, compilateur) et laisse le résidu propre à chaque die. Deux mesures de la même puce se rapprochent ; les mesures de puces différentes ne se rapprochent pas.

Démarrage rapide

git clone https://github.com/divagr18/gpu-instance-fingerprint.git
cd gpu-instance-fingerprint
pip install -r requirements.txt        # numpy + scipy, enough for every analysis

Lancer l'analyse sur les données incluses (CPU, aucun GPU nécessaire) :

python analysis/pooled_analyze.py      # 19 A40s: 111/112 = 99.1%
python analysis/analyze_puf.py "a40_8chip/*.json"   # 8 A40s: P3 100%

Exécuter la sonde sur un GPU :

pip install numpy cupy-cuda12x
python probes/probe_puf.py 3 0 > gpu_a_r0.json   # 3 epochs, replicate 0 (about 2 s per epoch)
python probes/probe_puf.py 3 1 > gpu_a_r1.json

Collectez quelques réplicas de chacune de deux GPU ou plus du même modèle, puis :

python analysis/analyze_puf.py "path/to/*.json"

Chaque enregistrement JSON consigne l'UUID du GPU, le pilote, la version de cupy ainsi que l'horloge et la température par époque, à côté des mesures. L'analyse regroupe par nom de modèle et étiquette les puces par UUID.

Pour exécuter sur des machines distantes via SSH, scripts/run_remote.sh déploie une sonde, l'exécute sur plusieurs hôtes en parallèle et collecte le JSON :

OUT_DIR=data/my_run REPS=4 scripts/run_remote.sh probe gpu1=root@HOST1:PORT gpu2=root@HOST2:PORT

docker/Dockerfile construit une image avec CUDA 12.8, cupy et la sonde préinstallée (docker build -f docker/Dockerfile -t gpu-instance-fingerprint .).

Reproduire chaque résultat

Toutes les commandes s'exécutent depuis la racine du dépôt sur un CPU. Les scripts trouvent leurs données dans data/ par eux-mêmes.

Télécharger l’outil