Monday, June 30, 2025

Hunting Fileless Malware

I ran across Manuel Arrieta's Hunting Fileless Malware in the Windows Registry article recently, and found it to be an interesting read.

Let me start by saying that the term "fileless malware", for me, is like finger nails dragged down a chalkboard. Part of this is due to the DarkWatchman write-up, where the authors stated that some parts of the malware were "...written to the Registry to avoid writing to disk." That kind of distinction has always just rubbed me the wrong way. However, regardless of what we call it, I do "get" the concept behind the turn of phrase, and why folks tend to feel that this sort of thing is more difficult to detect than malware that actually writes a file to disk. I'm not sure why they feel that way...maybe it's because this code that downloads the malware and injects it directly into memory (in some cases) can reside anywhere on the system, and within any Registry value. However, the key is that this somehow needs to remain persistent, which limits the number of locations for the code that initiates the download, accesses the shellcode, or performs whichever initiating function. 

In his article, Manuel discusses the use of LOLBins to write information to the Registry, and how this can be used for detection. He references several LOLBins, and something that we have to keep in mind is that there's often more to these detections than just what we see on the surface. For example, is PowerShell used extensively within your infrastructure to create Registry values; if not then just the use of PowerShell in that manner would make for a good hunt, or even a good detection opportunity. The same is true for other LOLBins, including reg.exe, rundll32.exe, etc. If these are not something that you usually 'see' within your infrastructure, then those instances that you do see would need to be investigated.

Manuel's article discusses a number of interesting approaches for creating detections for "fileless" malware that's written to the Registry, and anyone involved with detection engineering should strongly consider giving it a good, solid read, and seeing how it can be applied to their environment. 

I'd like to take the opportunity to add to Manuel's work by presenting means for detecting this type of malware from a triage or "dead box" perspective. For example, Manuel mentions looking for LOLBins writing Registry values of suspicious lengths. I like this approach, because I'd taken a similar approach in 2015 when I originally wrote the RegRipper sizes.pl plugin. This plugin walks through a Registry hive and looks for all values over a specific $min_size, which is set to 5000 bytes (you can easily change this by opening the plugin in Notepad and changing the size value). Now, you're going to have legitimate Registry values that contain a lot of data, and that's to be expected; it's normal. However, a way to extend this is to look to publicly available threat intel based on actual incident data, see what different threat actors are placing in Registry values, and tailor your approach. 

Almost 2 yrs ago, I announced that I'd found a way to integrate Yara into RegRipper v4.0, so any Yara rule that looks for indications of "fileless" malware or shellcode within a file can be run against Registry values, through RegRipper. This can include rules that look for base64-encoded strings, or that begin with some variation of "powershell" (i.e., mixed-case, carets between the letters, etc.).

The findexes.pl plugin, which looks for strings beginning with "MZ" in Registry values, was originally written in 2009, based off an engagement that Don Weber worked while he was a member of the IBM ISS X-Force ERS team. Don found that, during the engagement, the threat actor had written a PE file to a Registry value, and then rather than reaching out to a network resource to download the malware, it was simply extracted from the Registry value. I found this very interesting at the time, because several years prior, while working on network exploitation research for the military, I'd theorized something similar happening, and actually created a working demo. Jump forward several years, and Don was showing me that this was actually being used in the wild. This findexes.pl plugin is one approach, and using Yara rules is another.

Examples
Here's an example of a persistence mechanism in the Registry pointing to a value that contains a base64-encoded string.

Here's an example from Splunk; scroll down to the section called "Fileless Execution Through Registry"; this one creates a Run key value that creates Javascript code to run calc.exe, so it's clearly not "fileless", per se, but it does serve as a harmless example you can use to test dead-box detections.

Here are some practical examples from Securonix; unfortunately, some of the examples are in screen captures, so you can't get specifics about them, such as the length of the value data, but you can use these example to round out your detections.

Thursday, June 26, 2025

Program Execution, follow-up pt II

On the heels of my previous post on this topic, it occurred to me that this tendency to incorrectly refer to ShimCache and AmCache artifacts as "evidence of execution" strongly indicates that we're also not validating program execution. That is to say, when we "see" a program execution event, or something that indicates that a program may have executed, are we validating that it was successful? Are we looking to determine if it completed its intended task, or are we simply assuming that it did?

