Log4Shell (CVE-2021-44228): Splunk Searches for Detecting Vulnerable Applications
This article shows how Splunk searches based on uberAgent UXM inventory & process startup data can help identify hosts and applications with versions of the Log4j library that have the Log4Shell vulnerability (CVE-2021-44228).
Log4j is a Java library. Let’s start by searching for machines where Java is installed.
The following Splunk search queries uberAgent’s application inventory data for Java installations and returns the machine (host) name, the application name, the application version and the appliction’s publisher (vendor).
index=`uberAgent_index` sourcetype=uberAgent:Application:ApplicationInventory java | stats count by host DisplayName DisplayVersion Publisher | fields - count
The following Splunk search queries uberAgent’s process startup data for starts of Java processes and returns the machine (host) name, the application name, the application version, the process name, the process’ parent name and the process path.
index=`uberAgent_index` sourcetype=uberAgent:Process:ProcessStartup ProcName=java OR ProcName=java.exe OR ProcName=javaw.exe | stats count by host AppName AppVersion ProcName ProcParentName ProcPath | fields - count
Now that we know where Java is installed and running, let’s move on to detecting vulnerable application installations.
The Dutch Nationaal Cyber Security Centrum maintains the vulnerability status of many applications in a table on GitHub. Unfortunately, it includes both vulnerable and invulnerable applications, so we need to filter.
To do that, I copied the raw Markdown view of the GitHub page to a text editor and cleaned it up a little, removing the unnecessary subheadings and rows where the product column was empty. Then I converted the Markdown table to XSLX in this online converter.
The resulting Excel sheet can be easily filtered. I had to fix some little errors where columns were mixed up (originating from the data source on GitHub, not from the conversion). Then I configured a filter that excluded applications that were known to be not vulnerable. The resulting table had 658 rows (down from 1551 in the unfiltered table).
In order to use the table as a lookup in Splunk I needed it in CSV format. Astonishingly, Excel is incapable of exporting selected columns to CSV, so I used the following formula to get a CSV with vendor, product, version, and vulnerability status:
="""" & A2 & """,""*" & A2 & "*"",""" & B2 & """,""*" & B2 & "*"",""" & D2 & """,""" & C2 & """"
I pasted that in a new column, copied the resulting CSV to a text editor, and saved it to disk after adding the heading:
Next, in Splunk’s UI I navigated to Settings > Lookups > Lookup table files > Add new and uploaded the CSV file in the app
uberAgent with the destination filename
Side note: this upload process places the file in the directory
$SPLUNK_HOME/etc/users/USERNAME/uberAgent/lookups on the Splunk server’s disk (docs).
In order to be able to configure case-insensitivity and enable wildcards for some fields, it is necessary to turn the lookup table into a lookup definition. First, go to Settings > Lookups > Lookup table files, search for
Log4ShellVulnerableAppList in all apps, and change the lookup’s permissions to
All apps (system):
Then go to Settings > Lookups > Lookup definitions and click Add new. I used the following options:
- Destination app:
- Lookup file:
- Advanced options > Case sensitive match: unchecked
- Advanced options > Match type:
The completed lookup definition form looks like this:
Application and product names are far less standardized than one might assume. Even vendors themselves use multiple variants like
Adobe Inc., and
Adobe Systems Incorporated. Our vulnerability data source generally uses simpler (shorter) names, which is helpful in our case. The lookup table we created contains both wildcard and standard versions of the supplier (vendor) and product fields.
The following Splunk search lists all installed applications where the product and vendor name wildcard-match an entry in the vulnerability data table:
index=`uberAgent_index` sourcetype=uberAgent:Application:ApplicationInventory | stats dc(host) as "Installed host count" by DisplayName Publisher | lookup Log4ShellVulnerableAppList ProductWildcards as DisplayName, SupplierWildcards as Publisher | eval ProdMatchTest="Z".Product."Z" | where NOT ProdMatchTest="ZZ" | rename DisplayName as "Installed product name" Publisher as "Installed product vendor" Product as "Vulnerable product" Status as "Vulnerability status" Supplier as "Vulnerable Supplier" Version as "Vulnerable version(s)" | fields - ProdMatchTest
The resulting table looks as follows: