Skip to content
Please update to the latest release 0.77.2 to address Multiple CVEs.
Windows.Registry.NTUser

Windows.Registry.NTUser

Searches for registry keys and values across all users’ NTUSER.DAT hives using raw NTFS parsing.

When a user logs into a windows machine the system creates their own “profile” which consists of a registry hive mapped into the HKEY_USERS hive. This hive file is locked while the user is logged in. If the user is not logged in, the file is not mapped at all.

This artifact bypasses the locking mechanism by parsing the raw NTFS filesystem to recover the registry hives. We then parse the registry hives to search for the glob provided.

This artifact is designed to be reused by other artifacts that need to access user data.

NOTE: Any artifacts that look into the HKEY_USERS registry hive should be using the Windows.Registry.NTUser artifact instead of accessing the hive via the API. The API only makes the currently logged in users available in that hive, so if we rely on the windows API we will miss any settings for the users not currently logged on.


name: Windows.Registry.NTUser
description: |
  Searches for registry keys and values across all users' NTUSER.DAT
  hives using raw NTFS parsing.

  When a user logs into a windows machine the system creates their own
  "profile" which consists of a registry hive mapped into the
  HKEY_USERS hive. This hive file is locked while the user is logged
  in. If the user is not logged in, the file is not mapped at all.

  This artifact bypasses the locking mechanism by parsing the raw NTFS
  filesystem to recover the registry hives. We then parse the registry
  hives to search for the glob provided.

  This artifact is designed to be reused by other artifacts that need
  to access user data.

  **NOTE:** Any artifacts that look into the HKEY_USERS registry hive
  should be using the `Windows.Registry.NTUser` artifact instead of
  accessing the hive via the API. The API only makes the currently
  logged in users available in that hive, so if we rely on the windows
  API we will miss any settings for the users not currently logged on.

precondition: SELECT OS From info() where OS = 'windows'

parameters:
 - name: KeyGlob
   default: Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\**
 - name: userRegex
   default: .
   type: regex

export: |
    // HivePath: The path to the hive on disk
    // RegistryPath: The path in the registry to mount the hive
    // RegMountPoint: The path inside the hive to mount (usually /)
    LET _map_file_to_reg_path(HivePath, RegistryPath, RegMountPoint, Accessor, Description) = dict(
       type="mount", description=Description,
       `from`=dict(accessor='raw_reg',
                   prefix=pathspec(
                      Path=RegMountPoint,
                      DelegateAccessor=Accessor,
                      DelegatePath=HivePath),
                   path_type='registry'),
        `on`=dict(accessor='registry',
                  prefix=RegistryPath,
                  path_type='registry'))

    -- This needs to always be mapped because it is normally denied through the API
    LET _required_mappings = (
       _map_file_to_reg_path(
          HivePath="C:/Windows/System32/Config/SECURITY",
          RegistryPath="HKEY_LOCAL_MACHINE\\Security",
          RegMountPoint="/",
          Accessor='ntfs',
          Description="Map SECURITY Hive to HKEY_LOCAL_MACHINE"),
    )

    LET _standard_mappings = (
       _map_file_to_reg_path(
          HivePath="C:/Windows/System32/Config/SYSTEM",
          RegistryPath="HKEY_LOCAL_MACHINE\\System\\CurrentControlSet",
          RegMountPoint="/ControlSet001",
          Accessor='ntfs',
          Description="Map SYSTEM Hive to CurrentControlSet"),
       _map_file_to_reg_path(
          HivePath="C:/Windows/System32/Config/SOFTWARE",
          RegistryPath="HKEY_LOCAL_MACHINE\\Software",
          RegMountPoint="/",
          Accessor='ntfs',
          Description="Map Software hive to HKEY_LOCAL_MACHINE"),
       _map_file_to_reg_path(
          HivePath="C:/Windows/System32/Config/System",
          RegistryPath="HKEY_LOCAL_MACHINE\\System",
          RegMountPoint="/",
          Accessor='ntfs',
          Description="Map System hive to HKEY_LOCAL_MACHINE")
    )

    LET _make_ntuser_mappings(Accessor, Hive, Subpath) = SELECT _map_file_to_reg_path(
      HivePath=NTUserPath,
      RegMountPoint="/",
      Accessor=Accessor,
      Description=format(format="Map NTUSER.dat from User %v to HKEY_USERS", args=NTUserPath[2]),
      -- This is technically the SID but it is clearer to just use the username
      RegistryPath="HKEY_USERS\\" + NTUserPath[2] + Subpath) AS Mapping
    FROM foreach(row={
       SELECT pathspec(parse=expand(path=Directory),
                       path_type="windows") + Hive  AS NTUserPath
       FROM Artifact.Windows.Sys.Users()
    }, query={
        -- Verify the file actually exists
        SELECT NTUserPath FROM stat(filename=NTUserPath)
    })

    LET _user_mappings =
      _make_ntuser_mappings(Accessor='auto', Hive="NTUser.dat", Subpath="").Mapping +
      _make_ntuser_mappings(Accessor='auto',
        Hive="\\AppData\\Local\\Microsoft\\Windows\\UsrClass.dat",
        Subpath="\\Software\\Classes", Subpath="\\Software\\Classes").Mapping

    // Use this like `LET _ <= MapRawRegistryHives`
    LET MapRawRegistryHives =remap(config=dict(
       remappings=_user_mappings + _standard_mappings + _required_mappings))

sources:
 - query: |
       LET UserProfiles = SELECT Uid,
            Gid,
            Name || "" as Username,
            Description,
            UUID,
            {
                SELECT OSPath FROM glob(
                   root=expand(path=Directory),
                   globs="/NTUSER.DAT",
                   accessor="auto")
            } as OSPath,
            expand(path=Directory) as Directory
       FROM Artifact.Windows.Sys.Users()
       WHERE Directory and OSPath AND Username =~ userRegex

       SELECT * FROM foreach(
            row={
                SELECT * FROM UserProfiles
            },
            query={
                SELECT OSPath, OSPath, Data, Mtime AS Mtime,
                       Username, Description, Uid, Gid, UUID, Directory
                FROM glob(
                    globs=KeyGlob,
                    root=pathspec(
                       DelegateAccessor="ntfs",
                       DelegatePath=OSPath,
                       Path="/"),
                    accessor="raw_reg")
            })