For example, let's say we have an alert based on a threat actor running a net user command to add a new user account to an endpoint; when I see this command, I want to check the Security Event Log to see if there are any Security-Auditing/4720 records at about the same time, to indicate that the command succeeded. The command will very likely be accompanied by other Security Event Log records related to the account being enabled, the password being reset, etc; however, the ../4720 event record is what primarily interests me, because sometimes, you'll see the net user command that does not include the /add or /ad switch, but is still reported as a "new user being created", when, in fact, the account already exists and the password is being changed.

Regardless of what's reported, the point here is, are we validating what we're seeing? Another example is the use of msiexec.exe; when we see a command using this LOLBin run, do we also see accompanying MsiInstaller records in the Application Event Log? I've seen reports of msiexec.exe being run against HTTP resources, stating that something was installed; however, there are no corresponding MsiInstaller records in the Application Event Log.

Another use of the Application Event Log, when validating program execution, comes when you timeline the log records alongside EDR telemetry or process launch (Sysmon, Security-Auditing/4688) records. For example, if you see Application Pop-up or Windows Error Reporting messages for the program around the same time as the program execution, this would indicate that the program did not successfully launch. 

Another similarly valuable resource is AV logs. You may see the program execution attempt, followed by an AV message indicating that the process was detected and quarantined. Or, as has occurred several times, Window Defender may generate a detection record, and rather than a successful quarantine message, the detection is followed by a critical failure message, and the malware continues to execute.

The great folks over at Cyber Triage posted this guide on Malware WMI Event Consumers; pg 6 illustrates the "Classic Detection" techniques. Looking at these, EDR/Sysmon, and the WMI-Activity/Operational Event Log can be incorporated into a timeline to not only illustrate program execution, but that the execution succeeded and resulted in the intended (by the threat actor) outcome. For example, if you incorporate EDR into a timeline that includes the Windows Event Logs, then you'd likely look for WMI-Activity/5861 event records to see if a new event consumer had been successfully created. 

From there, the next step would be to parse the Objects.DATA file to determine if the event consumer is still visible in the WMI repository. 

Summary
Continuing to see artifacts such as ShimCache and AmCache referred to in the community as "evidence of execution" really showed me how we're overall too focused on the one thing that illustrates that something happened. While it's important to have a correct, accurate understanding of the nature of various individual artifacts, as a community we need to start processing this understanding within a system framework, understanding that each data source plays an important role within the system, as a whole. Nothing happens in isolation; whenever something happens on a live system, impressions and tool marks are going to be left in a variety of data sources. Some may be extremely transient, existing in memory for only a very short time, while others may be written to logs or to the Registry, and persist well beyond the removal of the "offending" application. 

But, I get it. It's easy to simply state that something happened, and hope that no one questions your statement. It's much harder to make a statement supported by data, because doing so isn't something we're familiar with, it's not something we've been doing for years at this point. It's not part of our process, nor is it part of our culture. But remember...everything is difficult, sometimes even after the first time we do it. Climbing a rope in gym class was hard, until you first did it. It may even have been hard the second or third time, but eventually you realized you could do it. 

Validation of your findings is important, because when you complete the ticket or the report you're writing, and send it off to your "customer", someone may be making a decision and allocating resources based on those findings. My previous blog post provides one example of how I've experienced the need to validate findings during my time in the industry. Whether you see it right now or not, at some point, someone's very likely going to take your findings and make a decision based on what you're provided, and you want to be as sure as you can that those findings are correct, and supported by the data.

Wednesday, June 25, 2025

Program Execution, follow-up

 Last Nov, I published a blog post titled Program Execution: The ShimCache/AmCache Myth as a means of documenting, yet again and in one place, the meaning of the artifacts. I did this because I kept seeing the "...these artifacts illustrate program execution..." again and again, and this is simply incorrect. 

I recently ran across Mat's post on Medium called Chronos vs Chaos: The Art (and Pain) of Building a DFIR Timeline. Developing timelines is something I've done for a very long time, and continue to do even today. The folks I work with know that I document my incident reviews with a liberal application of timelining. I first talked about timelining in Windows Forensic Analysis 2/e, published in 2009, and by the time Windows Forensic Analysis 3/e was published 3 yrs later, timelining had it's own chapter.

In his post, Mat quite correctly states that one of the issues with timelining is the plethora (my word, not his) of time stamp formats. This is abundantly true...64-bit formats, 32-bit formats, string formats, etc. Mat also states, in the section regarding "gaps", that "Analysts must infer or corroborate from context, which is tricky"; this is very true, but one of the purposes of a timeline is to provide that context, by correlating various data sources and viewing them side-by-side.

