In a prior post I described how to detection potential Log4shell (CVE-2021-44228) exploitation by looking for patterns in a Java process’ write() or sendto() buffer in LDAP and RMI connections. One limitation of this is that it matches on text in the buffer.

The good news is that as of version 0.32.0, Falco now supports matching on raw bytes expressed as hexadecimal strings! This means that we can now match on any pattern in the buffer, not just “human-readable” text.

The other limitation of the aforementioned detection is that it does not distinguish between a legitimate LDAP or RMI connection and one that was triggered by Log4shell, hence making it only effective on organizations where Java JNDI connections are rare or nonexistent.

This post addresses these two limitations using Falco’s new byte matching feature.

Abstract

Instead of looking for outbound LDAP and RMI from a Java process, look for Java processes that download Java class files. This is bound to be less noisy as this behavior should not be common in Java.

Fortunately, a Java class can be easily identified by its 4-byte header 0xCAFEBABE, also known as the magic number.

I would also like to note that this is not my original idea an was suggested by @loresuso in the course of my submitting a PR for the prior detection method. I only did the validation and rule-writing.

Analysis

As usual, I turned to Sysdig for analysis. I expanded the command to watch for read() and recvfrom() events:

sysdig -X "evt.type in (write, sendto, read, recvfrom) and fd.type in (ipv4, ipv6) \
    and proc.name=java" \
    -p"%fd.name (%evt.type, %evt.buflen bytes) %evt.buffer"

I did not have time to do all the tests I did last time, so I settled for testing on a PoC using Java 17 and at least one pre-17 version.

For Java 17, I used the original PoC provided to me by d0nutptr. The magic number was easy enough to catch:

I then tried a PoC vulnerable app christophetd/log4shell-vulnerable-app which runs on Java 8, while still using d0nutptr’s attacker LDAP and HTTP server.

Similar results, only that it uses recvfrom() instead of read(), as expected.

Falco rule

# Rule for detecting potential Log4Shell (CVE-2021-44228) exploitation
# Note: Not compatible with Java 17+, which uses read() syscalls

- macro: java_network_read
  condition: (evt.type=recvfrom and fd.type in (ipv4, ipv6) and proc.name=java)

- rule: Java Process Class File Download
  desc: Detected Java process downloading a class file which could indicate a successful exploit of the log4shell Log4j vulnerability (CVE-2021-44228)
  condition: >
                java_network_read and evt.buffer bcontains cafebabe
  output: Java process class file download (user=%user.name user_loginname=%user.loginname user_loginuid=%user.loginuid event=%evt.type connection=%fd.name server_ip=%fd.sip server_port=%fd.sport proto=%fd.l4proto process=%proc.name command=%proc.cmdline parent=%proc.pname buffer=%evt.buffer container_id=%container.id image=%container.image.repository)
  priority: CRITICAL
  tags: [mitre_initial_access]

This rule has been merged to Falco mainline and will be part of the default ruleset (tentatively) in version 0.32.1.

To make this rule work with Java 17+ Falco needs to run with the -A flag (monitor ALL syscalls), then with the macro changed to:

- macro: java_network_read
  condition: (evt.type in (recvfrom, read) and fd.type in (ipv4, ipv6) and proc.name=java)

Limitations

  • This rule is not able to detect downloads via HTTPS
  • I have not fully tested whether or not the magic number can be obscured by making the HTTP server return a large chunk of headers (beyond the buffer falco is able to see by default), but I suspect that the answer is yes.

Acknowledgements

Thank you @loresuso for the review and guidance.