Que fait Analyse des fichiers LNK Windows pour l'extraction d'artefacts ?
Quand l'utiliser
- Lors de la reconstruction de l'historique d'accès aux fichiers d'un utilisateur à partir de fichiers de raccourcis Windows
- Pour tracer les fichiers accédés, les partages réseau et les supports amovibles
- Lors d'enquêtes pour prouver qu'un utilisateur a ouvert des documents spécifiques
- Pour corréler l'accès aux fichiers avec d'autres artefacts de la timeline
- Pour identifier les chemins accédés sur des systèmes distants ou des périphériques USB
Prérequis
- Accès aux fichiers LNK de l'image forensique (Recent, Desktop, Quick Launch)
- LECmd (Eric Zimmerman), python-lnk, ou LnkParser pour l'analyse
- Compréhension de la structure des fichiers LNK (format Shell Link Binary)
- Connaissance des emplacements des fichiers LNK sur les systèmes Windows
- Poste de travail forensique avec les outils d'analyse installés
Workflow
Étape 1 : Collecte des fichiers LNK de l'image forensique
# Monter l'image forensique
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
mkdir -p /cases/case-2024-001/lnk/{recent,desktop,startup,custom}
# Copier les fichiers LNK des éléments récents (source principale)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/*.lnk \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# Copier les destinations automatiques (Jump Lists)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/AutomaticDestinations/*.automaticDestinations-ms \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# Copier les destinations personnalisées (éléments épinglés des Jump Lists)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/CustomDestinations/*.customDestinations-ms \
/cases/case-2024-001/lnk/custom/ 2>/dev/null
# Copier les raccourcis du bureau
cp /mnt/evidence/Users/*/Desktop/*.lnk /cases/case-2024-001/lnk/desktop/ 2>/dev/null
# Copier les raccourcis du dossier Startup (persistance)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Start\ Menu/Programs/Startup/*.lnk \
/cases/case-2024-001/lnk/startup/ 2>/dev/null
cp "/mnt/evidence/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup"/*.lnk \
/cases/case-2024-001/lnk/startup/ 2>/dev/null
# Trouver tous les fichiers LNK sur le système
find /mnt/evidence/ -name "*.lnk" -type f 2>/dev/null > /cases/case-2024-001/lnk/all_lnk_locations.txt
# Compter et hacher
ls /cases/case-2024-001/lnk/recent/ | wc -l
sha256sum /cases/case-2024-001/lnk/recent/*.lnk > /cases/case-2024-001/lnk/lnk_hashes.txt 2>/dev/null
Étape 2 : Analyse des fichiers LNK avec LECmd
# Utiliser LECmd d'Eric Zimmerman (Windows ou via Mono)
# Traiter tous les fichiers LNK d'un dossier
LECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf lnk_analysis.csv
# Traiter un seul fichier LNK avec sortie détaillée
LECmd.exe -f "C:\cases\lnk\recent\document.pdf.lnk"
# Traiter les fichiers Jump List
JLECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf jumplist_analysis.csv
# La sortie inclut :
# - Chemin du fichier source
# - Chemin cible (fichier accédé)
# - Horodatages de création, modification, accès de la cible
# - Horodatages de création et modification du LNK
# - Répertoire de travail
# - Arguments de ligne de commande
# - Numéro de série et étiquette du volume
# - Type de lecteur (Fixe, Amovible, Réseau)
# - Identifiant machine (nom NetBIOS)
# - Adresse MAC (depuis la base de données de suivi)
# - Taille du fichier cible
Étape 3 : Analyse des fichiers LNK avec Python
pip install LnkParse3
python3 << 'PYEOF'
import LnkParse3
import os, json, csv
from datetime import datetime
lnk_dir = '/cases/case-2024-001/lnk/recent/'
results = []
for filename in sorted(os.listdir(lnk_dir)):
if not filename.lower().endswith('.lnk'):
continue
filepath = os.path.join(lnk_dir, filename)
try:
with open(filepath, 'rb') as f:
lnk = LnkParse3.lnk_file(f)
info = lnk.get_json()
parsed = {
'lnk_file': filename,
'target_path': '',
'working_dir': '',
'arguments': '',
'target_created': '',
'target_modified': '',
'target_accessed': '',
'file_size': '',
'drive_type': '',
'volume_serial': '',
'volume_label': '',
'machine_id': '',
'mac_address': '',
}
# Extraire les horodatages d'en-tête
header = info.get('header', {})
parsed['target_created'] = str(header.get('creation_time', ''))
parsed['target_modified'] = str(header.get('modified_time', ''))
parsed['target_accessed'] = str(header.get('accessed_time', ''))
parsed['file_size'] = str(header.get('file_size', ''))
# Extraire les informations de lien
link_info = info.get('link_info', {})
if link_info:
local_path = link_info.get('local_base_path', '')
network_path = link_info.get('common_network_relative_link', {}).get('net_name', '')
parsed['target_path'] = local_path or network_path
vol_info = link_info.get('volume_id', {})
if vol_info:
parsed['drive_type'] = str(vol_info.get('drive_type', ''))
parsed['volume_serial'] = str(vol_info.get('drive_serial_number', ''))
parsed['volume_label'] = str(vol_info.get('volume_label', ''))
# Extraire les données de chaîne
string_data = info.get('string_data', {})
parsed['working_dir'] = str(string_data.get('working_dir', ''))
parsed['arguments'] = str(string_data.get('command_line_arguments', ''))
# Extraire les données de suivi (machine ID et MAC)
extra = info.get('extra', {})
tracker = extra.get('DISTRIBUTED_LINK_TRACKER_BLOCK', {})
if tracker:
parsed['machine_id'] = str(tracker.get('machine_id', ''))
parsed['mac_address'] = str(tracker.get('mac_address', ''))
results.append(parsed)
# Afficher le résumé
print(f"\n{filename}")
print(f" Cible : {parsed['target_path']}")
print(f" Modifié : {parsed['target_modified']}")
print(f" Lecteur : {parsed['drive_type']} (Série : {parsed['volume_serial']})")
if parsed['machine_id']:
print(f" Machine : {parsed['machine_id']}")
except Exception as e:
print(f" Erreur lors de l'analyse de {filename} : {e}")
# Écrire les résultats dans un CSV
with open('/cases/case-2024-001/analysis/lnk_analysis.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=results[0].keys() if results else [])
writer.writeheader()
writer.writerows(results)
print(f"\n\nTotal de fichiers LNK analysés : {len(results)}")
PYEOF
Étape 4 : Analyse pour la valeur d'enquête
# Identifier les fichiers accédés depuis un support amovible
python3 << 'PYEOF'
import csv
with open('/cases/case-2024-001/analysis/lnk_analysis.csv') as f:
reader = csv.DictReader(f)
print("=== FICHIERS ACCÉDÉS DEPUIS UN SUPPORT AMOVIBLE ===\n")
removable = []
network = []
for row in reader:
if 'DRIVE_REMOVABLE' in row.get('drive_type', '').upper() or \
'removable' in row.get('drive_type', '').lower():
removable.append(row)
print(f" {row['target_modified']} | {row['target_path']} | Vol : {row['volume_serial']}")
if 'network' in row.get('drive_type', '').lower() or \
row.get('target_path', '').startswith('\\\\'):
network.append(row)
print(f"\n=== FICHIERS ACCÉDÉS DEPUIS DES PARTAGES RÉSEAU ===\n")
for row in network:
print(f" {row['target_modified']} | {row['target_path']}")
print(f"\nFichiers sur support amovible : {len(removable)}")
print(f"Fichiers sur partage réseau : {len(network)}")
# Vérifier les machines uniques (données de suivi)
machines = set()
for row in [*removable, *network]:
if row.get('machine_id'):
machines.add(row['machine_id'])
if machines:
print(f"\nIdentifiants machine trouvés : {machines}")
PYEOF
# Vérifier les fichiers LNK du dossier Startup pour la persistance
echo "=== RACCOURCIS DU DOSSIER STARTUP (PERSISTANCE) ===" > /cases/case-2024-001/analysis/startup_persistence.txt
for lnk in /cases/case-2024-001/lnk/startup/*.lnk; do
python3 -c "
import LnkParse3
with open('$lnk', 'rb') as f:
lnk = LnkParse3.lnk_file(f)
info = lnk.get_json()
target = info.get('link_info', {}).get('local_base_path', 'Inconnu')
args = info.get('string_data', {}).get('command_line_arguments', '')
print(f' [0m$(basename $lnk): {target} {args}')
" >> /cases/case-2024-001/analysis/startup_persistence.txt 2>/dev/null
done
Concepts clés
| Concept | Description |
|---|---|
| Shell Link (.lnk) | Format de fichier de raccourci Windows contenant le chemin cible, les horodatages et les métadonnées |
| Horodatages cibles | Heures de création, modification et accès du fichier pointé par le raccourci |
| Numéro de série du volume | Identifiant unique du volume de lecteur où se trouve le fichier cible |
| Identifiant machine | Nom NetBIOS intégré par le service Distributed Link Tracking |
| Adresse MAC | Adresse MAC de la carte réseau de la machine ayant créé le fichier LNK |
| Jump Lists | Listes de fichiers récents et épinglés par application (contenant des données LNK intégrées) |
| Destinations automatiques | Entrées de Jump List gérées par le système pour les fichiers récemment ouverts |
| Destinations personnalisées | Éléments de Jump List épinglés par l'utilisateur, persistants jusqu'à suppression manuelle |
Outils et systèmes
| Outil | Objectif |
|---|---|
| LECmd | Analyseur de fichiers LNK en ligne de commande d'Eric Zimmerman avec sortie CSV/JSON |
| JLECmd | Analyseur de Jump Lists d'Eric Zimmerman |
| LnkParse3 | Bibliothèque Python pour l'analyse programmatique de fichiers LNK |
| lnk_parser | Outil alternatif d'analyse LNK en Python |
| Autopsy | Plateforme forensique avec module d'analyse de fichiers LNK |
| KAPE | Collecte automatisée d'artefacts LNK et Jump Lists |
| Plaso | Outil de timeline avec analyseur LNK pour la création de super-timelines |
| LNK Explorer | Outil graphique pour l'examen interactif de fichiers LNK |
Scénarios courants
Scénario 1 : Exfiltration de données via clé USB Analyser les fichiers LNK du dossier Recent pour les cibles sur des lecteurs amovibles, corréler les numéros de série des volumes avec les entrées de registre USBSTOR, établir la liste des fichiers accédés depuis les périphériques USB, déterminer quels documents ont été ouverts depuis le lecteur amovible, corréler avec les horodatages de copie de fichiers.
Scénario 2 : Persistance malveillante via raccourcis Startup Examiner les fichiers LNK du dossier Startup pour des cibles malveillantes, vérifier le chemin cible et les arguments à la recherche de commandes encodées ou d'exécutables suspects, vérifier que le fichier cible existe et l'examiner, corréler l'horodatage de création avec le moment initial de la compromission.
Scénario 3 : Enquête sur l'accès à des partages réseau Filtrer les fichiers LNK avec des chemins réseau (cibles UNC), identifier quels partages réseau ont été accédés et quand, corréler les identifiants machine avec les systèmes connus de l'entreprise, vérifier si des serveurs de fichiers sensibles ont été accédés en dehors des heures normales de travail, établir une timeline d'accès pour une enquête de conformité.
Scénario 4 : Timeline d'accès aux documents pour procédure judiciaire Extraire tous les fichiers LNK du dossier Recent, établir une liste chronologique des documents accédés par l'utilisateur, identifier les fichiers spécifiques pertinents pour l'affaire, présenter les horodatages cibles montrant quand les fichiers ont été ouverts, corréler avec les timelines d'email et de communication.
Format de sortie
Résumé de l'analyse des fichiers LNK :
Profil utilisateur : suspect_user
Total fichiers LNK : 234 (Recent : 198, Desktop : 23, Startup : 5, Autres : 8)
Statistiques d'accès aux fichiers :
Lecteur local (C:) : 156 fichiers
Support amovible : 23 fichiers (3 numéros de série de volume uniques)
Partages réseau : 15 fichiers (\\server01, \\fileserver)
Autres lecteurs : 4 fichiers
Identifiants machine trouvés : DESKTOP-ABC123, LAPTOP-XYZ789
Adresses MAC : AA:BB:CC:DD:EE:FF, 11:22:33:44:55:66
Accès sur support amovible :
Volume série 1234-ABCD :
2024-01-15 14:32 - E:\Confidential\financial_report.xlsx
2024-01-15 14:45 - E:\Confidential\customer_database.csv
2024-01-15 15:00 - E:\Projects\source_code.zip
Persistance Startup :
updater.lnk -> C:\ProgramData\svc\updater.exe (SUSPECT)
OneDrive.lnk -> C:\Users\...\OneDrive.exe (Légitime)
Timeline : /cases/case-2024-001/analysis/lnk_analysis.csv