Who Left the Backdoor Open? Using Startupinfo for the Win

In the endless quest to research additional Windows system forensic artifacts to use during an Incident Response investigation, I stumbled across something I thought was cool. This definitely wasn’t a new artifact, it was just a specific native Windows XML file that I wasn’t aware of. I noticed this file was not commonly used from a forensic capability, so it must be something that the offensive side of the house was potentially unaware of too… maybe?

In this blog post, I will briefly identify what the startupinfo.xml file is and the forensic capabilities it provides. There is a great blog post that already goes into significant detail by Hadar Yudovich, which you can read here, but I wanted to expand on this a bit more. The primary use case I’ll be focusing on has to do with command and control (C2) process startup and the detection capabilities it brings to light with malicious user logon persistence.

Most importantly to note, there are definitely other forensic artifacts and logs that can be used to identify this persistence activity, but hopefully you will share in my excitement about the value this individual file brings to an incident investigation.

Testing Environment

The testing environment I set up was nothing high-speed, but I wanted to provide an overview of what it entailed, in case you wanted to replicate the testing I performed.

My internal testing environment simply consisted of the following:

  • Kali VM used as my C2 server
  • Powershell Empire used as my C2 framework
    • Persistent modules used
      • powershell/persistence/elevated/registry*
      • powershell/persistence/elevated/wmi*
  • Windows 10 VM used as my victim machine
    • Forensic file used for analysis
      • C:\Windows\System32\WDI\LogFiles\StartUpInfo\<User SID>_startupinfo<#>.xml

Brief Startupinfo.xml Overview

Based on Hadar Yudovich’s blog post, here are some of the key aspects of the XML file that I took note of before testing.

  • The XML file is located at C:\Windows\System32\WDI\LogFiles\StartUpInfo\
  • The naming convention of the file contains the user SID and incremental count of the file <User SID>_StartUpInfo<#1-5>.xml. There are a maximum of five files created for each user that identify the date/timestamp of the user logon activity
  • The XML file contains process execution for the first 90 seconds of user logon activity
  • The process information includes:
    • Name, PID, start time, command line, disk usage, CPU usage
    • Parent PID, parent process start time, parent process name

Command and Control Setup

I will not go into detail surrounding the C2 framework components, since that is out of scope for this blog post, but to get the C2 infrastructure set up and beacon callback established, I performed the following steps:

  1. I installed the current version of PowerShell Empire on my Kali VM
    • I set up my HTTP Listener to handle the victim agent C2 callback
    • I set up the victim agent PowerShell launcher
  2. I dropped the PowerShell base64 launcher on the victim Win10 VM
  3. I confirmed the agent callback session was successfully established
    • At this point there was NO persistence in place to survive Win10 VM host reboot
  4. The first persistence test was a fileless technique using the registry to house the PowerShell Empire agent payload
    • powershell/persistence/elevated/registry*
      • This places the beacon payload call mechanism in registry key location HKLM:Software\Microsoft\Windows\CurrentVersion\Run\Updater
      • This stores the beacon base64 payload in registry key location HKLM:Software\Microsoft\Windows\CurrentVersion\Debug
    • I executed the persistent module on the C2 server side
    • I confirmed the C2 persistence was successfully pushed to the victim Win10 VM
      • I rebooted the victim Win10 VM and logged back in, which spawned a new PowerShell Empire agent session. This confirmed the registry autorun persistence was successful
  5. The second persistent test was a WMI-based technique that used a permanent WMI event subscription
    • powershell/persistence/elevated/wmi*

Due to the persistence event trigger timing (between two and five minutes after user logon), this test was specifically used to validate that this persistence method would bypass the startupinfo.xml detection capabilities

Startupinfo.xml for the Win

The focus here was to identify that this single XML file could detect and provide multiple indicators of compromise (IoC) without having to comb through various other system log resources or system artifacts. The overall analyst goal is to lean towards increased rapid Incident Response triage capabilities.

This particular part of the startupinfo.xml testing successfully detected persistence that was using an autorun registry key to execute the PowerShell Empire payload. Run registry keys cause programs to run each time that a user logs on. The data value for a key is a command line no longer than 260 characters.

To learn more about autorun persistence, you can read Hexacorn’s amazing blog post.

Registry Run Key Persistence Testing

The PowerShell Empire powershell/persistence/elevated/registry* persistence module executes once the successful user logon takes place. In this test, I used the default settings of the module. I used Process Hacker to actively monitor the successful execution of the Run registry key persistence. Once executed, I confirmed the new persistent PowerShell Empire agent session was established on the C2 server.

Figure 1 – Registry Run Key Persistence Executed

I also manually verified the registry Run key persistence using Registry Editor. First, I navigated to the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run location to uncover what the PowerShell command looks like. The PowerShell script executes a command in PowerShell that is stored in a variable named “x“.

Run Key PowerShell Command

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "$x=$((gp HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion Debug).Debug);powershell -Win Hidden -enc $x"

Figure 2 – Registry Run Key Persistence

The value of “x” is stored in a different registry key located in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Debug. This is where the actual base64 payload is located.

Figure 3 – Registry Run Key Persistence Payload

I confirmed the presence of the startupinfo.xml files within the C:\Windows\System32\WDI\LogFiles\StartupInfo location, but I also wanted to confirm the user account the startupinfo.xml files pertained to, which also allowed me to confirm the specific user account the process execution ran under. I was logged in as the REM user and verified these startupinfo.xml files were tied to this user account by the security identifier (SID) S-1-5-21-1866265027-1870850910-1579135973-1000, which is identified in the first part of the XML files.

