Echoes of Hackers · Forge · Octobre Rose

⚒️ MAESTRO · SENSORTRACE · LAB_ONLY

SensorTrace - Lab de détection des capteurs

Salut Apache👋 Ce lab te montre comment savoir si le micro, la caméra ou la géolocalisation sont activés, par qui, et quand - sur Android, iOS, Windows et macOS. Puis on ajoute le « regard de l’autre côté » : comment une image en apparence anodine peut transporter du code, et comment le détecter. Tout est LAB_ONLY, sur tes propres appareils, avec ton consentement. On ne crée aucune charge utilisable : on apprend à reconnaître la forme d’un comportement pour mieux le repérer.

⚠️ Ce lab est strictement défensif et 100 % local

Tu vas manipuler des pastilles, des journaux d’activité et des fichiers cobayes (images polyglot, métadonnées EXIF, SVG avec script). Aucun de ces fichiers ne contient de code utilisable : les charges embarquées sont réduites à echo "LAB_ONLY" et alert('demo'). Objectif : apprendre à détecter, pas à exploiter. Les cobayes ne doivent jamais quitter le dossier du lab : ni mail, ni chat, ni upload, ni dépôt public.

Garde-fous intégrés à ce lab :

  • Périmètre : uniquement tes propres appareils (téléphone perso, PC, Mac), avec ton consentement explicite à chaque demande d’accès.
  • Aucune cible tierce : on ne teste jamais sur l’appareil de quelqu’un d’autre, même avec autorisation orale - utilise tes propres machines.
  • Aucune charge utilisable : les charges embarquées dans les cobayes sont des marqueurs de démonstration (LAB_ONLY, alert('demo')).
  • Cobayes confinés : les fichiers polyglot.php.gif, exif.jpg, appended.jpg, demo.svg restent dans ~/Bureau/sensor-trace-lab/image-piegee/ et sont supprimés en fin d’exercice.
  • Pas de persistance : aucune des pages ou commandes ne modifie de configuration système sans que tu ne l’aies explicitement fait (toutes les actions sont documentées, réversibles, et rappelées en fin de section).

🎗️ Note Octobre Rose

Voir, comprendre, vérifier - sur soi, pour soi. La vie privée, c’est d’abord un droit qu’on exerce en connaissance de cause. Ce lab reste strictement confiné : on apprend, on vérifie, on protège.

Théorie - les pastilles, les journaux, et leurs limites

Chaque OS moderne signale l’accès aux capteurs par un indicateur visuel en temps réel (pastille, icône, point coloré) et conserve un journal d’activité consultable après coup. Ces deux sources ne racontent pas la même chose : la pastille dit « en ce moment », le journal dit « récemment, combien de fois, et par qui ». Un lab sérieux corrèle les deux.

Android 12+ - pastille verte et Privacy Dashboard

Un point vert (ou une icône) apparaît dans la barre d’état dès qu’une application utilise le micro ou la caméra. Un point bleu signale parfois l’accès à la localisation selon la version. Ces indicateurs sont impossibles à masquer côté application.

Journal : Paramètres > Sécurité et confidentialité > Tableau de bord de confidentialité. Il liste, par heure et par application, les accès au micro, à la caméra et à la localisation.

; Android - sources de preuve pastille point vert/bleu, temps reel, systeme dashboard journal d'acces (heure, app, permission) adb cmd privacy get-recent-events limite un site web peut utiliser le capteur via Chrome, sans que Chrome ait la permission

iOS 14+ - point orange, point vert

Point orange = micro. Point vert = caméra (ou caméra + micro). Le Centre de contrôle affiche la dernière application ayant accédé. Depuis iOS 15, le Rapport de confidentialité de l’app conserve l’historique détaillé (heure, app, type d’accès).

Journal : Réglages > Confidentialité et sécurité > Rapport de confidentialité de l’app.

; iOS - sources de preuve pastille orange (micro) / vert (camera) centre Centre de controle = derniere app active rapport Rapport de confidentialite = historique limite certains spywares avances ont su masquer la pastille (recherche Predator) -> croiser avec le rapport

Windows 10/11 - icône de notification

