Skip to content

Interpolating Log4Shell

GuilhermePereira edited this page Feb 22, 2023 · 5 revisions

eLogJ

extended Log4j is a tool that essentially allows for detection and prevention of the Log4Shell attack. It was developed around a un-secure logger that logged information directly from the HTTP header field (X-Api-Version) without any type of data sanitisation or pre-processing. In order to trace sufficient information to be able to detect the Log4Shell attack, tracing programs were needed in strategic positions to provide run-time detection.

eLogJ is thus composed of two separate eBPF programs working in unison to analyse the current state of the network activity and adapt according to user-defined rule-sets considering the paradigm of the Log4Shell attack. State is maintained using eBPF maps, which are essentially generic storage units of different types for sharing data between the kernel and user space. Although these units are useful, they can easily be tampered with since eBPF provides direct communication from any space regardless of the map type. This is why a eBPF Linux Security Module program was also added, to verify data structure integrity and block malicious intervention, such as, deleting a eBPF map during run-time.

The following page will dissect eLogJ as a whole, the figure bellow showcases the tools landscape within the Log4Shell paradigm. The main interpolation occurs at steps 1 & 2. Note that from the loggers' perspective, steps 1 & 3 are considered as inbound traffic leaving step 2 as outbound traffic. This is an important abstraction to reflect since the type of eBPF programs vary according to the flow of traffic (according to an interface, eBPF network programs are essentially hooked around a user-defined interface). This implies several performance considerations as will be expressed in the following sections.


eBPF maps

As in most eBPF programs, eBPF maps are the cornerstone for any type of interpolation and/or tracing. These maps are essentially data structures that allow manipulation of data from user and kernel space. There are several types of eBPF maps, although currently our eBPF framework only uses two types of map structures.

  1- PerfEventArray
    This type of map is used exclusively for sending events (EventLog) from kernel-space to user-space. At the moment, the structure EventLog is composed of simple fields to allow packet tracing from both ends of where interpolation is possible, that is, inbound and outbound. Notice that throughout the landscape of eBPF there are several maps specialised for sending events to user-space from kernel-space. Due to the nature of our scenario and the reduced amount of events being sent out, the map type PerfEventArray was used instead of the PerfEventArrayBuffer type (Ring Buffer). As expressed in [3], the main distinction between the two is that the latter provides better memory efficiency by being able to share the data structure across several CPUs while still preserving event ordering. The former doesn't preserve event ordering and is allocated in a per-CPU basis thus, when multiple CPUs are available, performance is worse. From [4] and [5] we can conclude that switching between these types should be trivial (since the former is inherited in the latter).

  2- HashMap<u32, u32>
    The HashMap data structure is the main eBPF map type used throughout eBPF programs. These maps are basically used to provide state information between inbound and outbound traffic. For each scenario where eBPF is used, a more formal definition will be given. For know, the important aspect is that each map is constituted by u32 key and value data types. In most cases the key will be the equivalent of an IP address as an unsigned integer, as a reference, consider this ip converter: https://www.ipaddressguide.com/ip.

Inbound traffic

TODO: Traffic control (TC) - Explain Shallow Packet Inspection / State propagation with XDP

Outbound traffic

TODO: Express Data Path (XDP) state propagation from TC ; Add figure for LOOKUPS map
The outbound traffic is traced by a eXpress Data Path (XDP) eBPF program. It is assumed that our logger (running Log4J) doesn't have out-going traffic other than possible JNDI lookups. Thus, this program must essentially trace for GET HTTP requests and/or TCP packets to be able to apply the rule-sets defined in eLogJ. Detection of JNDI lookups is dependable from TC and XDP, both control the LOOKUPS map which allow for rule-set application. Lookups aren't strictly preserved, the map can be initially updated by TC and consequently registered in XDP from the GET request which was originated from the malicious JNDI payload. This request is used to fetch the malicious java class that the log4j logger will consequently execute (leading to remote code exploitation). In order to provide efficient use of the map's state, the LOOKUPS map stores a counter value which indicates the number of active lookups, this counter is incremented at TC (inbound - when JNDI lookup procedure starts) and decremented in XDP (outbound - final phase of JNDI lookup**1).

**1 - Assuming GET request is detected (and no other HTTP communication)

Linux Security Modules (LSM)

Linux Security Modules can also be integrated in eBPF. In this case, LSM is used to provide an (optional)* extra layer of integrity assurance by tracing the bpf sys-call. Since eLogJ depends on bpf system calls to trace information, LSM must me placed so that no initial sys-calls are blocked, allowing the framework to boot without interruption.


From hindsight, eBPF map manipulation from kernel space can't be traced using LSM. Although, after booting eLogJ, external user space intervention will always be needed to load or manipulate state maps, resulting in sys-calls that are traceable by LSM. Assuming that eLogJ is the only eBPF tool running in the system with eBPF map manipulation. Privilege of loading further eBPF programs/object code (btf) or updating eBPF maps can be revoked, assuring that no third-party/malicious intervention is conducted.

Logging

TODO: EventLog , log_type (local/remote), Wazuh



Ref:
[1] => https://docs.kernel.org/bpf/maps.html
[2] => https://docs.cilium.io/en/stable/bpf/
[3] => https://www.kernel.org/doc/html/latest/bpf/ringbuf.html
[4][PerfEvent]  => https://docs.rs/aya/latest/aya/maps/perf/struct.PerfEventArray.html
[5][RingBuffer] => https://docs.rs/aya/latest/aya/maps/perf/struct.PerfEventArrayBuffer.html
[6] => https://man7.org/linux/man-pages/man2/bpf.2.html
Clone this wiki locally