Figure 4 – User Account SID Identification

I confirmed that the persistent registry Run key execution was successfully captured within the startupinfo.xml file.

I used the jupyter notebook python code that Hadar Yudovich’s blog post provided in order to parse the XML data file.

Figure 5 – Persistent Registry Run Key Execution Captured

An alternative to using the Jupyter notebook python code is to use the xml2csv tool to create an exported CSV file, but I noticed the individual process IDs column was missing from the output.

Figure 6 – Xml2csv output

For me, the cool part here is the command line output that was successfully captured from the PowerShell registry Run key and payload executions. I was also interested in the \??\C:\WINDOWS\system32\conhost.exe 0xffffffff -ForceV1 execution and came across this stackexchange post that explained the execution to be affiliated with, “If there is no session attached to the physical console, (for example, if the physical console session is in the process of being attached or detached), this function returns 0xFFFFFFFF.”

As you can see from the output, we have captured the following critical IoCs from a single file:

  • User ID the processes were executed from
  • Parent process IDs
  • Parent process names
  • Child process IDs
  • Start time of process execution
  • Process disk usage
  • Process CPU usage
  • Command line output

As a quick example of how I pivoted off of the acquired IoCs, I performed a simple netstat -naob and found the process ID 1348. Figures #1 and Figure #5 identified this process ID to be affiliated with the PowerShell process. Now, for whatever reason, if you were unable to decode the encoded PowerShell payload, the netstat command output would allow you to see the C2 server IP address the victim Win10 VM is beaconing out to.

Figure 7 – C2 Server IP Address

Logging Limitations to Consider

In order to acquire this level of output within Windows native event logs, an organization would

need to have Audit Process Tracking/Creation auditing and Powershell Script Block Logging enabled to capture this level of detailed process activity. In my experience, most organizations cannot enable Audit Process Tracking/Creation due to the level of noise it creates and the volume of logs it forwards to a back-end SIEM, if one is in place. Remember, in this testing this malicious activity was occurring on a user machine, not a production server, so there is even less of a chance that this level of logging would be enabled. Sysmon detection capabilities are also there, but I have found few organizations that have this successfully deployed across their entire environment.

Malicious Registry Key Eradication

Since I already knew the exact locations of the registry persistence, I used Registry Editor to navigate to the key locations, right clicked on the keys, deleted both of them, and rebooted the victim Win10 VM. I verified in the C2 server that the persistent agent session stopped beaconing.

Startupinfo.xml Unfortunately Looses

With any forensic artifact, there will be capability limitations, and unfortunately, I was able to circumvent the detection capabilities using a specific PowerShell Empire persistence module that executes by default outside of the startupinfo.xml 90 second monitoring window. The bright side is that, as defenders, we have additional monitoring logs we can leverage to detect this specific WMI activity, for example:

  • Microsoft-Windows-WMI-Activity/Operational
  • Sysmon

Some additional monitoring and threat hunting resources you can use:

  • https://www.darkoperator.com/blog/2017/10/14/basics-of-tracking-wmi-activity
  • https://threathunterplaybook.com/notebooks/windows/08_lateral_movement/WIN-200902020333.html
  • https://github.com/trustedsec/SysmonCommunityGuide/blob/master/WMI-events.md

WMI Event Subscription Persistence Testing

The PowerShell Empire powershell/persistence/elevated/wmi* persistence module triggers between two and five minutes after successful user logon, which falls outside of the 90 second monitoring window of the startupinfo.xml file. In this test, I used the default settings of the module. I used Process Hacker to actively monitor the successful execution of the WMI subscription persistence. Once executed, I confirmed the new PowerShell Empire agent session was established on the C2 server.

Figure 8 – WMI Persistence Executed

I also manually verified within PowerShell the presence of the persistent WMI instance using the following command to uncover the PowerShell Empire base64 payload:

powershell Get-WMIObject -Namespace root\Subscription -Class __EventConsumer
Figure 9 – WMI Persistence Base64 Payload Identification

I confirmed the startupinfo.xml file was unsuccessful in capturing this WMI persistence execution.

Figure 10 – No Signs of WMI Execution in startupinfo.xml File

Malicious WMI Persistence Eradication

I wanted to learn more about how this WMI persistence mechanism was set up on the victim machine, so I took one final step and manually removed the WMI Event Filter, Event Consumer, and binding that were created.

Remove the WMI Binding

Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription | Where-Object { $_.filter -match 'Updater'} | Remove-WmiObject;

Remove the WMI Event Consumer

Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -Filter "name='Updater'" | Remove-WmiObject

Remove the WMI Event Filter

Get-WMIObject -Namespace root\Subscription -Class __EventFilter -Filter "Name='Updater'" | Remove-WmiObject -Verbose

I rebooted the victim Win10 VM and verified in the C2 server that the persistent agent session stopped beaconing.

To learn a little more about permanent WMI Event Subscriptions, you can take a look at:

  • https://learn-powershell.net/2013/08/14/powershell-and-events-permanent-wmi-event-subscriptions/

Closing

I may not have covered anything groundbreaking here, but hopefully this information provided some additional detection capabilities and, more importantly, some ideas on how to continue with further detection testing. I also hope that identifying the usefulness of this artifact will provide Incident Responders something to add to the forensic tool bag to enhance rapid investigation capabilities.

Expand your overall understanding of the threat landscape by looking at things from a triad viewpoint: offensive, defensive, and forensic. Understand offensive tooling, tune defensive monitoring, and continue to uncover new forensic sources to assist in detection and uncover the residue left behind from offensive weapons. Prepare yourself for the next incident by doing the necessary work!

@H3dTr1p