Skip to content

TaskCache-Forensik: Tree, Tasks und DynamicInfo

Was der TaskCache-Schlüssel im SOFTWARE-Hive zu jeder geplanten Aufgabe speichert: Tree mit Id/Index/SD, Tasks-Werte, DynamicInfo, Actions, Triggers und Hash.

Veröffentlicht am 7 Min. Lesezeit

Kurz gesagt. TaskCache besteht aus zwei Hälften. Tree\<path> ordnet einem Aufgabennamen seine GUID (Id), eine Kategorie (Index) und eine Sicherheitsbeschreibung (SD) zu. Tasks\{GUID} speichert Path, URI, Author, Date, Hash, Actions, Triggers und DynamicInfo, dessen FILETIMEs Erstellung, letzte Ausführung und letzte erfolgreiche Ausführung in UTC liefern. Die Binärformate wurden von der Community per Reverse Engineering erschlossen: Vertrauen Sie den gut belegten Feldern und prüfen Sie den Rest gegen andere Quellen.

Dies ist der Registry-Schwerpunkt der Serie, die mit dem Leitfaden zur Forensik geplanter Aufgaben beginnt. Die wichtigsten Quellen sind die Analyse von cyber.wtf (Windows 10 1909, gegengeprüft mit Windows 7) und winreg-kb von libyal. Microsoft dokumentiert diese Werte nicht.

Aufbau des Schlüssels

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache
├── Tree\<folder>\<task name>      Id, Index, SD
├── Tasks\{GUID}                   Path, URI, Author, Date, Hash, Actions, Triggers, DynamicInfo, ...
├── Boot\{GUID}
├── Logon\{GUID}
├── Plain\{GUID}
└── Maintenance\{GUID}

Tree spiegelt die Ordnerstruktur von C:\Windows\System32\Tasks. Tasks ist flach, mit einem Schlüssel pro Aufgaben-GUID. Die vier Kategorieschlüssel enthalten je einen Unterschlüssel pro Aufgaben-GUID dieser Kategorie.

Tree: Namen, Kategorien, Berechtigungen

WertTypBedeutung
IdStringDie Aufgaben-GUID, z. B. {8A1B...}, verweist auf Tasks\{GUID}
IndexDWORDKategorie. cyber.wtf ordnet zu: 1 Boot, 2 Logon, 3 Plain, 4 Maintenance; Ordner haben keinen Index
SDBinarySelbstrelative Sicherheitsbeschreibung, die den Zugriff auf die Aufgabe regelt

Drei Punkte sollten Sie bei jedem Tree-Eintrag prüfen:

  1. Ist SD vorhanden? Ein Aufgabenschlüssel ohne SD ist für schtasks und die Konsole unsichtbar. Das ist die Versteckmethode von Tarrask (Microsoft, 2022).
  2. Verweigert die dekodierte SD den Lesezugriff? Binary Defense hat gezeigt, dass eine gültige Beschreibung, die allen das Lesen verweigert, eine Aufgabe genauso gut versteckt und dabei unauffällig aussieht (Binary Defense). Lesen Sie die SDDL, statt nur zu prüfen, ob der Wert existiert.
  3. Ist Index plausibel? MITRE führt das Ändern des Werts Index als weitere Versteckmethode auf (T1053.005). Ein Wert 0 bei einer Aufgabe oder ein Index, der nicht zu dem Kategorieschlüssel passt, unter dem die GUID auftaucht, verdient eine Notiz.

Die Last-Write-Zeit des Tree-Schlüssels ist eine FILETIME in UTC, die sich bei jeder Änderung eines Werts in diesem Schlüssel aktualisiert. Bei einer normalen Aufgabe liegt sie nahe am Registrierungszeitpunkt. Liegt sie deutlich nach der Erstellungszeit aus DynamicInfo, hat etwas den Schlüssel neu geschrieben; bei einer Aufgabe im Tarrask-Stil kann das der Moment sein, in dem SD gelöscht wurde. Das ist eine Schlussfolgerung, kein direkter Nachweis, und so sollten Sie es im Bericht auch formulieren.

Tasks{GUID}: die Aufgabendaten

