Registry Parser
All articles

Detecting T1547.001: registry Run-key persistence

7 min read

If you are mapping detections to a framework, T1547.001 is the entry every Windows registry hunt eventually touches. MITRE files it under Boot or Logon Autostart Execution: adversaries add a value to a registry Run key, or drop a binary into a Startup folder, and the operating system runs it for them at the next logon. No exploit, no privilege beyond writing the key, no novel tradecraft. It is the most common persistence mechanism on the planet precisely because it is trivial, durable, and survives reboots. This post is the detection-and-investigation companion to the broader Run keys and IFEO deep-dive: same keys, but framed as registry persistence detection — where T1547.001 lives, what a clean baseline looks like, and how to hunt the malicious entries hiding among legitimate ones.

For how the ATT&CK matrix lines up against registry artifacts in general, see MITRE ATT&CK and the registry. This post drills into one sub-technique.

Where it lives in the registry

T1547.001 covers a specific, enumerable set of keys. Walk all of them — attackers reach for the less-checked variants precisely because defenders stop at the first two.

Machine-wide, in the SOFTWARE hive (fires for every user at logon, requires admin to write):

  • HKLM\Software\Microsoft\Windows\CurrentVersion\Run
  • HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce — fires once at next logon, then the value deletes itself. Common in installers; periodically abused.
  • HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnceEx — runs before Explorer, sequentially, and can load DLLs via a Depend subkey. Uncommon enough that any entry deserves scrutiny.
  • HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run (and RunOnce, RunOnceEx) — the 32-bit-on-64-bit view of the same keys. Always check both views. A tool that only reads the native view misses anything written here.