Une icône de micro ou une flèche de localisation s’affiche dans la zone de notification pendant l’accès. Le journal d’activité (Paramètres > Confidentialité & sécurité > Autorisations des applications) indique, par application, l’historique récent.

Registre : HKCU\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\<capteur> liste les applications ayant demandé/obtenu l’accès.

; Windows - sources de preuve icone barre des taches, temps reel journal Parametres > Confidentialite > Recent activity registre ConsentStore (liste apps + timestamps) limite webcam externe sans LED physique ; acces tres brefs parfois invisibles

macOS 12+ - points du Centre de contrôle

À droite de l’icône du Centre de contrôle, des points colorés apparaissent : orange = micro, vert = caméra, violet = enregistrement audio système, flèche = localisation. Centre de contrôle > partie supérieure liste les apps actives.

Journal unifié : log show --predicate 'subsystem == "com.apple.TCC"' - le sous-système TCC (Transparency, Consent, Control) garde les décisions d’autorisation et parfois les accès effectifs.

; macOS - sources de preuve points orange / vert / violet / fleche, temps reel centre Centre de controle = apps actives tcc log show --predicate ...com.apple.TCC... limite Sonoma 14.4+ : indicateurs masquables sur ecran externe en plein ecran

Le point commun : aucune pastille ne dit ce qui est fait avec le flux, seulement qu’il y a flux. Un accès légitime (visio) et un accès suspect (enregistrement silencieux) allument la même pastille. C’est pourquoi on corrèle systématiquement avec :

  1. le journal d’activité natif de l’OS (heure, app, durée),
  2. la page web en cours (un site peut déclencher getUserMedia via le navigateur, sans permission « app »),
  3. les outils tiers (Grapefruit, OVERSIGHT, scripts ADB/PowerShell),
  4. les traces fichiers quand une page charge des ressources (c’est là qu’intervient l’image piégée).

Architecture du lab

flowchart TB subgraph DEV["Tes appareils (consentants)"] A["Android 12+
pastille + Privacy Dashboard"] I["iOS 14+
point orange/vert + Rapport"] W["Windows 10/11
icone + Recent activity"] M["macOS 12+
points + log show TCC"] end subgraph PAGE["Page HTML locale (page-test.html)"] G["getUserMedia()
demande micro / camera / geo"] J["<img src=...>
charge les cobayes"] end subgraph COB["Cobayes LAB_ONLY (image-piegee/)"] P1["polyglot.php.gif"] P2["exif.jpg"] P3["appended.jpg"] P4["demo.svg"] end subgraph OUT["Outils def."] T1["file / exiftool / xxd"] T2["strings / binwalk / foremost"] T3["scan_images.py"] T4["YARA (image_polyglot.yar)"] end subgraph JOUR["Journaux a correler"] L1["pastille temps reel"] L2["journal activite OS"] L3["rapport scan_images.py"] L4["YARA + Suricata (optionnel)"] end DEV -- "consentement explicite" --> PAGE PAGE -- "charge" --> COB COB -- "audit" --> OUT OUT -- "produit" --> JOUR L1 -. "correlation" .- L2 L2 -. "correlation" .- L3 L3 -. "correlation" .- L4
              APPAREILS (consentants)
  Android / iOS / Windows / macOS
        |  consentement explicite
        v
  page-test.html  (getUserMedia + img coby)
        |  charge
        v
  cobayes LAB_ONLY : polyglot.php.gif | exif.jpg | appended.jpg | demo.svg
        |  audit
        v
  file | exiftool | xxd | strings | binwalk | foremost | scan_images.py | YARA
        |  produit
        v
  JOURNAUX A CORRELER : pastille + journal OS + rapport scan + alertes YARA
        \______ 4 sources = 1 evenement ______/

Si le diagramme ne s’affiche pas (CDN bloqué), le schéma ASCII de secours apparaît automatiquement.

Prérequis

  • Ta machine Kali (ou Debian/Ubuntu) avec Terminal, et - selon l’appareil testé - ton téléphone Android, ton iPhone, ton PC Windows, ton Mac.
  • Outils en ligne de commande côté Linux/Kali : exiftool, binwalk, foremost, strings, xxd, file, identify (ImageMagick), yara, python3.
  • Côté Android : adb (Android Platform Tools), mode développeur et debug USB activés uniquement le temps de l’exercice.
  • Côté Windows : PowerShell (natif). Côté macOS : Terminal (natif).
  • Tout se passe en local. Ne lance rien sur l’appareil de quelqu’un d’autre. Aucun fichier cobaye ne sort du dossier du lab.

Installation des outils sur Kali :

sudo apt update
sudo apt install -y exiftool binwalk foremost imagemagick yara python3 android-tools-adb

Étape 1 Créer l’arborescence du lab

Tout tient dans un seul dossier de ton Bureau. Copie et exécute :

terminal - arborescence
# Cree l'arborescence du lab sur ton Bureau
mkdir -p ~/Bureau/sensor-trace-lab/{journaux,image-piegee,scripts,yara,page}
cd ~/Bureau/sensor-trace-lab
echo "Lab SensorTrace pret dans $(pwd)"
ls -la

Étape 2 Android - Privacy Dashboard + ADB

Sur ton téléphone Android (12+), vérifie d’abord la pastille et le Privacy Dashboard. Puis, si tu veux automatiser, active le debug USB et branche le téléphone à ton Kali.

terminal - Android / adb
# 1) Verifier que le telephone est bien vu
adb devices

# 2) Evenements recents par capteur (equivalent Privacy Dashboard)
adb shell cmd privacy get-recent-events --sensor-type camera
adb shell cmd privacy get-recent-events --sensor-type microphone
adb shell cmd privacy get-recent-events --sensor-type location

# 3) Permissions accordees (liste par paquet)
adb shell dumpsys package | grep -E "android.permission.(CAMERA|RECORD_AUDIO|ACCESS_FINE_LOCATION)"

# 4) Voir qui a la permission MICROPHONE active
adb shell pm list packages -p | head -20

# 5) Desactiver le debug USB a la fin (sur le telephone : Options de developpeur)

Le piège classique : un site dans Chrome peut utiliser ton micro/caméra sans que Chrome ait la permission “app”. La pastille s’allume - mais l’enquête doit descendre au niveau du site : dans Chrome, icône 🔒 dans la barre d’adresse > Autorisations. C’est un cas d’école pour la corrélation.

Étape 3 iOS - Rapport de confidentialité

Sur ton iPhone (iOS 15+), fais le tour des sources : pastille, Centre de contrôle, rapport de confidentialité, et permissions par app.

chemin iOS - pas de shell
# 1) Pastille en temps reel : barre d'etat
#    point orange = micro ; point vert = camera (ou les deux)

# 2) Centre de controle = derniere app ayant accede
Glisser du coin superieur droit vers le bas
-> la derniere app ayant utilise micro/camera s'affiche en haut

# 3) Rapport de confidentialite (historique, le plus utile)
Reglages > Confidentialite et securite > Rapport de confidentialite de l'app
-> liste des acces par app, par heure, par type (micro / camera / geo)

# 4) Permissions par app
Reglages > Confidentialite et securite > Microphone
Reglages > Confidentialite et securite > Appareil photo
Reglages > Confidentialite et securite > Service de localisation

# 5) Cas suspect : app qui demande le micro mais n'en a pas besoin
#    -> verifier dans le rapport si elle a accede en arriere-plan

Limite documentée : certains spywares avancés ont su masquer la pastille (recherche Predator). D’où l’importance de ne pas se fier uniquement à la pastille : le Rapport de confidentialité reste la source la plus fiable côté iOS non jailbreaké.

Étape 4 Windows 10/11 - Recent activity + PowerShell

Sur ton PC Windows, vérifie l’icône de notification et le journal d’activité. Puis, en PowerShell, liste les applications ayant accédé aux capteurs.

PowerShell - Windows
# 1) Journal d'activite "Recent activity" (GUI)
#    Parametres > Confidentialite et securite > Autorisations des applications
#    > Microphone / Appareil photo / Localisation

# 2) Liste des applications ayant accede au micro
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone\*" |
  Select-Object PSChildName, LastUsedTimeStart, LastUsedTimeStop

# 3) Liste des applications ayant accede a la camera
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\*" |
  Select-Object PSChildName, LastUsedTimeStart, LastUsedTimeStop

# 4) Liste des applications ayant accede a la localisation
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location\*" |
  Select-Object PSChildName, LastUsedTimeStart, LastUsedTimeStop

# 5) Cas suspect : application avec LastUsedTimeStop a 0
#    -> acces encore en cours au moment du controle

Le piège classique : une webcam externe n’a pas toujours de LED physique. L’icône Windows peut ne pas s’afficher pour un accès très bref. On corrèle donc icône + journal d’activité, jamais l’un sans l’autre.

Étape 5 macOS 12+ - Centre de contrôle + log show

Sur ton Mac, vérifie les points colorés et le Centre de contrôle. Puis, en Terminal, audite les décisions TCC (Transparency, Consent, Control).

terminal - macOS
# 1) Points colores dans la barre des menus
#    orange = micro ; vert = camera ; violet = audio systeme ; fleche = geo

# 2) Centre de controle : apps actives en haut
#    Clic sur l'icone dans la barre des menus

# 3) Reglages systeme > Confidentialite et securite
#    > Microphone / Camera / Localisation

# 4) Audit avance : decisions TCC sur la derniere heure
log show --predicate 'subsystem == "com.apple.TCC"' --last 1h

# 5) Filtrer les acces camera
log show --predicate 'subsystem == "com.apple.TCC" AND eventMessage CONTAINS "camera"' --last 1h

# 6) Filtrer les acces micro
log show --predicate 'subsystem == "com.apple.TCC" AND eventMessage CONTAINS "microphone"' --last 1h

# 7) Filtrer les acces localisation
log show --predicate 'subsystem == "com.apple.TCC" AND eventMessage CONTAINS "location"' --last 1h

Le piège classique : depuis macOS Sonoma 14.4, les indicateurs peuvent être masqués sur un écran externe en plein écran. Si tu utilises un moniteur externe, la pastille peut ne pas être visible : log show reste ton filet de sécurité.

Étape 6 Page de test locale (getUserMedia + cobayes)

Cette page te sert de banc d’essai : elle demande l’accès aux capteurs et charge les cobayes. Ouvre-la depuis file:// ou un petit serveur local, jamais depuis un site public. Elle te permet de provoquer un accès volontaire et de vérifier que la pastille, le journal OS et scan_images.py racontent la même histoire.

page/page-test.html
<!doctype html>
<html lang="fr">
<head>
  <meta charset="utf-8">
  <title>SensorTrace - page de test locale</title>
  <style>
    body{font-family:system-ui,sans-serif;background:#0c0a0f;color:#ece7f3;padding:2rem;max-width:900px;margin:auto}
    button{background:#c21f6b;color:#fff;border:0;padding:.6rem 1rem;border-radius:8px;font-weight:700;cursor:pointer;margin:.2rem}
    #status{background:#1b1724;border:1px solid #322a3f;border-radius:8px;padding:.8rem;margin:1rem 0;font-family:monospace;white-space:pre-wrap}
    img.coby{border:2px dashed #ff8a3d;max-width:160px;margin:.3rem;background:#15121b}
    .banner{background:linear-gradient(90deg,rgba(255,85,85,.18),rgba(255,85,85,.04));border:1px solid #ff5555;border-left:6px solid #ff5555;border-radius:10px;padding:.8rem 1rem;margin-bottom:1rem}
    .banner b{color:#ff9a9a}
  </style>
</head>
<body>
  <div class="banner">
    <b>LAB_ONLY</b> - page de test. Toutes les demandes d'acces sont
    volontaires. Les images ci-dessous sont des cobayes inoffensifs
    (charges de demo uniquement). Ne pas heberger publiquement.
  </div>
  <h1>SensorTrace - page de test</h1>
  <p>Chaque bouton declenche une demande <code>getUserMedia</code>.
     Regarde la pastille de l'OS pendant l'acces, puis ouvre le journal
     d'activite pour comparer.</p>
  <p>
    <button id="cam">Demander la camera</button>
    <button id="mic">Demander le micro</button>
    <button id="geo">Demander la geoloc</button>
    <button id="stop">Tout arreter</button>
  </p>
  <div id="status">En attente d'une action…</div>

  <h2>Cobayes (images piegees LAB_ONLY)</h2>
  <p>Chargement local depuis le dossier image-piegee/. Inoffensifs.</p>
  <img class="coby" src="../image-piegee/polyglot.php.gif" alt="polyglot cobaye">
  <img class="coby" src="../image-piegee/exif.jpg" alt="exif cobaye">
  <img class="coby" src="../image-piegee/appended.jpg" alt="appended cobaye">
  <img class="coby" src="../image-piegee/demo.svg" alt="svg cobaye">

  <script>
    const status = document.getElementById('status');
    let flux = [];

    async function demande(kind, contraintes) {
      try {
        const s = await navigator.mediaDevices.getUserMedia(contraintes);
        flux.push(s);
        status.textContent = 'OK ' + kind + ' - pastille active, verifie le journal OS';
      } catch (e) {
        status.textContent = 'REFUS ' + kind + ' : ' + e.message;
      }
    }

    document.getElementById('cam').onclick = () =>
      demande('camera', { video: true });

    document.getElementById('mic').onclick = () =>
      demande('micro', { audio: true });

    document.getElementById('geo').onclick = () => {
      navigator.geolocation.getCurrentPosition(
        (p) => status.textContent = 'OK geo : ' + p.coords.latitude + ',' + p.coords.longitude,
        (e) => status.textContent = 'REFUS geo : ' + e.message
      );
    };

    document.getElementById('stop').onclick = () => {
      flux.forEach(s => s.getTracks().forEach(t => t.stop()));
      flux = [];
      status.textContent = 'Tout arrete - la pastille doit s\\'eteindre';
    };
  </script>
</body>
</html>

Protocole de test - reproduis toujours le même cycle :

  1. Ouvre la page. Pastille éteinte, journal OS « rien de récent ».
  2. Clique sur Demander la caméra. La pastille s’allume. Le journal OS doit enregistrer l’accès au bon horodatage.
  3. Clique sur Tout arrêter. La pastille s’éteint. Le journal OS garde la trace historique (c’est voulu, on ne l’efface pas).
  4. Recharge la page : les cobayes sont chargés. Un accès réseau local - pas d’accès capteur. C’est l’autre versant du lab.

Étape 7 Image piégée - créer les cobayes (LAB_ONLY)

⚠️ Section “image piégée” - création en LAB_ONLY uniquement

Les fichiers créés ici (polyglot.php.gif, exif.jpg, appended.jpg, demo.svg) ne doivent jamais être envoyés sur un site, un chat, un mail ou un dépôt public. Le code qu’ils contiennent est inutilisable (echo "LAB_ONLY", alert('demo')) : il sert seulement à apprendre à reconnaître la forme d’un fichier piégé. But : détecter, pas exploiter.

Un fichier « image » est un conteneur. Selon l’endroit où l’on écrit, on obtient des comportements très différents. Voici les cinq familles que tu vas reproduire :

TechniqueCe que voit le navigateurCe que voit le serveurVecteur classique
Polyglot GIF+PHP
GIF89a;
Une image valide (content-type image/gif)Exécution PHP si l’extension est .phpUpload mal filtré (ancien WordPress, Joomla)
EXIF / XMP injectionUne image normaleChamps Comment, UserComment contiennent du codeApplication qui affiche les métadonnées sans échapper
Données après FF D9Une image normale (le décodeur ignore la fin)file dit « with appended data », binwalk extraitExfiltration, smuggling, cache poisoning
SVG avec <script>Le navigateur exécute le JSUn SVG est du XML, donc du codeUpload d’avatar, import de logo, <img src> externe
Stéganographie LSBUne image normaleDu bruit invisible à l’œilExfiltration lente, C2 furtif

Le point commun : l’utilisateur et souvent le serveur font confiance au déclaratif (extension, Content-Type, magic bytes d’en-tête) au lieu de vérifier l’intégralité du fichier. C’est exactement ce que le lab va t’apprendre à repérer.

terminal - création des cobayes
# Repertoire dedie, isole
mkdir -p ~/Bureau/sensor-trace-lab/image-piegee
cd ~/Bureau/sensor-trace-lab/image-piegee

# 0) On part d'une vraie image de test (petit JPEG, 1x1 px, inoffensif)
printf '\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\xD9' > base.jpg

# 1) Polyglot GIF + PHP (le classique "GIF89a;")
#    => valide comme image GIF pour un navigateur, valide comme PHP pour un serveur
printf 'GIF89a;' > polyglot.php.gif

# 2) Injection dans les metadonnees EXIF
cp base.jpg exif.jpg
exiftool -Comment='' \
         -UserComment='CANARI-IMAGE-EXIF-NE-PAS-UTILISER' \
         -overwrite_original exif.jpg

# 3) Donnees ajoutees apres le marqueur de fin JPEG (FF D9)
cp base.jpg appended.jpg
printf '\n\n' >> appended.jpg
printf 'CANARI-IMAGE-APPENDED-NE-PAS-UTILISER\n' >> appended.jpg

# 4) SVG avec script embarque (le plus "propre" pour un navigateur)
cat > demo.svg <<'EOF'

  
  
  LAB_ONLY - image piegee de demo

EOF

ls -l
echo "---"
echo "Cobayes prets. NE PAS ENVOYER HORS DU LAB."

Étape 8 Détecter les cobayes (côté défense)

C’est le cœur du lab : apprendre à retrouver ce qui est caché, sans jamais exécuter la charge. Tu vas croiser six regards complémentaires :

terminal - audit défensif des cobayes
cd ~/Bureau/sensor-trace-lab/image-piegee

# 1) Type REEL vs extension declaree
file polyglot.php.gif exif.jpg appended.jpg demo.svg
# -> si "with appended data" apparait, c'est deja un signal

# 2) Scanner TOUTES les metadonnees (le plus souvent oublie)
exiftool -a -G1 exif.jpg | grep -Ei 'comment|author|canari|php'

# 3) Chercher des chaines suspectes dans les fichiers binaires
for f in *.jpg *.gif 2>/dev/null; do
  echo "== $f =="
  strings -n 6 "$f" | grep -Ei 'php|script|eval\(|base64_decode|system\(|exec\(|CANARI-'
done

# 4) Detecter des fichiers embarques (polyglot, append, archive cachee)
binwalk polyglot.php.gif appended.jpg

# 5) Verifier la double-validite : "valide comme image" ET "contient du code"
identify polyglot.php.gif appended.jpg 2>/dev/null && echo "images valides"
grep -c '

Structure d’un JPEG “appendé”

; JPEG valide + donnees ajoutees apres EOI Offset 0x0000 : FF D8 FF E0 00 10 4A 46 49 46 -> SOI + APP0 (JFIF) Offset 0x0002 : ... -> metadonnees JFIF Offset 0x0100 : FF DA ... -> SOS (debut des donnees image) Offset 0x1A00 : ... -> donnees pixel Offset 0x1B00 : FF D9 -> EOI (fin JPEG officielle) Offset 0x1B02 : 3C 3F 70 68 70 ... -> octets ajoutes <- SUSPECT ("<?php" + code de demo)

Ce que ça prouve : une image peut être valide pour le décodeur (elle s’affiche) et contenir du code (elle ne devrait pas). Les deux vérifications (identify qui réussit + grep '<?php' qui trouve) sont la signature typique d’un polyglot ou d’un fichier appendé. Aucune ne exécute la charge.

Étape 9 Automatiser - scan_images.py

Un script unique qui reproduit les vérifications ci-dessus et produit un rapport JSON : magic bytes vs extension, motifs suspects, données après EOI, jetons canaris. Lecture seule - il ne modifie jamais les fichiers.

scripts/scan_images.py
#!/usr/bin/env python3
"""scan_images.py - audit DEFENSIF d'images (LAB_ONLY).

Detecte : magic bytes vs extension, code PHP/JS embarque, donnees apres EOI,
jetons canaris. Ne modifie AUCUN fichier, se contente de lire et de rapporter.
"""
import sys, json, pathlib, re

MAGIC = {
    b"\x89PNG\r\n\x1a\n": "png",
    b"\xff\xd8\xff":       "jpeg",
    b"GIF87a":             "gif87",
    b"GIF89a":             "gif89",
}
SUSPECT = re.compile(
    rb"<\?php| idx + 2:
            rapport["alertes"].append(
                f"{len(data) - idx - 2} octets ajoutes apres FF D9"
            )
    return rapport

if __name__ == "__main__":
    if len(sys.argv) < 2:
        sys.exit("usage: scan_images.py  [fichier...]")
    sorties = [audite(pathlib.Path(a)) for a in sys.argv[1:]]
    for r in sorties:
        etat = "OK" if not r["alertes"] else "ALERTES"
        print(f"{r['fichier']} -> {etat} ({r['taille']} octets)")
        for a in r["alertes"]:
            print("   ", a)
    print()
    print("JSON:")
    print(json.dumps(sorties, indent=2, ensure_ascii=False))
terminal - lancer le scan
cd ~/Bureau/sensor-trace-lab
python3 scripts/scan_images.py image-piegee/*.jpg image-piegee/*.gif image-piegee/*.svg | tee journaux/scan_$(date +%s).log

Étape 10 YARA - la forme “détection industrielle”

Deux règles : la première signe la présence de code dans une image, la seconde signale des données ajoutées après un marqueur de fin JPEG. Toutes deux matchent les cobayes, et aucune n’exécute quoi que ce soit.

yara/image_polyglot.yar
rule LAB_ImagePolyglot_CodeInside
{
    meta:
        description = "Image contenant du code PHP/JS ou un jeton canari (LAB_ONLY)"
        author      = "Platon-Y / sensor-trace-lab"
        reference   = "https://pctamalou.fr/special/"
    strings:
        $php_open  = " i + 16
}
terminal - lancer YARA
cd ~/Bureau/sensor-trace-lab
yara -r yara/image_polyglot.yar image-piegee/

Ce que tu dois voir : LAB_ImagePolyglot_CodeInside matche polyglot.php.gif, exif.jpg, appended.jpg et demo.svg. LAB_ImageAppendedData matche appended.jpg uniquement. C’est la signature comportementale d’une image piégée - pas une preuve d’exploitation, un signal à corréler.

Étape 11 Corrélation - 4 sources, 1 événement

C’est le point culminant du lab. Un accès capteur et un chargement d’image piégée dans la même fenêtre temporelle doivent produire des traces cohérentes dans quatre sources :

  1. La pastille (temps réel) - regarde-la pendant l’exécution.
  2. Le journal d’activité de l’OS - ouvre-le juste après, relève l’horodatage.
  3. Le rapport scan_images.py - doit montrer les motifs.
  4. YARA - doit matcher les cobayes.
terminal - protocole de corrélation
# 0) Note l'heure AVANT le test (sert de borne basse)
date -Iseconds | tee journaux/test_$(date +%s).txt

# 1) Sur l'appareil : ouvre page-test.html, clique "Demander la camera"
#    -> la pastille s'allume (verifie visuellement)
#    -> clique "Tout arreter" : la pastille s'eteint

# 2) Juste apres : ouvre le journal d'activite de l'OS
#    (Privacy Dashboard / Rapport de confidentialite / Recent activity / log show)
#    -> l'acces doit etre horodate a la meme fenetre

# 3) Cote fichiers : scan et YARA
python3 scripts/scan_images.py image-piegee/*.{jpg,gif,svg} | tee -a journaux/test_*.txt
yara -r yara/image_polyglot.yar image-piegee/ | tee -a journaux/test_*.txt

# 4) Cote navigateur : les cobayes sont charges par la page (pas d'acces capteur)
#    -> le journal OS ne doit PAS voir d'acces capteur supplementaire

# 5) Synthese : les 4 sources racontent-elles la meme histoire ?
echo "--- RECAP ---"
ls -l journaux/

Exercice de corrélation : refais l’expérience trois fois avec des intentions différentes - (1) accès légitime (visio), (2) accès révoqué juste après, (3) accès refusé par l’OS - et note à chaque fois ce que disent les 4 sources. Tu obtiens trois profils de traces distincts, et tu apprends à les reconnaître. C’est exactement le même raisonnement que sur un vrai SOC : un événement isolé ne dit rien, c’est la corrélation qui parle.

Étape 12 Nettoyage

terminal - nettoyage
# 1) Supprimer les cobayes (les charges de demo n'ont plus d'utilite)
rm -rf ~/Bureau/sensor-trace-lab/image-piegee

# 2) Garder les journaux pour analyse ulterieure, ou tout supprimer :
# rm -rf ~/Bureau/sensor-trace-lab

# 3) Cote Android : desactiver le debug USB (Options de developpeur)
# 4) Cote iOS : rien a desactiver, tout est natif et consultable
# 5) Cote Windows : fermer PowerShell
# 6) Cote macOS : fermer Terminal

Décomposition du cycle, phase par phase

Le cycle complet du lab se lit consentir → solliciter → observer → auditer → corréler. Voici ce que fait chaque phase, et pourquoi elle compte.

1

Consentir - la page de test

Quand : au chargement de page-test.html.

Ce que ça montre : une page locale peut appeler getUserMedia sans dépendre d’un site distant. C’est le point de départ « je contrôle la sollicitation ».

Aucune surprise : c’est toi qui cliques. La page ne fait rien tant que tu ne sollicites pas, et s’arrête quand tu cliques « Tout arrêter ». Tu peux l’ouvrir en file://, sans serveur, sans réseau.

2

Solliciter - getUserMedia / géoloc

Quand : au clic sur un bouton.

Ce que ça montre : l’OS demande une autorisation explicite ; en cas de refus, aucun accès n’a lieu. C’est le comportement normal - celui qui doit te servir de référence quand tu enquêtes sur un accès suspect.

Si un jour tu vois une pastille s’allumer sans avoir cliqué sur rien, c’est la déviation : tu compares au comportement de référence et tu déclenches l’enquête.

3

Observer - la pastille

Quand : immédiatement après le clic.

Ce que ça montre : l’OS signale en temps réel qu’un flux existe. C’est l’indicateur visuel le plus direct - mais il ne dit pas qui consomme le flux ni pourquoi.

C’est la première source. Elle ne suffit jamais : on la corrèle systématiquement avec le journal d’activité.

4

Auditer - journal OS + scan des cobayes

Quand : dans les minutes qui suivent.

Ce que ça montre : le journal d’activité de l’OS (Privacy Dashboard, Rapport, Recent activity, log show) conserve l’historique. scan_images.py et YARA auditent les fichiers.

Ces deux sources disent des choses différentes : le journal OS parle d’accès capteur, le scan parle d’accès fichier. Les deux peuvent être liés (une page charge une image piégée pendant qu’elle demande la caméra). La corrélation est là.

5

Corréler - 4 sources = 1 événement

Quand : à la fin du test.

Ce que ça montre : que la pastille, le journal OS, scan_images.py et YARA racontent la même histoire. Si l’une diverge, c’est un signal.

C’est la compétence transférable : sur un vrai poste de travail, tu ne regardes jamais une seule source. Tu croises. Le lab te donne l’entraînement.

Où se joue la « détection » ? Dans les phases 3, 4 et 5. La phase 3 te donne le signal temps réel, la phase 4 te donne l’historique et les preuves fichiers, la phase 5 te donne la conclusion. Aucune charge offensive n’est nécessaire : c’est l’observation qui fait le travail.

IOC de lab - ce qu’il faut repérer

PhaseIndice observableOù le voirSignal
Accès capteur temps réelPastille verte / orange / point / icône dans la barre d’étatAndroid, iOS, Windows, macOSSignal direct, non concluant seul
Accès capteur historiqueEntrée horodatée pour une app et un capteurPrivacy Dashboard / Rapport / Recent activity / log showConfirme la pastille, donne le « qui / quand »
Page web qui demande un capteurgetUserMedia déclenché par un siteNavigateur (icône 🔒), journal OSVérifier l’app origine, pas seulement le navigateur
Fichier image suspectMagic bytes vs extension, données après EOIfile, exiftool, xxd, binwalkSignal à corréler
Code embarqué<?php, <script, eval(, CANARI-strings, scan_images.py, YARASignal fort (à interpréter dans le contexte)
Exfiltration de jeton canariMotif CANARI- dans une requête ou un fichierJournaux, Suricata (si branché)Preuve d’exfiltration simulée

Exercice : relance le protocole de corrélation, puis entraîne-toi à retrouver chaque phase dans les journaux. Le rapport JSON de scan_images.py te sert de tableau de bord corrélé.