The Registry
The registry on Microsoft machines acts as a database to store low-level information for the system and its users. Introduced in Windows 3.1, the registry allows for persistence and evasion of security controls.
Messing with the registry is an easy way to brick your machine. Make sure to use a throwaway VM if doing further testing.
Within the registry, there are five main root keys:
- HKEY_CLASSES_ROOT (A merged view of the HKEY_LOCAL_MACHINE\Software\Classes and HKEY_Users<SID of user>\Software\Classes keys)
- HKEY_CURRENT_USER (Subkey of the logged-in user’s SID in HKEY_USERS)
- HKEY_LOCAL_MACHINE
- HKEY_USERS
- HKEY_CURRENT_CONFIG (Link to the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Hardware Profiles\Current key)
Additionally, there are other root keys. Most of these roots are invisible within the registry editor but accessible through Windows API functions:
- HKEY_CURRENT_USER_LOCAL_SETTINGS (Link to HKCU\Software\Classes\Local Settings)
- HKEY_PERFORMANCE_DATA
- HKEY_PERFORMANCE_NLSTEXT
- HKEY_PERFORMANCE_TEXT
Within the registry, there are keys, subkeys (think of directories), and values (think of files). Root keys start with H
such as HKEY_LOCAL_MACHINE
that represent a handle to each key. The registry isn’t stored as one big file on disk, but as multiple files called hives containing a registry tree.
Registry keys and values are case-insensitive.
There are twelve different value types that can be stored in the registry:
Name | Value |
---|---|
REG_NONE | None |
REG_SZ | Fixed length unicode string |
REG_EXPAND_SZ | Variable-length unicode string that can have embedded variables |
REG_BINARY | Binary data |
REG_DWORD | 32-bit number (can be booleans) |
REG_DWORD_BIG_ENDIAN | 32-bit number (high byte first) |
REG_LINK | Unicode symbolic link |
REG_MULTI_SZ | Array of unicode null-terminated strings |
REG_RESOURCE_LIST | Hardware resource descriptions |
REG_FULL_RESOURCE_DESCRIPTOR | Hardware resource descriptions |
REG_RESOURCE_REQUIREMENTS_LIST | Resource requirements |
REG_QWORD | A 64 bit number |
Have you ever wondered how Windows remembers past RDP connections when opening mstsc.exe? Well you probably haven’t, but one example of how the registry is used by storing past connection details at:
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Terminal Server Client\Servers\
Permissions
Each registry hive has different permissions that will be important when attempting to persist through it:
- HKEY_CLASSES_ROOT (HKCR)
- Standard Users: Read Only
- HKEY_CURRENT_USER (HKCU)
- Standard Users: Full Control
- HKEY_LOCAL_MACHINE (HKLM)
- Standard Users: Read Only
- HKEY_USERS (HKU)
- Standard Users: Read Only
- HKEY_CURRENT_CONFIG (HKCC)
- Standard Users: Read Only
We’ll pay special attention to the HKEY_CURRENT_USER hive since a standard user can write to it.
Persistence
Run/RunOnce - The most common way
The most common and basic way to persist in the registry is through the Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
registry hive. Any entries in this hive will be executed when the user logs in. We can add an entry with the following command:
1
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v <key name> /t REG_SZ /d <full .exe path> /f
OR
1
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run" /v <key name> /t REG_SZ /d <full .exe path> /f
Now, each time the user (whose context we added the entry under) logs in, the specified executable will be executed.
Along with the
Run
, there are also existsRunOnce
that will execute only once:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce
LogonScripts - A little less common
Similar to the Run
and RunOnce
key, we can also specify a logon script through the registry. This script will run each time the user logins:
1
reg add "HKEY_CURRENT_USER\Environment" /v UserInitMprLogonScript /d "<.bat file path>" /t REG_SZ /f
Weaponizing the screensaver
The next method is to set the screensaver process to run our payload. This method is more likely to be detected due to it changing the default behavior if a screensaver is already configured per GPO. With this attack, we can either point to a .exe or a .scr file.
The only difference between .exe’s and .scr’s are the file extension.
1
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v "SCRNSAVE.EXE" /t REG_SZ /d "<target EXE/SCR>" /f
Note: In the example below, I have also set a timeout for the screensaver to activate after seconds for the sake of this demo.
1
reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v "ScreenSaveTimeOut" /t REG_SZ /d "3" /f
Because we are modifying the HKCU hive, we can perform this method as a standard user.
SilentProcessExit
SilentProcessExit was introduced in Windows for debugging purposes. It allows a command to be executed when a process exits.
1
2
3
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\quickassist.exe" /v GlobalFlag /t REG_DWORD /d 512
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\quickassist.exe" /v ReportingMode /t REG_DWORD /d 1
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\quickassist.exe" /v MonitorProcess /d "calc.exe"
In the above example, calc.exe will execute whenever a quickassist.exe process ends. The calc.exe payload can be swapped out ex: cmd.exe
COM
COM serves as a way for different applications and services to interact, no matter their language they were created in. It’s basically a language agnostic DLL that’s been around since 1992.
A simplified example of the COM process:
<TODO>
GUID’s containing the subkey of
InprocServer32
and load a .dll (in process COM server) whileLocalServer32
points to an .exe (out of process COM server).
From the above execution flow, we should be able to hijack the COM object when SCM queries the hives and swap out our .dll/.exe.
Note: COM objects are usually stored in the registry but ‘Registry Free COM’ is also a thing. This is where the ‘activation context class’ has a manifest file that points to the COM object.
COM Hijacking
MITRE’s mitigation for COM Hijacking lets us know that this can be an effective way to attack:
Where do we place our shellcode within the DLL? If hijacking a .dll (subkey of InprocServer32), we can’t place our payload in the .dll’s main function due to loader locks. Instead, we can use the DllGetClassObject
function.
<TODO>
Who needs DLL’s when you have scriplets
What if we don’t want to drop a DLL or EXE to disk? COM allows us to point to a scriplet file.
We do not need to use a .sct extension here. Any file extension with the proper XML will work.
<TODO>
COM Extension Handlers
This technique is simpler than COM hijacking. Here, we are pointing a file to be opened through the shell
subkey. First, lets take a look at the registry for the recycle bin CLSID. It’s located at:
1
reg query Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{645FF040-5081-101B-9F08-00AA002F954E}
We see that it’s CLSID has a key of “shell”. Within this, we can add the subkey “open\command” and point it to our desired executable. The verb “open” can be easily detected though. Research done by Hexacorn, discovered that we can add a new verb for the “shell” key to execute the value stored in \command entry. Now, anytime we go to open the recycle bin, our executable will be executed.
Ex:
1
2
3
4
5
# Assigning the verb 'foo' to the shell key by overwriting the default value
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\shell\" /ve /t REG_SZ /d "foo" /f
# Assigning the entry 'foo' and pointing it calc.exe
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\shell\foo\command" /ve /t REG_SZ /d "c:\Windows\System32\calc.exe" /f
Junctions
Junction files are one of four methods of making links within NTFS. They are very similar to symbolic links (symlink). Two key difference’s are:
- Junctions must point to a local directory while symbolic links can point to a remote directory/file.
- Junctions can be created by any user with privileges to target directory while symbolic links require admin privs.
The easiest way to create a junction file is by renaming a folder to blah.{CLSID}
where the CLSID is previously defined in the registry.
Ex - A junction folder to “My Computer” (CLSID: 20D04FE0-3AEA-1069-A2D8-08002B30309D):
The CLSID will be hidden in the desktop and explorer pane, but will show from command line.
Using the above functionality, we are able to achieve persistence through the following steps:
- Create a new registry key within HKCU of an unused CLSID
- Add the appropriate subkeys to point to our desired executable/dll (see COM Extension Handler above))
- Create a junction folder referencing the CLSID we created in step 1
- (Optional) Add the junction folder to the startup folder
%appdata%\Microsoft\Windows\Start Menu\Programs\Startup
For more persistence techniques, check out this great Hexacorn blogpost.
Post-Exploitation
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths
- Last 25 paths typed in the explorer address bar
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU
- Commands executed from the run dialog
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\*
- Recent files opened by file type
- Limited documentation was found on this hive
- Possible to recover some file data
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
- Programs that run at startup
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*
- Programs that have been installed
- Shows the date/time, command string, and more
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WorkplaceJoin\TenantInfo
- Tenant information for Azure AD joined devices
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\AuthCookies\Live\Default
- Live.com cookies
Computer\HKEY_CURRENT_USER\Volatile Environment
- Environment variables
Computer\HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\Shell
- ShellBags
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB
- Connected USB devices
Computer\HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices
- Mounted devices
- Useful to see if .iso was mounted by the user
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList
- Network information/history
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office<version>\Word\Security\Trusted Documents\TrustRecords
- List of documents that the user has trusted (enabled macros/editing)
- Replace “Word” with other Office Products
Computer\HKEY_CURRENT_USER\SOFTWARE\7-Zip\Compression
- 7-Zip compression history
Computer\HKEY_CURRENT_USER\SOFTWARE\7-Zip\Extraction Computer\HKEY_CURRENT_USER\SOFTWARE\7-Zip\FM
- 7-Zip extraction history
Long are the days when we could simply run mimikatz and spit out plaintext credentials.
Ever since Windows 8, Wdigest authentication has been disabled by default, preventing plaintext credentials from existing in memory. Using the following registry entry (ran in an elevated context), we can force WDigest authentication:
1
reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 1
Now, all we have to do is wait for authentication to occur then dump plaintext credentials from memory.