Blog Persistence and Profit within the Registry
Post
Cancel

Persistence and Profit within the Registry

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:

NameValue
REG_NONENone
REG_SZFixed length unicode string
REG_EXPAND_SZVariable-length unicode string that can have embedded variables
REG_BINARYBinary data
REG_DWORD32-bit number (can be booleans)
REG_DWORD_BIG_ENDIAN32-bit number (high byte first)
REG_LINKUnicode symbolic link
REG_MULTI_SZArray of unicode null-terminated strings
REG_RESOURCE_LISTHardware resource descriptions
REG_FULL_RESOURCE_DESCRIPTORHardware resource descriptions
REG_RESOURCE_REQUIREMENTS_LISTResource requirements
REG_QWORDA 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 exists RunOnce 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


Demo of screensaver method


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. This technique is used by Canary Tokens to detect if a specific command has been executed.


Demo of silentexit method


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) while LocalServer32 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: MITRE mitigation description for COM Hijacking

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}

reg query of recycle bin CLSID

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


gif of the above


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):

gif of the above


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.

Contents