WertBedeutung
PathAufgabenpfad, z. B. \Microsoft\Windows\Defrag\ScheduledDefrag
URIIdentisch mit dem XML-Element URI, sofern vorhanden
Author, Description, Source, Version, DocumentationKopien der Felder aus RegistrationInfo
DateRegistrierungsdatum als String, im selben zeitzonenlosen Format wie in der XML
HashIntegritäts-Hash der XML-Datei, siehe unten
SchemaSchemaversion als Zahl
SecurityDescriptorOptionale SDDL aus der XML
ActionsBinäre Serialisierung der Aktionen
TriggersBinäre Serialisierung von Triggern, Principal und Einstellungen
DynamicInfoBinärer Datensatz zum Ausführungsstatus

Nicht jeder Wert existiert bei jeder Aufgabe. cyber.wtf merkt an, dass offenbar nur Actions und Triggers nötig sind, damit die Aufgabe in der Konsole erscheint.

DynamicInfo

DynamicInfo ist der Grund, TaskCache immer auszuwerten. Das Layout nach cyber.wtf, stimmig mit den Größenangaben in winreg-kb (28 Bytes unter Vista/7, 36 Bytes ab Windows 8):

OffsetGrößeFeld
04Version / Magic, typischerweise 3
48FILETIME: erstellt (Registrierung oder letzte Aktualisierung)
128FILETIME: letzte Ausführung
204Aufgabenstatus
244Letzter Ergebniscode (HRESULT, z. B. 0x80070002 Datei nicht gefunden)
288FILETIME: letzte erfolgreiche Ausführung (nur ab Windows 8)

winreg-kb bezeichnet die ersten beiden Zeitstempel als "unknown" und vermutet "last registered or update time?" sowie "launch time?"; cyber.wtf benennt sie wie oben. In der Praxis verschiebt sich der Wert "erstellt", wenn eine Aufgabe neu registriert wird. Lesen Sie ihn daher als letzte Registrierung, nicht als erstmalige Erstellung. Der letzte Ergebniscode ist oft das nützlichste Feld: Eine Persistenzaufgabe, die erfolgreich gelaufen ist, zeigt 0x0; eine, deren Binärdatei entfernt wurde, zeigt ein HRESULT für "Datei nicht gefunden".

Alle drei FILETIMEs sind UTC. Damit sind sie der Anker für das zeitzonenlose XML-Feld Date, wie in Aufbau der Aufgaben-XML erklärt.

Der Actions-Blob

Der Wert Actions beginnt mit einem Versions-Word, danach folgt der String des Principal-Kontexts und dann ein Datensatz pro Aktion, erkennbar an einem Magic-Wert (cyber.wtf):

MagicAktion
0x6666Exec: Befehl, Argumente, Arbeitsverzeichnis
0x7777ComHandler: CLSID und Daten
0x8888SendEmail
0x9999ShowMessage

Strings sind UTF-16 mit Längenpräfix. Fehlt die XML-Datei, erfahren Sie über diesen Blob trotzdem, was die Aufgabe ausgeführt hat. Vergleichen Sie ihn mit der XML, wenn beide vorhanden sind: Ein Angreifer, der die Registry direkt bearbeitet, kann die Aktion ändern, ohne die Datei anzufassen, oder umgekehrt.

Der Triggers-Blob

Triggers beginnt mit einem Header (Version, dann ein "Job Bucket" mit Flags, einer CRC32, der Principal-ID, Benutzerinformationen und optionalen Einstellungen), gefolgt von Trigger-Datensätzen verschiedener Typen, jeweils mit eigenem Magic-Wert und 8-Byte-Ausrichtung. Das Header-Layout ist recht gut verstanden; die einzelnen Trigger-Datensätze unterscheiden sich je nach Windows-Version und sind weniger gesichert. Ein Parser kann den Header und den Principal (das Konto, unter dem die Aufgabe läuft) zuverlässig auslesen. Behandeln Sie aus dem Blob dekodierte Trigger-Details als Best-Effort und bevorzugen Sie die XML, wenn sie vorliegt.

Hash

Über den Wert Hash erkennt der Dienst, ob eine XML-Datei außerhalb seiner Kontrolle verändert wurde. winreg-kb verzeichnet ihn als SHA-256, auf Systemen vor dem Update KB2305420 als CRC32. Auf aktuellen Windows-10- und Windows-11-Systemen ist er nach Beobachtung der SHA-256 des XML-Dateiinhalts ohne die zwei Byte lange UTF-16-BOM.