Not quite halfway into the post, Mat brings up ShimCache and AmCache, and with respect to ShimCache, refers to it as:

A registry artifact that logs executables seen by the OS. Specifically, it records the file path and the file’s last modified time at the moment the program was executed...

So, "yes" to "executables seen by the OS", but "no" to "at the time the program was executed". 

Why do I say this? If you refer back to my previous blog post on this topic, and then refer to Mandiant's article on on ShimCache, the following statement will stand out to you:

It is important to understand there may be entries in the Shimcache that were not actually executed. [emphasis added]

So, a program doesn't actually have to be executed to appear in the ShimCache artifact.

With respect to the AmCache artifact, Mat states that it "does record execution times", but that is perhaps a too general, too broad-brush approach to the artifact. When considering the AmCache artifact in isolation, please refer to Analysis of the AmCache v2. For example, pg 27 of the linked PDF, under the "AmCache" section, states:

Furthermore, for the PE that is not part of a program, this is also a proof of execution. As for the last modification date of a registry File key, it corresponds with a run of ProgramDataUpdater more often than not.

This states that for Windows 10 version 1507, the File key LastWrite time is the last execution time, but not for the identified executable file. 

Finally, as an additional resource, Chris Ray over at Cyber Triage recently posted an Intro to ShimCache and AmCache, where he stated:

Due to the complex nature of these artifacts, it’s best to think of this data under evidence of existence rather than evidence of execution. In certain scenarios you can show a file executed with a high degree of confidence, but should never be the definitive proof that something ran.

Mat also states in his post, "AmCache is often used in conjunction with ShimCache...", which may be the case, but the "conjunction" part should not end there. If you're attempting to demonstrate program execution, for example, you should use all of the artifacts that Mat mentions in his post (MFT, Prefetch, UserAssist, ShimCache, AmCache, etc.), if available, in conjunction with others, to not only demonstrate program execution, but to also provide much greater insight and context than you'd get from just one of the artifacts.

When I was taking explosives training in the military, they had a saying for detonators: One is none, two is one. The idea is that one detonator, by itself, could fail, and has failed. But the likelihood of one of two detonators failing is extremely small. This idea can also be applied to demonstrating any particular category in digital forensics, including program execution...one artifact by itself, in isolation, is essentially "none". It could fail to do it's job, particularly if we're talking about ShimCache or AmCache by themselves. 

You should also consider additional artifacts to provide more granular context around the execution. If Process Tracking is enabled, the Security Event Log can be valuable, particularly if the system also has the Registry value set enabling full command lines. If Sysmon is installed, the Sysmon Event Log would prove incredibly valuable. The Application Event Log may provide indications of application failures, such as Application Pop-up or Windows Event Reporting failures. The Application Event Log may also contain DCOM/10028 messages referring to netscan or Advanced IP Scanner being executed. The Windows Defender Event Log may contain ../1116 records indicating a detection, followed by ../1119 records indicating a critical failure in attempting to quarantine the detected behavior. 

So, What?
Why does any of this matter? Who cares?

When I was performing PCI forensic investigations, one of the things Visa (the de facto "PCI Council", at the time) wanted us to include in our reports was a value called "window of compromise". This equated to the time from when the endpoint was compromised and the credit card gathering malware was placed on it, to the point where the compromise was detected and responded to/remediated. During one investigation, I found that the endpoint had been compromised, the malware dropped and launched, and then shortly thereafter, the installed AV detected and quarantined the malware. The threat actor then returned about 6 weeks later, on about 6 Jan, and put the malware back on the endpoint; this one wasn't detected by the AV. 

Now, if I had simply said that the "window of compromise" began when the malware was first placed on the system, without qualification or context, then Visa could have assessed a fine based on the number of credit cards processed over that 6 week period. That period was over the Thanksgiving-to-Christmas time frame is historical when more purchases are made, and the assessment of processing volume would have had a significant impact on the retailer. 

At the time, the malware that a lot of threat actors were using had a component that was "compiled" Perl code, and each time it was launched, the "compiled" Perl runtime was extracted into a unique folder path. Using the creation and last modification times of those folders, we could determine when and how often these components were run. As the malware had been quarantined by the AV, as expected, we found no indication of these folders during that 6 wk period.

The outcome of an investigation...your findings...can have a profound impact on someone, or on an organization. As such, having context beyond just the ShimCache or the AmCache, incorrectly put forth as "evidence of execution" solely and in isolation, is extremely important. 

I've Seen Things, pt II

