Saturday, December 31, 2022

Persistence and LOLBins

Grzegorz/@0gtweet tweeted something recently that I thought was fascinating, suggesting that a Registry modification might be considered an LOLBin. What he shared was pretty interesting, so I tried it out.

First, the Registry modification:

reg add "HKLM\System\CurrentControlSet\Control\Terminal Server\Utilities\query" /v LOLBin /t REG_MULTI_SZ /d 0\01\0LOLBin\0calc.exe

Then the command to launch calc.exe:

query LOLBin

Now, I've tried this on a Windows 10 system and it works great, even though Terminal Services isn't actually running on this system. Running just the "query" command on both Windows 10 and Windows 11 systems (neither with Terminal Services running) results in the same output on both:

C:\Users\harlan>query
Invalid parameter(s)
QUERY { PROCESS | SESSION | TERMSERVER | USER }

Running the "query" command with different parameters (i.e., "process", "user", etc.) proxies that command to the appropriate entry based on the value in the Registry, as illustrated in figure 1.

Fig 1: query key values






As such, running "query user" runs quser.exe, and you see the same output as if you simply ran "quser". 

Note that the Utilities key has two other subkeys, in addition to "query"; "change" and "reset", as illustrated in fig. 2.

Fig. 2: Utilities subkeys









So, I thought, what if I change the key path from "query", and make the same modification (via the 'reg add' command above) to the "change" subkey...would that have the same effect? Well, I tried it with an elevated command prompt, for both the "change" and "reset" subkeys, and got "Access is denied." both times. Okay, so we can only use this...at an Admin level, anyway...with the "query" subkey.

So what?
Part of what makes this particular persistence so insidious (IMHO) is how it can be launched. When we use the Run keys (or a Scheduled Task, or a Windows service) for persistence, an analyst may not have any trouble seeing the launch mechanism for the program/malware. In fact, even outside of Registry analysis, some SOC consoles will allow the analyst to see notable events, and even provide enough process lineage to allow the analyst to deduce that a notable event occurred.

To Grzegorz's point, this is an interesting LOLBin, because query.exe exists on the system by default. IMHO, this is important because when I started learning computers over 40 yrs ago (yes, circa 1982), all we had was the command line; as such, understanding which commands were available on the system, as well as things like STDOUT, STDERR, file redirection, etc., were all just part of what we learned. Now, 40 yrs later, we have entire generations of analysts (SOC, DFIR, etc.) who "grew up" without ever touching a command line. So, when I saw Grzegorz's tweet, the first thing I did was go the command prompt and type "query", and saw the response listed above. Easy peasy...but how many analysts do that? What's going to happen if a SOC analyst sees telemetry for "query user"? Or, what happens if a DFIR analyst sees a Prefetch file for query.exe? What assumptions will they make, and how will those assumptions drive the rest of their analysis and response?

What is a way to use this? Well, let's say you gain access to a system...and this is just hypothetical...and run a script that enables RDP (if it's not already running), enables StickyKeys, writes a Trojan to an alternate data stream (thanks to Dr. Hadi for some awesome research!!) and then creates a value beneath the "query" key for the Trojan. That way, if your activity on other systems gets discovered, you have a way back into the infrastructure that doesn't require authentication. Connect to the system via the Remote Desktop Client, access StickyKeys so that you get a System-level command prompt, and you type "query LOLBin". Boom, you're back in!

As you might expect, I did write a RegRipper plugin for this persistence mechanism, the output of which makes it pretty straightforward to see any changes that may have been made. For example, "normal" look like the following:

utilities v.20221231
(System) Get TS Utilities subkey values
Category: persistence - T1546

ControlSet001\Control\Terminal Server\Utilities\change
LastWrite time: 2018-04-12 09:20:04Z
logon           0 1 LOGON chglogon.exe
port            0 1 PORT chgport.exe
user            0 1 USER chgusr.exe
winsta          1 WINSTA chglogon.exe