Ihn neu zu berechnen ist eine günstige Integritätsprüfung:

  • Übereinstimmung: Die XML auf dem Datenträger entspricht dem, was der Dienst registriert hat.
  • Abweichung: Die Datei wurde nach der Registrierung bearbeitet, oder der Registry-Eintrag, oder die Datei wurde von anderswo wiederhergestellt. In jedem Fall widersprechen sich die beiden Kopien: Lesen Sie beide.
  • Keine XML: Die Datei wurde gelöscht; die Registry ist die einzige verbliebene Definition.

TaskCache mit den XML-Dateien korrelieren

Ordnen Sie jedem Tree-Schlüssel die XML-Datei mit demselben relativen Pfad unter System32\Tasks zu. Listen Sie dann auf:

SituationTypische ErklärungVorgehen
XML und TaskCache, Hash stimmtNormalTriage anhand des Inhalts
Nur TaskCache (keine XML)XML von Hand oder durch ein Bereinigungstool gelöscht; die Aufgabe läuft womöglich weiterHohe Priorität: Actions dekodieren
Nur XML (kein TaskCache)Datei abgelegt, aber nie registriert, Registry bereinigt oder Hive in inkonsistentem ZustandHive-Zustand und Ereignisprotokolle prüfen
Tree ohne SDVersteckte Aufgabe (Tarrask-Stil)Hohe Priorität
Hash-AbweichungDatei oder Registry nach der Registrierung geändertBeide Definitionen vergleichen

Ein Vorbehalt, bevor Sie etwas als "fehlend" einstufen: Wurde der SOFTWARE-Hive im laufenden Betrieb kopiert, ohne seine Transaktionsprotokolle einzuspielen, können jüngste Registry-Änderungen fehlen. Siehe Speicherorte und Sicherung geplanter Aufgaben.

Der Scheduled Tasks Parser führt diese Korrelation durch, berechnet den Hash neu, dekodiert die SD zu SDDL, DynamicInfo, Actions und den Triggers-Header und markiert Aufgaben, die nur in der Registry, nur auf dem Datenträger oder ohne SD existieren. Für umfangreichere Registry-Analysen deckt der Registry Parser den Rest des Hives ab.

FAQ

Was ist der Registry-Schlüssel TaskCache?

Unter HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache hält der Aufgabenplanungsdienst seine Kopie jeder registrierten Aufgabe vor: Namen und Sicherheitsbeschreibungen unter Tree, Aufgabendaten unter Tasks\{GUID} und Kategorielisten unter Boot, Logon, Plain und Maintenance.

Welche Zeitstempel enthält DynamicInfo?

Ab Windows 8 umfasst der Wert meist 36 Bytes: ein Versions-DWORD, eine FILETIME, die üblicherweise als Erstellungs- oder Registrierungszeit der Aufgabe gedeutet wird, eine FILETIME der letzten Ausführung, ein DWORD für den Aufgabenstatus, einen letzten Ergebniscode und eine FILETIME der letzten erfolgreichen Ausführung. Das Layout stammt aus Community-Recherchen, nicht aus Microsoft-Dokumentation.

Was ist der Wert Hash in TaskCache\Tasks?

Ein Integritäts-Hash der Aufgaben-XML. Auf aktuellen Systemen ist er nach Beobachtung ein SHA-256 der XML-Datei ohne ihre zwei Byte lange Byte Order Mark; ältere Systeme verwendeten CRC32. Weicht er von der XML auf dem Datenträger ab, wurde eine der beiden Kopien nach der Registrierung verändert.

Verwandte Artikel

Forensik geplanter Aufgaben von A bis Z: Task-XML-Dateien, der Registry-Schlüssel TaskCache, alte .job-Dateien und Ereignisprotokolle und wie Sie sie korrelieren.
Schritt für Schritt: Task-XML, .job-Dateien und SOFTWARE-Hive im kostenlosen Browser-Parser auswerten, versteckte Tasks finden, Zeitzonen klären, exportieren.
Checkliste für bösartige geplante Aufgaben: beschreibbare Pfade, kodiertes PowerShell, LOLBins, SYSTEM, Zufallsnamen, versteckte Tasks, XML/Registry-Abweichungen.