Per-user, in each NTUSER.DAT (fires at that user's logon, writable by the user — no admin needed):

  • HKCU\Software\Microsoft\Windows\CurrentVersion\Run
  • HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Run — undocumented Run-equivalent.

Policy-backed Run keys, set by Group Policy but writable directly:

  • HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run

These two are a favourite because most ad-hoc autostart checks never look under Policies\Explorer. Entries here run at logon like any Run value.

The Load and Run values (a pre-NT survival that still fires):

  • HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\Load
  • HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\Run

Both are single string values, not keys with multiple entries, and both are empty on a clean install. A populated Load or Run is anomalous by default.

The Startup folder, which T1547.001 also covers and which the registry redirects:

  • HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders and Shell Folders
  • HKCU\...\Explorer\User Shell Folders and Shell Folders

Common Startup and Startup point at the directories whose contents run at logon. Default targets are %ProgramData%\Microsoft\Windows\Start Menu\Programs\StartUp and the per-user equivalent. Repointing either value at a user-writable directory turns every file in that directory into an autostart — rare, because it needs SOFTWARE write, but devastating and routinely missed.

What normal looks like

You cannot hunt T1547.001 without knowing the baseline, because the keys are never empty. A freshly imaged enterprise host carries a predictable set of Run values, and they are boring on purpose:

  • HKLM\...\Run typically holds SecurityHealth (%windir%\system32\SecurityHealthSystray.exe), RtkAudUService or another audio driver tray app, vendor management agents, and your EDR's tray component. Every value resolves to a signed binary under Program Files, Program Files (x86), or System32.
  • HKCU\...\Run holds per-user app launchers — OneDrive (%localappdata%\Microsoft\OneDrive\OneDrive.exe /background), Teams, a cloud-storage client, maybe a notes app. These do live under %LOCALAPPDATA%, which is the wrinkle: OneDrive's legitimate Run entry points into AppData, so "AppData equals bad" is too blunt a rule for HKCU.
  • RunOnce is usually empty between installs. A pending value referencing an MSI or a setup wrapper is normal mid-install and gone afterward.
  • Load, Run, Policies\Explorer\Run, and the Wow6432Node Run keys are empty on most hosts. RunOnceEx is empty.
  • User Shell Folders\Common Startup and Startup point at the default Start Menu paths and nothing else.

The shape of a clean baseline: a short list of named values, each pointing at a signed vendor binary in a system or Program Files directory, with the few legitimate AppData exceptions (OneDrive, Teams) that you can name. Capture this once from a golden image and you have turned every subsequent hunt into a diff.

How to hunt it

Registry persistence detection here is a diff-and-filter exercise, not a creative one. The patterns that catch real intrusions:

Baseline diffing first. Dump every value from every key listed above across every NTUSER.DAT and the SOFTWARE hive, then diff against your golden-image baseline. Anything that is not in the baseline is your candidate list. This single step eliminates the vendor noise that makes manual review tedious. If you have VSS snapshots, diff the live hive against a snapshot from before the suspected intrusion window — a Run value present now but absent two days ago is the incident, with the timestamp range already narrowed.

Suspicious paths and interpreters. On the candidate list, flag values whose data:

  • references a scripting or living-off-the-land binary — powershell.exe, pwsh.exe, cmd.exe /c, wscript.exe, cscript.exe, mshta.exe, rundll32.exe, regsvr32.exe, msbuild.exe. A Run value should usually be a path to an application, not a command-line invoking an interpreter.
  • points into %TEMP%, %APPDATA%, %LOCALAPPDATA% (outside the known OneDrive/Teams exceptions), \Users\Public\, C:\ProgramData\<random>\, or \Windows\ root rather than System32.
  • carries an encoded or obfuscated payload — -enc, -EncodedCommand, -e followed by base64, FromBase64String, IEX, heavy escaping, or a long single-line blob. Encoded PowerShell in a Run value is malicious until proven otherwise; legitimate software does not hide its launch command.
  • invokes rundll32/regsvr32 against a DLL in a user-writable path, or mshta against a URL or a local .hta.

Key LastWrite recency. Each Run key carries a LastWrite timestamp (the values do not). Sort your keys by it. A Run key written within your intrusion window, against a backdrop of keys untouched since OS install, is a strong lead. The caveat from the services world applies: LastWrite updates on any value change, so recency tells you the key was touched, not when a specific value was created — necessary, not sufficient. Corroborate the named binary with AmCache, Prefetch, Shimcache, and Security 4688 / Sysmon 1 process-creation events.

The delete-after-run trick. A careful attacker writes a Run value, lets the payload fire, then deletes the value. The key's LastWrite reflects the deletion, and the value is gone from the live hive — but it lingers in the transaction logs (.LOG1/.LOG2) if the deletion was recent, in VSS, and in unallocated hive cells recoverable with yarp or RegRipper's del plugin. Always acquire the logs alongside the hive.

Investigate it in your browser

You do not need a Perl environment or a mounted hive to triage T1547.001. Load the NTUSER.DAT or SOFTWARE hive into the browser-based parser and analyze the hive in your browser — nothing leaves the machine, and you get the raw values plus each key's LastWrite, which is exactly what the diff-and-sort workflow above needs. Paste a path like Software\Microsoft\Windows\CurrentVersion\Run straight into the tree to jump to the key.

The automated Findings pass walks the T1547.001 key set for you and flags the patterns from the hunting section: Run values invoking interpreters, paths into %TEMP%/%APPDATA%, encoded command lines, populated Load/Run values, and Policies\Explorer\Run entries. Treat it as the first pass that surfaces the boring stuff; then walk the raw values yourself, because automated rules are tuned to avoid false positives and will under-flag a sufficiently clever path. The clean-baseline mindset still does the heavy lifting — Findings narrows the candidates, your knowledge of what this host should look like confirms them.

Related techniques

Run keys are one autostart surface among several, and an attacker who assumes you check Run keys will fall back to a neighbour:

  • The IFEO debugger trick, Userinit, and Shell hijacks live in the Run keys and IFEO post — same logon-autostart family, different keys.
  • Winlogon Userinit/Shell/Notify are their own ATT&CK sub-technique; see the Winlogon deep-dive.
  • Services (T1543.003) are the enterprise-intrusion workhorse and run before any user logs in; the services plugin post covers the SYSTEM-hive side.

Run the diff, filter on interpreters and user-writable paths, sort by LastWrite, and confirm against your baseline. T1547.001 is the boring path, which is exactly why it catches most of the incidents. Reference: MITRE ATT&CK T1547.001.