Registry artifact timestamps are extremely important to an incident response investigation. Threat actors may hide persistence mechanisms within the registry or modify registry values to disable Antivirus and other security tools. Knowing the time registry values are set/modified is very important to the overall investigation, especially when faced with answering questions pertaining to…
- Why did <security_tool> not detect the threat?
- What files did the threat actors recently view?
- What folders did the threat actors open?
- When was the persistence mechanism installed in the registry?
- And many other questions that are important to an investigation…
The idea of timestomping / time manipulation of a registry key’s ‘Last Write’ is a topic that has not been comprehensively covered in DFIR write-ups with most timestomping write-ups focused on timestomping of files via manipulation of the $STANDARD_INFORMATION time.
There exists a native Windows API “NtSetInformationKey” that allows a malicious threat actor to timestomp the ‘Last Write’ time of a registry key. I came across this when looking through the Undocumented NTInternals website for registry keys. As I looked further into this research, I came across a PoC tool built by Joakim Schicht (https://github.com/jschicht). This tool is called SetRegTime.exe and runs by using this native API “NtSetInformationKey” to change the Last Write Time for keys in the registry. The link to the tool is here.
Perhaps the most interesting component to all of this is the lack of strong detection for this technique (which I cover later in this blog post). The reason being – typically, the logic for detecting timestomping for files relies on a comparison between the $STANDARD_INFORMATION vs $FILENAME time given that $STANDARD_INFORMATION time can be trivially manipulated via Windows APIs. However, there isn’t a “comparison” time for a registry ‘Last Write’ time which makes the detection more difficult. To make it more difficult, the time change is written to the disk immediately via calling “NtFlushKey” which makes the “detection” of this via memory forensics almost impossible unless you have a memory image of the disk the second these APIs were triggered.
This blog post will cover the following topics:
- How to manipulate a registry key timestamp
- Attack demonstration
- Detection mechanisms and further thoughts
How to manipulate a registry key timestamp
By calling a set of native API keys an attacker can modify the Last Write time of a registry key in an extremely trivial manner. The most important API is the “NtSetInformationKey” API which takes in a few parameters – the most important being the KEY_SET_INFORMATION_CLASS parameter which is used to modify the ‘Last Write’ time by passing in “KEY_WRITE_TIME_INFORMATION”.
The breakdown for the API “NtSetInformationKey” can be seen in the screenshot below taken from Undocumented NtInternals website.
In the PoC built by Joakim Schicht, the tool uses the following API keys in conjunction with the offending “NtSetInformationKey”. I have broken down the use cases below: - NtCreateKey >> Creates or opens an existing registry key
- NtOpenKey >> Opens an existing registry key
- NtSetInformationKey >> Used to modify the time
- NtEnumerateKey >> Returns information about a registry key
- NtQueryKey >> Returns information from a registry key
- NtFlushKey >> Write the new timestamp immediately to disk
Attack Demonstration
Many thanks to Joakim Schicht for making my life so easy for building the PoC so I didn’t need to so I can focus on detection.
From the perspective of an attacker, I would weaponise the knowledge of these APIs so that this functionality is pre-built into the malware that they are distributing. I highly doubt that an attacker who is this “intent” on anti-forensics will proceed to run an executable on a system labelled “timestomp_reg” … but who knows, some threat groups get notoriously lazy. I have seen APT groups decide to use anti-forensic techniques to clean up certain things but then leave other traces everywhere else (that they could’ve cleaned up).
Step 1: Alter a registry key setting
For this instance I chose to mess with the Run key in HKLM Software – a common key that less sophisticated malware/threat actors tend to use.
Prior to manipulation, the ‘Last Write’ time for the Run key is shown below to be set sometime in 2021.
To manipulate the ‘Last Write’ time I ran Joakim’s tool to change the time for the run key to sometime in 2020.
Step 2: Wait a few seconds for changes to take place
I notice that despite running the NtFlushKey, the change is not immediate and takes a few seconds to show up. As you can see from the screenshot below the time has now been modified to reflect the malicious time.
Step 3: What about registry keys with sub keys?
For registry keys with sub-keys i.e. HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall, the “Uninstall” key’s ‘Last Write’ time reflects the time of the latest subkey that was added. To illustrate this point, the screenshot below shows the original Uninstall key write time.
When scrolling through the subkeys, you will see a corresponding subkey with the same write time:
When I tested Joakim’s tool on this, modifying the ‘Last Write’ time of a subkey does not modify the outermost registry key (in this instance, the Uninstall key). Therefore, if a threat actor is using this method to modify the registry times, they would need to recursively check all the relevant keys also have had their times modified.
The screenshot below shows the result of my recursive modification of the Uninstall key and the underlying relevant subkey to the year 2000. How for keys with various subkeys, the main ‘Last Write’ time for the top key should be the same time as the latest subkey that was added. In this instance, the year 2000 makes no sense considering there are entries within this subkey that have dates past the year 2000. As a blue teamer, I would look for discrepancies within these values.
Detection Methodology
Immediately, I think the first thought in most peoples’ mind will be “event logs if auditing is enabled”. I am going to show you why this isn’t the case. There are quite a few frustrating considerations with the detection of this technique, thus I have broken this section into four parts to consider:
- Why event logs detections fail on this technique
- Detecting discrepancies in registry keys
- Why memory forensics may not be feasible in most circumstances
- Why EDR is your best bet for detection (if your EDR tool monitors for this)
- Final considerations
TL;DR Detection
Detect on operations used to set registry information specifically using the parameter “KeySetInformationClass” passing in the value of “KeyWriteTimeInformation” as this is the exact parameter used to modify ‘Last Write’ time of a registry. There is no legitimate use case for this that I can think of. Further, detection on API calls to “NtSetInformationKey” along with the following other API keys:
- NtCreateKey
- NtOpenKey
- NtEnumerateKey
- NtQueryKey
- NtFlushKey
Finally look for discrepancies in timestamps for any registry keys with nested subkeys and ensure that the outer most key reflects the latest write time on the most recent subkey. This is not a perfect detection for keys where no subkeys exist.
Part 1: Why Event Log Detections Fail on this Technique
Typically, if auditing is enabled for registry changes, several event IDs should be triggered within the Security.evtx file. The IDs that are of interest include 4656, 4657, 4660 and 4663. The most interesting event ID with the highest relevance to a “modification” of a timestamp is event ID 4657. However, when you delve further into what this Event ID alerts on... you can see it will only trigger when a value is modified. The ‘Last Write’ time is not a registry value, therefore this Event ID will never trigger. See below for a screenshot from the documentation from Microsoft.
Given this sad realisation, you would hope that the Event IDs 4663 and 4656 might trigger as they relate to “accessing” of an object and requesting of a “handle” to an object. However, due to the nature of these native API calls, no events are written to the event log. This means event log detection for this technique does not work.
Below is a screenshot showing how I enabled the auditing on the registry.
Part 2: Detecting discrepancies in registry keys
For nested registry keys i.e. in HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall, you can hunt for discrepancies, such as subkeys with ‘Last Write’ times which are later than the “Uninstall” key.
For the example captured below, you can see that in between the two timestomped keys, the other subkeys have values that are later than the year 2000. In this instance, this should never be the case for nested registry keys as the ‘Uninstall’ key should store the most recent write time for the corresponding subkeys.
This detection won’t work for a registry key where there are no nested subkeys i.e. for the RUN/RUNONCE keys. Therefore, this is not a perfect detection mechanism for this technique.
Part 3: Why memory forensics may not be feasible in most circumstances
Due to the largely instantaneous nature of the changes due to leveraging the NtFlushKey, the changes are written to disk almost immediately. For a detection to occur, I can only think of a few scenarios where the likelihood of these occurring is low – especially during the case of an incident response. You would get a more effective outcome by focusing on contextual evidence versus zoning in on the detection of these APIs. It is not that detecting this technique via memory forensics is impossible, but just less feasible as you would essentially need to be able to capture those API calls in a memory dump when they occur. In most IR instances I’ve experienced, memory forensics provides the best detection for memory-based persistence mechanisms. Given this is not a persistence mechanism and doesn’t “persist” in memory, the evidence may not exist.
Part 4: Why EDR may be the best option
I used Procmon to monitor what was going on when I ran Joakim’s tool and there was one line that I think would make a good detection. Specifically, it is the detection of the KeySetInformationClass parameter being passed the KeyWriteTimeInformation which was used to overwrite the registry time. From earlier in the blog, you would’ve seen me point out that this parameter and value is what is used to over-write a registry time. There is no legitimate use case for this.
I’m not sure if EDR tools detect something like this, but I would think that this would be a high-fidelity detection to alert on.
To add to this, I would also add the detection of the following APIs being used in in conjunction:
- NtCreateKey
- NtOpenKey
- NtEnumerateKey
- NtSetInformationKey
- NtQueryKey
- NtFlushKey
Part 5: Final Considerations
As mentioned in my previous post about Windows Event Log Evasion via Native APIs, detections in incident response need to have correlating pieces of evidence. If a threat actor modifies the registry key there should be correlating things happening around that time – like the execution of a malware, modification of files etc. Generally, when I am working cases with interesting malware samples, I will get these samples reversed by the reverse engineering team. The results from the RE usually indicate if “interesting” functions exist – such as functions where timestomping of registry keys may occur.
Happy hunting!
REFERENCES
https://github.com/jschicht/SetRegTime
https://code.google.com/archive/p/mft2csv/wikis/SetRegTime.wiki
http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FKey%2FNtSetInformationKey.html
https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4657
https://www.inversecos.com/2022/03/windows-event-log-evasion-via-native.html
Comments
Post a Comment