As a follow-on to my previous post with this title, I wanted to keep the story going; in fact, there are likely to be several more posts in this series, so stay tuned.

And hey, I'm not the only one sharing my journey! Check out Josh's blog, particularly his recent post about how he broke into cybersecurity! I might have been drawn to Josh's post because, like me, he's a former Marine, although I can say that I was in the Corps back before computers were in common usage, back when we used radios that were 1950s tech, built in the 1970s. We didn't cross paths...I was off of active duty 12 yrs before Josh went to boot camp, but even so, there's some commonality in shared traditions and experiences.

Okay...back to it!

Programming
Programming is talked about a great deal within the industry, particularly within DFIR. Some folks will say that you absolutely need to be able to program, and even have very strong feelings about the language of choice, and others will do just fine with basic shell scripting and batch files. I've met some folks who are really great programmers, coming up with either individual projects, or more team or community based ones, like Volatility. A lot of the programming very often seems specialized, like HindSight, while other projects and contributions might be a bit more general. Even so, some of the absolute best DFIR analysts I've ever worked with have had minimal programming capabilities, not going much beyond shell scripting and regexes. 

As a result, when it comes to programming, your mileage may vary. I will say this, though...the experience of programming, in whichever language or framework you opt for, has the benefit of helping you understand how to break things down into manageable "chunks". Whether you're writing some code to manage logs, or you're leading an IR engagement, you'll realize that to get from A to Z, you first have to get from A to B, then to C, and then to D, and so on. Accomplishing a task by writing code forces you to approach the problem in that manner, and as such, has benefits outside of just getting the coding task completed.

I started programming BASIC on a MacIIe in the early '80s, and then did some small programming tasks on a Timex-Sinclair 1000; "small" because saving programs to or loading them from a tape recorder, or copying them out of a magazine, was a whole new level of hell. In high school, I took AP Computer Science the first year that it was offered; the course used Pascal as the language of choice, and when I got to college, it was back to BASIC on TRS-80 systems. When I got to graduate school (mid-'90s), it was MatLab, a small amount of C and some M68000 assembly, and then Java. At one point, just as I was leaving active duty, I had a small consulting gig teaching Java programming to a team at a business.

After I moved to the private sector, I taught myself Perl, initially because the network engineers were looking for someone to join their team with that skillset. I later ran across Dave Roth's work, and found some really fantastic use for his modules, bought his book, and even got in touch with him directly. I continued to stick with Perl, as at the time, it was the only language that had a functioning module for accessing offline Registry hives. I'd started writing my own module for this, but ran across James Macfarlane's module and figure, why not?

The Roles
My first role out of the military was at a small defense contracting firm, and that really didn't work out. After a short stay, I moved on to Trident Data Systems; these folks were another defense contractor, with offices in San Antonio, TX, and LA. As it turned out, I ended up on the commercial team, which was great. We did vulnerability assessments, and because we had a really good sales guy, that's what we did, and as a team, we got really good at it. Every now and then, something a bit different would come along, like a pen test, but for the most part, we had a lot of work in vuln assessments.

My boss in this jo was a retired Army Colonel; right off the bat, he told me that we were using ISS's Internet Scanner product, and that it would probably take about 2 - 3 years of running the tool regularly to really understand what it was doing. I thought he was right...there was a pretty, and pretty complicated GUI, and if you didn't turn off some of the defaults, like the check of the net send "vulnerability", you'd end up sending a message to every desktop, creating a headache for the local admin. 

As it turned out, within about 6 months, I started using those Perl skills I'd developed, along with Dave Roth's modules, to begin writing a replacement for Internet Scanner commercial product. The ISS product was a black box...you pushed a button, and it gave you answers back. Only we didn't know what the product was "looking at", nor how it was determining that something was "vulnerable". As we began to look closer and with a lot of digging into the MS KnowledgeBase, we began to figure out what the product was checking, and we started to see that some of the answers were wrong; one of the biggest issues we ran into was when the tool told us that the AutoAdminLogon functionality was "enabled" on 21 systems in one particular office, and it turned out that it was only truly enabled on one system. To make things worse, the customer knew that only one system had the functionality enabled; it had previously been enabled on the other 20 systems, but the customer had knowingly and painstakingly disabled it. So, it was a good thing that we were running the ISS product side-by-side with the new tool we were developing, and checking the work.

This was one of the first moments in my private sector career that really illustrated the need to understand, to really know, what your tools were doing and how they were doing it. This led to other moments throughout the ensuing 25+ years, as this lesson was continually revisited, again and again.