SEC504: Hacker Tools, Techniques, and Incident Handling

Experience SANS training through course previews.
Learn MoreLet us help.
Contact usConnect, learn, and share with other cybersecurity professionals
Engage, challenge, and network with fellow CISOs in this exclusive community of security leaders
Become a member for instant access to our free resources.
Sign UpMission-focused cybersecurity training for government, defense, and education
Explore industry-specific programming and customized training solutions
Sponsor a SANS event or research paper
We're here to help.
Contact UsThe Windows Registry can be pretty frustrating. That is, until I discovered that you can treat the registry just like the file system in PowerShell.
In general, I find working with the Windows Registry pretty frustrating. It's organized like a file system, but not as accessible. That is, until I discovered that you can treat the registry just like the file system in PowerShell. Almost.
If you want the TL/DR version; press End/FN+DownArrow and skip to the bottom of this article for a table summary of commands!
To start, open PowerShell on Windows and run the [code]Get-PSDrive[/code] cmdlet:
PS C:\Users\Sec504> Get-PSDrive
Name Used (GB) Free (GB) Provider Root CurrentLocation
---- --------- --------- -------- ---- ---------------
Alias Alias
C 29.81 10.19 FileSystem C:\ Users\Sec504
Cert Certificate \
D FileSystem D:\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Variable Variable
WSMan WSMan
In PowerShell we have PowerShell providers, ".NET programs that provide access to specialized data stores for easier viewing and management." (source: about_Providers) This includes the Windows Registry. We can access all of the registry data by accessing the top-level registry keys HKCU and HKLM (for HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE) as drive letters:
PS C:\Users\Sec504> Set-Location HKLM:
PS HKLM:\>
With the [code]HKLM:[/code] and [code]HKCU:[/code] drives, we can list the contents of registry keys using [code]Get-ChildItem[/code]:
PS HKLM:\> Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
Name Property
---- --------
AccountPicture
ActionCenter
AdvertisingInfo Enabled : 0
App Management
App Paths
AppHost EnableWebContentEvaluation : 1
Applets
...
We can also use [code]Set-Location[/code] (e.g., [code]cd[/code]) to change to a working location:
PS HKLM:\> Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ChildItem
Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
Name Property
---- --------
AccountPicture
ActionCenter
AdvertisingInfo Enabled : 0
App Management
App Paths
AppHost EnableWebContentEvaluation : 1
...
When we run [code]Get-ChildItem[/code], we'll see both registry keys and values. If you only want to see subkeys, use [code]Select-Object PSChildName[/code] in the pipeline:
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ChildItem | Select-Object PSChildName
PSChildName
-----------
AccountPicture
ActionCenter
AdvertisingInfo
App Management
App Paths
AppHost
If you only want to see values but not sub-keys, use [code]Get-ItemProperty[/code] (using the relative location [code].[/code] or the fully-qualified key location, shown here):
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemProperty .
ProgramFilesDir : C:\Program Files
CommonFilesDir : C:\Program Files\Common Files
ProgramFilesDir (x86) : C:\Program Files (x86)
CommonFilesDir (x86) : C:\Program Files (x86)\Common Files
CommonW6432Dir : C:\Program Files\Common Files
DevicePath : C:\WINDOWS\inf
MediaPathUnexpanded : C:\WINDOWS\Media
ProgramFilesPath : C:\Program Files
ProgramW6432Dir : C:\Program Files
SM_ConfigureProgramsName : Set Program Access and Defaults
SM_GamesName : Games
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
PSChildName : CurrentVersion
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
ProgramFilesDir : C:\Program Files
CommonFilesDir : C:\Program Files\Common Files
ProgramFilesDir (x86) : C:\Program Files (x86)
CommonFilesDir (x86) : C:\Program Files (x86)\Common Files
CommonW6432Dir : C:\Program Files\Common Files
DevicePath : C:\WINDOWS\inf
...
If you want to see the value of a specific registry key value, use [code]Get-ItemPropertyValue[/code], specifying both the registry key (as a default argument, or with the [code]-Path[/code] parameter), as well as the registry value name with the [code]-Name[/code] parameter (again in this example I use the relative location [code].[/code] and the fully-qualified location to show how both can be used):
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemPropertyValue . -Name ProgramFilesDir
C:\Program Files
PS HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion> Get-ItemPropertyValue HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name ProgramFilesDir
C:\Program Files
Let's take a look at creating registry keys. We'll stick with the non-privileged PowerShell session, and create (then later, remove) a temporary registry key in HKEY_CURRENT_USER. First, change to the [code]HKCU:[/code] drive provider and the [code]SOFTWARE[/code] key, then list the sub-keys:
PS HKLM:\> Set-Location HKCU:\SOFTWARE
PS HKCU:\SOFTWARE> Get-ChildItem | Select-Object -Property PSChildName
PSChildName
-----------
7-Zip
APN PIP
AppDataLow
Bogosoft
Cygwin
Google
Intel
JavaSoft
Local AppWizard-Generated Applications
Microsoft
Monobob2022
...
You can test if a registry key exists using [code]Test-Path[/code]. Let's see how this looks; run [code]Test-Path MyKey[/code]:
PS HKCU:\SOFTWARE> Test-Path MyKey
False
To create the key, use [code]New-Item[/code] with the [code]-Path[/code] and [code]-Name[/code] arguments.
PS HKCU:\SOFTWARE> New-Item -Path . -Name MyKey
Hive: HKEY_CURRENT_USER\SOFTWARE
Name Property
---- --------
MyKey
PS HKCU:\SOFTWARE> Test-Path MyKey
True
Every registry key has a default value (this is a holdover from the days when a registry key could only hold one value per key. To specify a default value, use [code]New-Item[/code]:
PS HKCU:\SOFTWARE> Set-Item -Path .\MyKey\ -Value "My default key value"
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\
(default) : My default key value
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName : MyKey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
To add a new value in the key, use [code]New-ItemProperty[/code] with the [code]-Path[/code], [code]-Name[/code], and [code]-Value[/code] arguments:
PS HKCU:\SOFTWARE> New-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValue -Value "My custom data"
MyCustomKeyValue : My custom data
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName : MyKey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\
(default) : My default key value
MyCustomKeyValue : My custom data
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName : MyKey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
So far, we've only been working with string objects. We can specify other data types, such as the DWORD integer type by adding [code]-PropertyType[/code]:
PS HKCU:\SOFTWARE> New-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValueDWORD -PropertyType DWORD -Value 12345
MyCustomKeyValueDWORD : 12345
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName : MyKey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\
(default) : My default key value
MyCustomKeyValue : My custom data
MyCustomKeyValueDWORD : 12345
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName : MyKey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
To delete a value in a registry key, use [code]Remove-ItemProperty[/code]:
PS HKCU:\SOFTWARE> Remove-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValueDWORD
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\
(default) : My default key value
MyCustomKeyValue : My custom data
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName : MyKey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
PS HKCU:\SOFTWARE> Remove-ItemProperty -Path .\MyKey\ -Name MyCustomKeyValue
PS HKCU:\SOFTWARE> Get-ItemProperty -Path .\MyKey\
(default) : My default key value
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE
PSChildName : MyKey
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
Excellent!
To clean up, let's remove the registry key [code]MyKey[/code] with [code]Remove-Item[/code]. I've added the [code]-Confirm[/code] option for safety; you can delete the key without being prompted to confirm by omitting [code]-Confirm[/code].
PS HKCU:\SOFTWARE> Remove-Item .\MyKey\ -Confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove Key" on target "Item: HKEY_CURRENT_USER\SOFTWARE\MyKey\".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y
PS HKCU:\SOFTWARE>
Next, let's take a look at the steps to search for a registry key. Let's search for a key named [code]BrowserEmulation[/code] (associated with Microsoft Edge, which everyone will have on their Windows systems).
Unfortunately, not all drive providers support the same parameters. While searching for a file on the file system with [code]Get-ChildItem[/code] is pretty straightforward ([code]Get-ChildItem -Path C:\ -Name mimikatz.exe -Recurse[/code] will find all files with the name [code]mimikatz.exe[/code], for example), this won't work with registry keys:
PS HKCU:\SOFTWARE> Get-ChildItem -Recurse -Path . -Name "BrowserEmulation"
Get-ChildItem : Cannot call method. The provider does not support the use of filters.
At line:1 char:1
+ Get-ChildItem -Recurse -Path . -Name "BrowserEmulation"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotImplemented: (:) [Get-ChildItem], PSNotSupportedException
+ FullyQualifiedErrorId : NotSupported,Microsoft.PowerShell.Commands.GetChildItemCommand
As an alternative, we can perform the recursive search for keys and use the pipeline to filter the results. This is not ideal for performance reasons, but it works reasonably well if you are patient:
PS HKCU:\SOFTWARE> Get-ChildItem -Recurse -Path . | Where-Object -Property Name -Like '*BrowserEmulation*' | Select-Object -Property PSPath
PSPath
------
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\BrowserEmulation
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\BrowserEmulation\LowMic
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\MicrosoftEdge\BrowserEmulation
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge\BrowserEmulation
Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge\BrowserEmulat...
If you want to find a registry value by name, we can use a similar [code]Get-ChildItem[/code] command, filtering by the [code]Property[/code] property instead of [code]Name[/code]. For example, to search for a registry value name called [code]LastLogonTime-Machine[/code], use the following command:
PS HKCU:\SOFTWARE> Get-ChildItem -Recurse -Path . | Where-Object -Property Property -EQ 'LastLogonTime-Machine'
Hive: HKEY_CURRENT_USER\SOFTWARE\Microsoft
Name Property
---- --------
EdgeUpdate LastLogonTime-Machine : 133009855555826276
Here's a summary of the commands we reviewed to access and manipulate the Windows Registry.
Task | Command |
---|---|
Change location to HKEY_CURRENT_USER | [code]Set-Location HKCU:[/code] |
Change location to HKEY_LOCAL_MACHINE | [code]Set-Location HKLM:[/code] |
List registry subkeys and values | [code]Get-ChildItem[/code] |
List registry subkeys only | [code]Get-ChildItem | Select-Object PSChildName[/code] |
List registry values only | [code]Get-ItemProperty .[/code] |
Access the registry data for a specific value | [code]Get-ItemPropertyValue[/code] (specify [code]-Path[/code] and [code]-Name[/code]) |
Test is a registry key exists | [code]Test-Path[/code] |
Create a registry key | [code]New-Item[/code] (specify [code]-Path[/code] and [code]-Name[/code]) |
Set a default registry key value | [code]Set-Item[/code] (specify [code]-Path[/code] and [code]-Value[/code], omitting [code]-Name[/code]) |
Set a named registry key value | [code]Set-Item[/code] (specify [code]-Path[/code], [code]-Value[/code], and [code]-Name[/code]) |
Delete a registry value | [code]Remove-ItemProperty[/code] (specify [code]-Path[/code] and [code]-Name[/code]) |
Delete a registry key | [code]Remove-Item[/code] |
Search for a registry key | [code]Get-ChildItem -Recurse[/code] (specify [code]-Path[/code] and [code]-Name[/code] where [code]-Name[/code] uses wildcards) |
Search for a registry value name | [code]Get-ChildItem -Recurse -Path . | Where-Object -Property Property -EQ 'SearchValueName'[/code] |
We'll continue to look at how to apply these commands to interrogate and manipulate the registry throughout the
-Joshua Wright
Return to Getting Started With PowerShell
Joshua Wright is the author of SANS SEC504: Hacker Tools, Techniques, and Incident Handling, a faculty fellow for the SANS Institute, and a senior technical director at Counter Hack.
As Senior Technical Director at Counter Hack and SANS Faculty Fellow, Joshua has advanced cybersecurity through ethical penetration testing, uncovering critical vulnerabilities across Fortune 500 companies and national infrastructure providers.
Read more about Joshua Wright