spring4shell detection and response — Elastic
Using the Elastic stack to detect potential malicious requests and explore exposure to the RCE flaw in the Java Spring Framework.
If you want to know what spring4shell is and the timeline, I recommend searching for it. This post is an attempt at providing insight into how you can use some basic elastic capabilities to detect some of the POC code and how auditbeat can help you in determining where to look for potential vulnerabilities.
As details started to emerge[1, 2, 3, 4] confirming the rumors of the day before and providing POC code. Work started on how to detect attempts at exploitation of the vulnerability and finding out if you were vulnerable.
Exposure
Auditbeat provides a robuust way of keeping track of the installed packages on your Linux and Mac system(s). As the vulnerability has two base requirements, the first is JDK9 or above. The second appears to have been access to the ‘WebAppClassLoader’ class. Looking for the first requirement is straight forward with a KQL query on auditbeat:
event.dataset:package and system.audit.package.name:(*jdk* or *java*)
The results can be used to filter out the versions you don’t want to by excluding the system.audit.package.version’s.
You are then left with anywhere between a couple and thousands of hosts depending on your environment. Prioritizing these hosts is a matter you probably know how to do, but i’d start with the internet exposed ones and moving inward.
Detection
Below detections are rudimentary and effective depending how much and how complete your logs are.
Detecting attempts at exploitation is relatively difficult as more details became available it became clear it is not a question of the request parameters but more of the body being send[1]. However, based on earlier details and combining with new information we can start writing some rudimentary detections.
The first one you could start with was based on the WAF rule shared by cyberkendra. The below EQL rule would look for these strings in the request parameters.
web where url.original regex (“.*class.*”, “.*Class.*”) or url.path regex (“.*class.*”, “.*Class.*”) or url.full regex (“.*class.*”, “.*Class.*”)
We later on evolved this detection to the below, which proved successful in blocking basic attempts
where (url.full regex (“.*classLoader.*”) or url.path regex (“.*classLoader.*”) or url.original regex (“.*classLoader.*”) or url.query regex (“.*classLoader.*”))
However we quickly learned this rule had one mayor flaw, it was case sensitive. Meaning it again evolved into
web where (url.full regex (".*(c|C)(l|L)(a|A)(s|S)(s|S)(l|L)(o|O)(a|A)(d|D)(e|E)(r|R).*") or url.path regex (".*(c|C)(l|L)(a|A)(s|S)(s|S)(l|L)(o|O)(a|A)(d|D)(e|E)(r|R).*") or url.original regex (".*(c|C)(l|L)(a|A)(s|S)(s|S)(l|L)(o|O)(a|A)(d|D)(e|E)(r|R).*") or url.query regex (".*(c|C)(l|L)(a|A)(s|S)(s|S)(l|L)(o|O)(a|A)(d|D)(e|E)(r|R).*"))
Now what?
You can start exploring the details of the vulnerability and run the poc code against your own resources (at your own risk) to try and build detections.
One of the mayor tactics expected would be to create reverse shell(s) so playing around with an EQL sequence detection could yield positive results.
Final note
On a final note: It is always better to patch and resolve vulnerabilities then it is to mitigate the risk of exploitation. But as we all know this is not always possible and this is where your SecOps team(s) come in.