Following the successful launch of owLSM, our first open-source project with more than 250 GitHub stars as of writing, we are now launching a blog series to explore the project's practical applications, capabilities, and value.
In this article, we demonstrate how to detect and prevent new vulnerabilities immediately after a proof of concept (PoC) is released using owLSM.
We previously used owlSM with the notorious copy.fail Linux vulnerability and it was the first open-source project that released a rule that detects and prevents copy.fail exploitation. See the rule and explanation here.
However, today we are going to focus on the CrackArmor vulnerability as it's a much simpler vulnerability to explain to the less technical readers, but the flow and concept of how owLSM stays the same.
CrackArmor in a Nutshel
CrackArmor groups nine vulnerabilities, where the most interesting ones allow an unprivileged local attacker to load, replace, and remove AppArmor profiles. Using this vulnerability, Qualys demonstrated local privilege escalation (LPE), denial of service (DoS), and access control bypass.
owLSM
owLSM is a security agent that implements a stateful Sigma rules engine, providing security teams with the strongest prevention capabilities of any open-source project and great observability for their Linux assets.
First Step: Monitoring CrackArmor
In order to understand what rule to create for CrackArmor, we must see what events owLSM generates when we exploit the vulnerability.
1. We run owLSM without any config, so it’s in “observability only” mode: ./owlsm > events.log.
2. We exploit the vulnerability.
bob@vm:/tmp$ id
uid=1004(bob) gid=1004(bob) groups=1004(bob),100(users)
bob@vm:/tmp$ ls -l /sys/kernel/security/apparmor/policy/profiles/*rsyslogd*
total 0
-r--r--r-- 1 root root 0 Nov 26 16:31 attach
-r--r--r-- 1 root root 0 Nov 26 16:31 mode
-r--r--r-- 1 root root 0 Nov 26 16:31 name
-r--r--r-- 1 root root 0 Nov 26 16:31 sha256
bob@vm:/tmp$ su -P -c 'stty raw && echo -n rsyslogd' "$USER" > /sys/kernel/security/apparmor/.remove
Password: # The unprivileged user password
bob@vm:/tmp$ ls -l /sys/kernel/security/apparmor/policy/profiles/*rsyslogd*
ls: cannot access '/sys/kernel/security/apparmor/policy/profiles/*rsyslogd*': No such file or directory
We can see that an unprivileged user is able to remove AppArmor profiles using theCrackArmor vulnerability, which is something that only rootis supposed to do.
3. Now we go through the events owLSM generated, looking for interesting CrackArmor-related events. We see the following event (next page):
{
"action": "ALLOW_EVENT",
"id": 11644,
"time": 10519555087103152,
"type": "WRITE",
"data": {
"target": {
"file": {
"dev": 6,
"filename": ".remove",
"inode": 2151,
"last_modified_seconds": 1774694243,
"mode": 438,
"nlink": 1,
"owner": {
"gid": 0,
"uid": 0
},
"path": "/sys/kernel/security/apparmor/.remove",
"sgid": 0,
"suid": 0,
"type": "REGULAR_FILE"
}
}
},
"process": {
"cgroup_id": 1925910,
"cmd": "su -P -c stty raw && echo -n rsyslogd bob",
"egid": 1004,
"euid": 0,
"file": {
"dev": 264241152,
"filename": "su",
"inode": 5122498,
"last_modified_seconds": 1712671357,
"mode": 493,
"nlink": 1,
"owner": {
"gid": 0,
"uid": 0
},
"path": "/usr/bin/su",
"sgid": 0,
"suid": 1,
"type": "REGULAR_FILE"
...
},
"pid": 2073929,
"ppid": 2072312,
"ptrace_flags": 0,
"rgid": 1004,
"ruid": 1004,
"shell_command": "",
"start_time": 10519552320407528,
...
},
"parent_process": {
"file": {
"path": "/usr/bin/bash",
"sgid": 0,
"suid": 0,
"type": "REGULAR_FILE",
...
},
"pid": 2072312,
"ppid": 2072310,
"ptrace_flags": 0,
"rgid": 1004,
"ruid": 1004,
"shell_command": "su -P -c 'stty raw && echo -n rsyslogd' \"$USER\" > /sys/kernel/security/apparmor/.remove",
...
},
}
Understanding the Event
owLSM events contain a lot of information. To see all attributes and to understand each one, see Events Breakdown. Looking at the event, we can see the following:
-
The event type is WRITE
-
The target file is /sys/kernel/security/apparmor/.remove
-
parent_process.shell_command shows us the command that was executed
-
The process that performed the write operation is su
-
The process binary has the SUID bit set process.file.suid: 1, which is a requirement of the vulnerability.
-
The process euid (effective user ID) is 0 (root) but the ruid is 1004 (bob). This is due to the SUID bit.
Writing the Rule
We need to write a single agnostic rule that will cover all cases of this vulnerability. If you read the Qualys report, you know that:
-
CrackArmor vulnerabilities target different files in /sys/kernel/security/apparmor/
-
An attacker can use any SUID binary that allows him to control what is written to the files /sys/kernel/security/apparmor/* , not only su
The Rule:
title: CrackArmor mitigation
id: 1
description: "CrackArmor: block non-root writes using suid binaries to AppArmor control files"
action: "BLOCK_KILL_PROCESS"
events:
- WRITE
logsource:
product: linux
category: file_event
detection:
selection_apparmor_path:
target.file.path|startswith: "/sys/kernel/security/apparmor"
selection_suid_binary:
process.file.suid: 1
filter_root:
process.ruid: 0
condition: selection_apparmor_path and selection_suid_binary and not filter_root
What the Rule Does: It monitors write events to paths starting with /sys/kernel/security/apparmor, where the binary performing the write is a SUID binary and the real user ID isn’t 0 (so it’s not actually root doing the writing).
When this happens, owLSM will block the write operation and kill the process.
This ensures that only root can modify AppArmor profiles, even if the attacker uses a SUID binary that runs with root permissions.
What We Learned
We saw how to create a prevention rule for a malicious operation (an exploit) in less than 10 minutes.
Just run owLSM, simulate the attack, find an event you want to focus on and write a rule that will match against that event.
When to Use owLSM
For many public vulnerabilities, we can just patch the software/system, thus mitigating the vulnerability. However, in instances where a patch isn’t available, it will take time until a patch can be implemented, or to prevent malicious activities from being performed in your Linux environment, owLSM proves to be an effective tool.
Help Us
Support us by giving the project a GitHub star. By doing so, you prove that our decision to open-source owLSM was correct and encourage more vendors to do the same.