PwnKit: detect privilege escalation with CrowdSec

Qualys just published CVE-2021-4034 which is trivial to exploit and impacts a large variety of distributions and versions. In a nutshell, the vulnerability, also called PwnKit, allows for a local escalation of privilege (LPE), due to out-of-band writing, in Polkit’s Pkexec, an alternate solution to the “sudo” privilege management tool. Pkexec is installed by default on most popular Linux distributions. A successful exploit can lead to handing admin/root privileges to unauthorized users. 

While everybody loves a fine LPE, it’s mostly an excuse for us to take a look at another aspect of CrowdSec: pure alerting capabilities along with remediation.


We just published a new collection, targeting Linux’s Local Privilege Escalation, and CVE-2021-4034 is its first scenario! While this will not allow you to prevent the exploit, it will give you insight on whether you have been compromised by this vulnerability. Stay tuned as we add additional exploit attempt scenarios to the collection.

A successful exploitation for PwnKit is quite trivial to detect in the system logs:

Jan 27 13:03:43 ip-172-31-32-108 pkexec[25573]: centos: The value for the SHELL variable was not found the /etc/shells file [USER=root] [TTY=/dev/pts/1] [CWD=/home/centos/poc-cve-2021-4034-main] [COMMAND=GCONV_PATH=./gconv PATH=GCONV_PATH=. SHELL=/fake/shell CHARSET=payload]

(Please note that it has already been reported that smarter attackers may exploit the vulnerability without leaving any trace in the logs, but it’s not really the topic here)

The collection itself can be found here.

Let’s install it, assuming that you already have a running CrowdSec 1.3 instance, otherwise please see the documentation:

cscli collections install crowdsecurity/linux-lpe….
systemctl reload crowdsec

Let’s try our exploit freshly grabbed from GitHub:

[centos@ip-172-31-32-108 poc-cve-2021-4034-main]$ ./exploit 
Spawning root shell!
sh-4.2# id
uid=0(root) gid=0(root) groups=0(root),4(adm),10(wheel),190(systemd-journal),1000(centos) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
sh-4.2# exit

Meanwhile, in CrowdSec logs (/var/log/crowdsec.log), we can see that the scenario was detected:

time="27-01-2022 13:03:43" level=info msg="Bucket overflow" bucket_id=snowy-wood capacity=0 cfg=dark-pond file=/etc/crowdsec/scenarios/CVE-2021-4034.yaml name=crowdsecurity/CVE-2021-4034 partition=410597c68bcbeb1fb6a5ac5a7d20c07e47209b18
time="27-01-2022 13:03:43" level=info msg="system_account centos performed 'crowdsecurity/CVE-2021-4034' (1 events over 1.3µs) at 2022-01-27 13:03:43.831469449 +0000 UTC"
time="27-01-2022 13:03:44" level=info msg="(3d5c05376530a2eb49e3e90576f83c5bbztCXDYSUWyHCAhv) alert : crowdsecurity/CVE-2021-4034 by system_account centos"


We can detect the exploit, and now what? The CrowdSec solution cannot block the malevolent user or prevent exploitation, but it can alert you. Fortunately, CrowdSec supports notification plugins. In this case, let’s set up a Slack alerting to be able to react in real-time. 

First of all, let’s adapt our profiles to generate notifications on alerts that are targeting a system user and not an IP, by adding a new profile to the configuration file (/etc/crowdsec/config/profiles.yaml):

name: default_ip_remediation
#only look at events targeting system users, and applies no remediation
name: notif_only
 - Alert.GetScope() == 'system_account'
  - slack_lpe

As the default Slack notification template expects an alert regarding an IP, we can generate a new one “slack_lpe”. To achieve this, let’s simply create a new Slack template in /etc/crowdsec/notifications/slack-lpe.yaml:

# Don't change this
type: slack

name: slack_lpe # this must match with the registered plugin in the profile
log_level: info # Options include: trace, debug, info, warn, error, off

format: |  # This template receives list of models.Alert objects
  {{range . -}}
    {{$alert := . -}}
    {{$src_machine := "" }}
    {{range $alert.Events -}}
      {{$event := . -}}
      {{range $event.Meta -}}
        {{$meta := . -}}
        {{if eq $meta.Key "machine" }} {{$src_machine = $meta.Value}} {{end}}
      {{end -}}
    {{end -}}
    {{$alert.Source.Scope}} {{$alert.Source.Value}} triggered {{$alert.Scenario}} on {{$src_machine}} (`agent {{$alert.MachineID}}`)
  {{end -}}


# group_wait: # duration to wait collecting alerts before sending to this plugin, eg "30s"

# group_threshold: # if alerts exceed this, then the plugin will be sent the message. eg "10"

# max_retry: # number of tries to attempt to send message to plugins in case of error.

# timeout: # duration to wait for response from plugin before considering this attempt a failure. eg "10s"

(Note: for this to work, you will have to generate your own Slack webhook url)

What should happen is:

  • If an attacker exploits the Pwnkit vulnerability, he will trigger the crowdsecurity/CVE-2021-4034 scenario 
  • This scenario will generate an alerting about the system_user that just performed the exploit
  • The alert will be caught by our notif_only profile that will dispatch the alert to the Slack notification plugin

Let’s try exploiting the vulnerability again:

▶ tail -f /var/log/crowdsec.log
time="27-01-2022 13:08:53" level=info msg="system_account centos performed 'crowdsecurity/CVE-2021-4034' (1 events over 1.299µs) at 2022-01-27 13:08:53.098841249 +0000 UTC"
time="27-01-2022 13:08:53" level=info msg="(3d5c05376530a2eb49e3e90576f83c5bbztCXDYSUWyHCAhv) alert : crowdsecurity/CVE-2021-4034 by system_account centos"
time="27-01-2022 13:08:53" level=info msg="found notify signal for slack_lpe config" @module=slack-plugin

The alert is indeed triggered:

And the alert notification pops up on Slack to allow a swift reaction:

Stay safe, happy hunting!

Join our community on Discord to get support and learn more about CrowdSec scenarios.

You may also like

Protect Your Applications with AWS WAF and CrowdSec: Part I

Protect Your Applications with AWS WAF and CrowdSec: Part I

Learn how to configure the AWS WAF Remediation Component to protect applications running behind an ALB that can block both IPs and countries.

Protect Your Serverless Applications with AWS WAF and CrowdSec: Part II

Protect Your Serverless Applications with AWS WAF and CrowdSec: Part II

Learn how to protect your serverless applications hosted behind CloudFront or Application Load Balancer with CrowdSec and the AWS WAF.

Securing A Multi-Server CrowdSec Security Engine Installation With HTTPS

Securing A Multi-Server CrowdSec Security Engine Installation With HTTPS

In part II of this series, you learn about the three different ways to achieve secure TLS communications between your CrowdSec Security Engines in a multi-server setup.