Was macht Analysieren von Windows-LNK-Dateien auf Forensik-Artefakte?
Wann verwenden
- Bei der Rekonstruktion der Dateizugriffshistorie eines Benutzers aus Windows-Verknüpfungsdateien
- Zur Nachverfolgung von zugegriffenen Dateien, Netzwerkfreigaben und Wechselmedien
- Bei Untersuchungen, um zu belegen, dass ein Benutzer bestimmte Dokumente geöffnet hat
- Bei der Korrelation von Dateizugriffen mit anderen Zeitachsen-Artefakten
- Zur Identifizierung von zugegriffenen Pfaden auf entfernten Systemen oder USB-Geräten
Voraussetzungen
- Zugriff auf LNK-Dateien aus einem forensischen Abbild (Recent, Desktop, Quick Launch)
- LECmd (Eric Zimmerman), python-lnk oder LnkParser für die Analyse
- Verständnis der LNK-Dateistruktur (Shell-Link-Binärformat)
- Kenntnis der LNK-Dateispeicherorte unter Windows-Systemen
- Forensische Workstation mit installierten Analysetools
Arbeitsablauf
Schritt 1: LNK-Dateien aus forensischem Abbild sammeln
# Forensisches Abbild mounten
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}
# Recent-Items-LNK-Dateien kopieren (primäre Quelle)
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/*.lnk \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# Automatische Ziele (Jump Lists) kopieren
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/AutomaticDestinations/*.automaticDestinations-ms \
/cases/case-2024-001/lnk/recent/ 2>/dev/null
# Benutzerdefinierte Ziele (angeheftete Jump-List-Elemente) kopieren
cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/CustomDestinations/*.customDestinations-ms \
/cases/case-2024-001/lnk/custom/ 2>/dev/null
# Desktop-Verknüpfungen kopieren
cp /mnt/evidence/Users/*/Desktop/*.lnk /cases/case-2024-001/lnk/desktop/ 2>/dev/null
# Startup-Ordner-Verknüpfungen kopieren (Persistenz)
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
# Alle LNK-Dateien auf dem System finden
find /mnt/evidence/ -name "*.lnk" -type f 2>/dev/null > /cases/case-2024-001/lnk/all_lnk_locations.txt
# Anzahl und Hashes ermitteln
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
Schritt 2: LNK-Dateien mit LECmd parsen
# Eric Zimmermans LECmd verwenden (Windows oder via Mono)
# Alle LNK-Dateien in einem Verzeichnis verarbeiten
LECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf lnk_analysis.csv
# Eine einzelne LNK-Datei mit ausführlicher Ausgabe verarbeiten
LECmd.exe -f "C:\cases\lnk\recent\document.pdf.lnk"
# Jump-List-Dateien verarbeiten
JLECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf jumplist_analysis.csv
# Ausgabe umfasst:
# - Quelldateipfad
# - Zielpfad (Datei, auf die zugegriffen wurde)
# - Erstellungs-, Änderungs- und Zugriffszeitstempel des Ziels
# - Erstellungs- und Änderungszeitstempel der LNK-Datei
# - Arbeitsverzeichnis
# - Befehlszeilenargumente
# - Volume-Seriennummer und -Bezeichnung
# - Laufwerkstyp (Festplatte, Wechselmedium, Netzwerk)
# - Maschinen-ID (NetBIOS-Name)
# - MAC-Adresse (aus der Tracker-Datenbank)
# - Dateigröße des Ziels
Schritt 3: LNK-Dateien mit Python parsen
pip install LnkParse3
python3 << 'PYEOF'
import LnkParse3
import os, json, csv
from datetime import datetime
lnk_dir = '/cases/case-2024-001/lnk/recent/'
ergebnisse = []
for dateiname in sorted(os.listdir(lnk_dir)):
if not dateiname.lower().endswith('.lnk'):
continue
dateipfad = os.path.join(lnk_dir, dateiname)
try:
with open(dateipfad, 'rb') as f:
lnk = LnkParse3.lnk_file(f)
info = lnk.get_json()
geparst = {
'lnk_datei': dateiname,
'zielpfad': '',
'arbeitsverzeichnis': '',
'argumente': '',
'ziel_erstellt': '',
'ziel_geaendert': '',
'ziel_zugegriffen': '',
'dateigroesse': '',
'laufwerkstyp': '',
'volume_seriennummer': '',
'volume_bezeichnung': '',
'maschinen_id': '',
'mac_adresse': '',
}
# Header-Zeitstempel extrahieren
header = info.get('header', {})
geparst['ziel_erstellt'] = str(header.get('creation_time', ''))
geparst['ziel_geaendert'] = str(header.get('modified_time', ''))
geparst['ziel_zugegriffen'] = str(header.get('accessed_time', ''))
geparst['dateigroesse'] = str(header.get('file_size', ''))
# Link-Informationen extrahieren
link_info = info.get('link_info', {})
if link_info:
lokaler_pfad = link_info.get('local_base_path', '')
netzwerkpfad = link_info.get('common_network_relative_link', {}).get('net_name', '')
geparst['zielpfad'] = lokaler_pfad or netzwerkpfad
vol_info = link_info.get('volume_id', {})
if vol_info:
geparst['laufwerkstyp'] = str(vol_info.get('drive_type', ''))
geparst['volume_seriennummer'] = str(vol_info.get('drive_serial_number', ''))
geparst['volume_bezeichnung'] = str(vol_info.get('volume_label', ''))
# Zeichenfolgendaten extrahieren
string_data = info.get('string_data', {})
geparst['arbeitsverzeichnis'] = str(string_data.get('working_dir', ''))
geparst['argumente'] = str(string_data.get('command_line_arguments', ''))
# Tracker-Daten extrahieren (Maschinen-ID und MAC)
extra = info.get('extra', {})
tracker = extra.get('DISTRIBUTED_LINK_TRACKER_BLOCK', {})
if tracker:
geparst['maschinen_id'] = str(tracker.get('machine_id', ''))
geparst['mac_adresse'] = str(tracker.get('mac_address', ''))
ergebnisse.append(geparst)
# Zusammenfassung ausgeben
print(f"\n{dateiname}")
print(f" Ziel: {geparst['zielpfad']}")
print(f" Geändert: {geparst['ziel_geaendert']}")
print(f" Laufwerk: {geparst['laufwerkstyp']} (Seriennummer: {geparst['volume_seriennummer']})")
if geparst['maschinen_id']:
print(f" Maschine: {geparst['maschinen_id']}")
except Exception as e:
print(f" Fehler beim Parsen von {dateiname}: {e}")
# Ergebnisse in CSV schreiben
if ergebnisse:
with open('/cases/case-2024-001/analysis/lnk_analysis.csv', 'w', newline='') as f:
feldnamen = ergebnisse[0].keys()
writer = csv.DictWriter(f, fieldnames=feldnamen)
writer.writeheader()
writer.writerows(ergebnisse)
print(f"\n\nInsgesamt geparste LNK-Dateien: {len(ergebnisse)}")
PYEOF
Schritt 4: Auf investigativen Wert analysieren
# Dateien identifizieren, auf die von Wechselmedien zugegriffen wurde
python3 << 'PYEOF'
import csv
with open('/cases/case-2024-001/analysis/lnk_analysis.csv') as f:
reader = csv.DictReader(f)
print("=== DATEIEN, AUF DIE VON WECHSELMEDIEN ZUGEGRIFFEN WURDE ===\n")
wechselmedien = []
netzwerk = []
for zeile in reader:
if 'DRIVE_REMOVABLE' in zeile.get('laufwerkstyp', '').upper() or \
'removable' in zeile.get('laufwerkstyp', '').lower():
wechselmedien.append(zeile)
print(f" {zeile['ziel_geaendert']} | {zeile['zielpfad']} | Vol: {zeile['volume_seriennummer']}")
if 'network' in zeile.get('laufwerkstyp', '').lower() or \
zeile.get('zielpfad', '').startswith('\\\\'):
netzwerk.append(zeile)
print(f"\n=== DATEIEN, AUF DIE VON NETZWERKFREIGABEN ZUGEGRIFFEN WURDE ===\n")
for zeile in netzwerk:
print(f" {zeile['ziel_geaendert']} | {zeile['zielpfad']}")
print(f"\nDateien von Wechselmedien: {len(wechselmedien)}")
print(f"Dateien von Netzwerkfreigaben: {len(netzwerk)}")
# Auf eindeutige Maschinen prüfen (Tracker-Daten)
maschinen = set()
for zeile in [*wechselmedien, *netzwerk]:
if zeile.get('maschinen_id'):
maschinen.add(zeile['maschinen_id'])
if maschinen:
print(f"\nGefundene Maschinen-IDs: {maschinen}")
PYEOF
# Startup-Ordner-LNK-Dateien auf Persistenz prüfen
echo "=== STARTUP-ORDNER-VERKNÜPFUNGEN (PERSISTENZ) ===" > /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()
ziel = info.get('link_info', {}).get('local_base_path', 'Unbekannt')
args = info.get('string_data', {}).get('command_line_arguments', '')
print(f' \$(basename $lnk): {ziel} {args}')
" >> /cases/case-2024-001/analysis/startup_persistence.txt 2>/dev/null
done
Wichtige Konzepte
| Konzept | Beschreibung |
|---|---|
| Shell Link (.lnk) | Windows-Verknüpfungsdateiformat mit Zielpfad, Zeitstempeln und Metadaten |
| Ziel-Zeitstempel | Erstellungs-, Änderungs- und Zugriffszeiten der Datei, auf die die Verknüpfung zeigt |
| Volume-Seriennummer | Eindeutige Kennung des Datenträgervolumens, auf dem sich die Zieldatei befindet |
| Maschinen-ID | NetBIOS-Name, eingebettet durch den Distributed Link Tracking-Dienst |
| MAC-Adresse | MAC-Adresse des Netzwerkadapters der Maschine, die die LNK-Datei erstellt hat |
| Jump Lists | Letzte und angeheftete Dateilisten pro Anwendung (enthalten eingebettete LNK-Daten) |
| Automatische Ziele | Systemverwaltete Jump-List-Einträge für zuletzt geöffnete Dateien |
| Benutzerdefinierte Ziele | Vom Benutzer angeheftete Jump-List-Elemente, die bis zur manuellen Entfernung bestehen bleiben |
Tools & Systeme
| Werkzeug | Zweck |
|---|---|
| LECmd | Eric Zimmermanns Kommandozeilen-LNK-Parser mit CSV/JSON-Ausgabe |
| JLECmd | Eric Zimmermanns Jump-List-Parser |
| LnkParse3 | Python-Bibliothek für programmatische LNK-Dateianalyse |
| lnk_parser | Alternatives Python-LNK-Parsing-Werkzeug |
| Autopsy | Forensische Plattform mit LNK-Dateianalysemodul |
| KAPE | Automatisierte Sammlung von LNK- und Jump-List-Artefakten |
| Plaso | Zeitachsen-Werkzeug mit LNK-Datei-Parser zur Erstellung von Super-Zeitachsen |
| LNK Explorer | GUI-Werkzeug zur interaktiven LNK-Dateiuntersuchung |
Häufige Szenarien
Szenario 1: Datenexfiltration über USB-Laufwerk Analysieren Sie Recent-Ordner-LNK-Dateien auf Ziele auf Wechseldatenträgern, korrelieren Sie Volume-Seriennummern mit USBSTOR-Registrierungseinträgen, erstellen Sie eine Liste der von USB-Geräten aus zugegriffenen Dateien, ermitteln Sie, welche Dokumente vom Wechseldatenträger geöffnet wurden, korrelieren Sie mit Dateikopier-Zeitstempeln.
Szenario 2: Malware-Persistenz über Startup-Verknüpfungen Untersuchen Sie Startup-Ordner-LNK-Dateien auf schädliche Ziele, prüfen Sie Zielpfad und Argumente auf codierte Befehle oder verdächtige ausführbare Dateien, verifizieren Sie, ob die Zieldatei existiert, und untersuchen Sie sie, korrelieren Sie den Erstellungszeitstempel mit dem Zeitpunkt der ersten Kompromittierung.
Szenario 3: Untersuchung von Netzwerkfreigabenzugriffen Filtern Sie LNK-Dateien mit Netzwerkpfaden (UNC-Ziele), identifizieren Sie, auf welche Netzwerkfreigaben wann zugegriffen wurde, korrelieren Sie Maschinen-IDs mit bekannten Unternehmenssystemen, prüfen Sie, ob außerhalb der normalen Tätigkeiten auf sensible Dateiserver zugegriffen wurde, erstellen Sie eine Zugriffszeitachse für Compliance-Untersuchungen.
Szenario 4: Dokumentenzugriffszeitachse für rechtliche Verfahren Extrahieren Sie alle Recent-Ordner-LNK-Dateien, erstellen Sie eine chronologische Liste der vom Benutzer aufgerufenen Dokumente, identifizieren Sie für den Fall relevante Dateien, präsentieren Sie Zielzeitstempel, die zeigen, wann Dateien geöffnet wurden, korrelieren Sie mit E-Mail- und Kommunikationszeitachsen.
Ausgabeformat
LNK-Dateianalyse-Zusammenfassung:
Benutzerprofil: suspect_user
Gesamtzahl LNK-Dateien: 234 (Recent: 198, Desktop: 23, Startup: 5, Sonstige: 8)
Dateizugriffsstatistiken:
Lokales Laufwerk (C:): 156 Dateien
Wechselmedien: 23 Dateien (3 eindeutige Volume-Seriennummern)
Netzwerkfreigaben: 15 Dateien (\\server01, \\fileserver)
Andere Laufwerke: 4 Dateien
Gefundene Maschinen-IDs: DESKTOP-ABC123, LAPTOP-XYZ789
MAC-Adressen: AA:BB:CC:DD:EE:FF, 11:22:33:44:55:66
Zugriff auf Wechselmedien:
Volume-Seriennummer 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
Startup-Persistenz:
updater.lnk -> C:\ProgramData\svc\updater.exe (VERDÄCHTIG)
OneDrive.lnk -> C:\Users\...\OneDrive.exe (Legitim)
Zeitachse: /cases/case-2024-001/analysis/lnk_analysis.csv