ControlSet001\Control\Terminal Server\Utilities\query
LastWrite time: 2018-04-12 09:20:04Z
appserver       0 2 TERMSERVER qappsrv.exe
process         0 1 PROCESS qprocess.exe
session         0 1 SESSION qwinsta.exe
user            0 1 USER quser.exe
winsta          1 WINSTA qwinsta.exe

ControlSet001\Control\Terminal Server\Utilities\reset
LastWrite time: 2018-04-12 09:20:04Z
session         0 1 SESSION rwinsta.exe
winsta          1 WINSTA rwinsta.exe

Analysis Tip: The "query" subkey beneath "\Terminal Server\Utilities" can be used for persistence. Look for unusual value names.

Ref: https://twitter.com/0gtweet/status/1607690354068754433

Keeping Grounded

As 2022 comes to a close, I reflect back over the past year, and the previous years that have gone before. I know we find it fascinating to hear "experts" make predictions for the future, but I tend to believe that there's more value in reflecting on and learning from the past.

Years ago, I remember hearing about something in legal circles referred to as "the CSI effect". In short, the unrealistic portrayal of "forensics" on TV shows had influenced public opinion. People would watch an hour-long crime drama TV show and what they saw set the expectation in their minds of "forensics" should be, and this unrealistic expectation made it difficult for prosecutors to convince some juries of their evidence.

Over the holiday season, a "bomb cyclone" across the US combined with the numbers of folks wanting to travel to cause travel delays with the airlines, as one might expect. Planes needed to be deiced, but at some locations, travel was simply impossible. However, one airline in particular experienced heavier than usual delays and cancellations, to the point where the Transportation Secretary took notice. For several days, the evening national news covered this story, focusing in on the failures of the airline, and how stranded passengers were standing in long lines just to seek assistance from the airline's customer service. As each day went by and media reports highlighted how the cascading failures were snowballing and impacting travelers, all of this served to create an sense of negativity toward the airline management. Everyone I spoke with over the holidays had the same negative perspective of the airline's management.

On the morning of 28 Dec 2022, I saw the following post on LinkedIn:







Erin's message served as a stark reminder that there's often more to the story, that regardless of what we see being reported in the media, there are often stories that are not covered and reported, and that do not make it into the public eye. News outlets have a limited amount of time to cover a hand-picked menu of events of the day, so we have to be conscious of "collection bias", and if what we're seeing and hearing is playing into a narrative that we assume is correct.

The point here is to remain grounded, and as we roll over into the New Year, this is a good opportunity to make a resolution to remain grounded, and to seek out accountability partners and mentors to help us remain grounded. Don't be so focused on the negative aspects of an event that we loose sight of the positive things that happen, and that the folks who make those positive things happen need our support more than someone we believe is to blame needs our anger. 

Sunday, December 25, 2022

Why I love RegRipper

Yes, yes, I know...you're probably thinking, "you wrote it, dude", and while that's true, that's not the reason why I really love RegRipper. Yes, it's my "baby", but there's so much more to it than that. For me, it's about flexibility and utility. At the beginning of 2020, there was an issue with the core Perl module that RegRipper is built on...all of the time stamps were coming back as all zeros. So, I tracked down the individual line of code in the specific module, and changed it...then recompiled the EXEs and updated the Github repo. Boom. Done. I've written plugins during investigations, based on new things I found, and I've turned around working plugins in under an hour for folks who've reached out with a concise request and sample data. When I've seen something on social media, or something as a result of engaging in a CTF, I can tweak RegRipper; add a plugin, add capability, extend current functionality, etc. Updates are pretty easy. Yes, yes...I know what you're going to say..."...but you wrote it." Yes, I did...but more importantly, I'm passionate about it. I see far too few folks in the industry who know anything about the Registry, so when I see something on social media, I'll try to imagine how what's talked about could be used maliciously, and write a plugin.

And I'm not the only one writing plugins. Over the past few months, some folks have reached out with new plugins, updates, fixes, etc. I even had an exchange with someone the other day that resulted in them submitting a plugin to the repo. Even if you don't know Perl (a lot of folks just copy-paste), getting a new plugin is as easy as sending a clear, concise description of what you're looking for, and some sample data.

