Expanding on Pyramid of Pain

I believe most threat hunters would already be familiar with the Pyramid of Pain. Most hunters aim to detect artefacts and tools, as they are higher up the pyramid. However, there is scarce information available to guide them in doing so. Using my red team knowledge, I would like to expand on the tools segment of the pyramid of pain to help threat hunters write better tool detection queries.

image

Executable Name

To detect the use of nmap, the most straightforward query would simply be sourcetype=os_logs process.name="nmap.exe". Some hunters will stop here and pat themselves on the back for reaching the top of the Pyramid of Pain. Unfortunately, it is one of the easiest query to circumvent. Almost every computer user knows how to rename a file. In this case, renaming nmap is sufficient to circumvent this query. No self respecting adversary is going to commit this mistake, the only instances of nmap you detect would be those owned by sysadmins who have no reason to hide their use of the binary.

Sophisticated adversaries will even choose a name which suits the functionality of the tool. I like using a variant of print discovery utility.exe. Most printer vendors release utilities which will scan the subnet to detect connected printers and automatically install and configure it. A befitting name for nmap indeed.

Also, certain OS binaries like rundll32.exe and mavinject.exe will work even if it has been renamed. Adversaries will make a copy of such binaries, place it in a different folder and profit.

Version Info

Detection based on Version Info resource is more frequently seen in YARA rules and less commonly available in threat hunting solutions. To detect nmap which is published by Insecure.org, a query such as sourcetype=os_logs process.version_info="*Insecure.org*" would be used. I would categorise it as a step above executable name as it causes slightly greater pain for the adversary. Instead of simply renaming the binary, the adversary has to use tools such as Resource Hacker to modify the Version Info.

If a binary is signed, such a modification would cause the signature verification to fail.

image

CLI arguments

Detection based on CLI arguments bring even greater pain to the adversary. To detect nmap, such a query may look like sourcetype=os_logs (process.command_line="*--top-ports*" || process.command_line="* -p21,*" || process.command_line="* -p22,*". In order for the adversary to circumvent CLI argument detection, he will need to modify the source code and recompile the tool, or to change individual bytes in the binary itself.

A bit of human psychology is at play here. Humans will tend to list numbers in ascending order, i.e. "-p21,22,80,139,443,445,3389". Hence, by detecting the first few common ports, we will likely be able to catch most attempts. Listing every single combination exhaustively would just place too much stress on the query engine.

I have seen hunters write queries such as sourcetype=os_logs process.name="rundll32.exe" && process.command_line="*zipfldr.dll,RouteTheCall*". Such a query is indeed useful in cutting down false positives and only picking up misuse of rundll32.exe. However, in terms of Pyramid of Pain, such a query would belong to the "Executable Name" level since it breaks once the adversary renames rundll32.exe. For it to belong at the CLI arguments level, the query should look like sourcetype=os_logs process.command_line="*,RouteTheCall*". Of course, when crafting such queries, it is important to find command line arguments which are unique enough to stand alone by itself.

image

Do take note that DLL exports can be called using their ordinal numbers as well. For example, PrintUIEntryW is ordinal #3. Hence, rundll32 printui.dll,PrintUIEntry can also be executed using the command rundll32 printui.dll,#3. As far as I know, using ordinal numbers will cause issues with arguments passed to the DLL, hence it does not work for certain LOLBAS.

All

Writing good queries require a bit of creativity and in depth understanding of the tools involved. I have found JPCERT's resources to be very useful in understanding the various artefacts that are created when such tools are run. Hunters will also need to run these tools themselves, figure out how they work before they can write good queries.

This section is named all because a combination of all different indicators used in a creative manner is the answer to good detection with low false positives. Adversaries may adopt some of these tactics to avoid detection, but as long as they miss out on one, you would be able to detect them. i.e. To detect nmap, a query like sourcetype=os_logs (process.version_info="*Insecure.org*" || process.command_line="*--top-ports*" || process.command_line="* -p21,*" || process.command_line="* -p22,*") uses multiple indicators. Adversaries will need to circumvent both the Version Info and the CLI arguments portion of the query to escape detection.

Happy hunting!