Not long ago, a friend asked me about JSON output for the plugins, so I've started a project to create JSON-output versions of the plugins where it makes sense to do so. The first was for the AppCompatCache...I still have a couple of updates to do on what information appears in the output, but the basic format is there. Here's an excerpt of what that output currently looks like:

{
  "pluginname": "appcompatcache_json"
  "description": "query\parse the appcompatcache\shimcache data source"
  "key": ".ControlSet001\Control\Session Manager."
  "value": "AppCompatCache"
  "LastWrite Time": "2019-02-15 14:01:26Z"
  "members": [
    {
      "value": "C:\Program Files\Puppet Labs\Puppet\bin\run_facter_interactive.bat"
      "data": "2016-04-25 20:19:03"
    },
    {
      "value": "C:\Windows\System32\FodHelper.exe"
      "data": "2018-04-11 23:34:32"
    },
    {
      "value": "C:\Windows\system32\regsvr32.exe"
      "data": "2018-04-11 23:34:34"
    },

Yeah, I have some ideas as to how to align this output with other tools, and once I settle on the basic format, I can continue creating plugins where it makes sense to do so.

Recently, we've been seeing instances of "Scheduled Task abuse", specifically of the RegIdleBackup task. To be clear, while some have been seeing it recently, it's not "new"...Fox IT, part of the NCC Group, reported on it last year. It's also been covered more recently here in reference to GraceWire/FlawedGrace. Of all the reporting that's out there on this issue, what hasn't been addressed is how the modification to the task is performed; is the task XML file being modified directly, or is the API being used, such that the change would also be reflected in the Task subkey entry in the Registry?

From the RegIdleBackup task XML file:

<Actions Context="LocalSystem">
    <ComHandler>
      <ClassId>{CA767AA8-9157-4604-B64B-40747123D5F2}</ClassId>
    </ComHandler>
  </Actions>

So, we see the COM handler listed in the XML file, and that's the same CLSID that's listed in the Task entry in the Software hive. About 2 years ago, I updated a plugin that parsed the Scheduled Tasks from the Software hive, so I went back to that plugin recently and added additional code to look up CLSIDs within the Software hive and report the DLL they point to; here's what the output looks like now (from a sample hive):

Path: \Microsoft\Windows\Registry\RegIdleBackup
URI : Microsoft\Windows\Registry\RegIdleBackup
Task Reg Time : 2020-09-22 14:34:08Z
Task Last Run : 2022-12-11 16:17:11Z
Task Completed: 2022-12-11 16:17:11Z
User   : LocalSystem
Action : {ca767aa8-9157-4604-b64b-40747123d5f2} (%SystemRoot%\System32\regidle.dll)

The code I added does the look up regardless of whether the CLSID is the only entry listed in the Action field, or if arguments are provided, as well. For example:

Path: \Microsoft\Windows\DeviceDirectoryClient\HandleWnsCommand
URI : \Microsoft\Windows\DeviceDirectoryClient\HandleWnsCommand
Task Reg Time : 2020-09-27 14:34:08Z
User   : System
Action : {ae31b729-d5fd-401e-af42-784074835afe} -WnsCommand (%systemroot%\system32\DeviceDirectoryClient.dll)

The plugin also reports if it's unable to locate the CLSID within the Software hive.

So, what this means is that the next time I see a system that's been subject to an attack that includes Scheduled Task abuse, I can check to see if the issue impacts the Software hive as well as the Task XML file, and get a better understanding of the attack, beyond what's available in open reporting.

Finally, I can quickly create plugins based on testing scenarios; for some things, like parsing unallocated space within hive files, this is great for doing tool comparison and validation. However, when it comes to other aspects of DFIR, like extracting and parsing specific data from the Registry, there really aren't many other tools to use for comparison.

Interestingly enough, if you're interested in running something on a live system, I ran across reg_hunter a bit ago; it seems to provide a good bit of the same functionality provided by RegRipper, including looking for null bytes, RLO control characters in key and value names, looking for executables in value data, etc.