Recently I started using Keybase which is a Slack like application but provides end-to-end encryption. Version 2.8.0.20181017144746.3efc4cbf3c is vulnerable to a privilege escalation vulnerability allowing a low privileged user to execute arbitrary commands as root.

After executing the application using a low privileged account I noticed a process named keybase-redirector running as root. I was interested and wanted to understand how this worked. After checking the file permissions I found that the keybase-redirector was setuid root. I enjoy the challenge of finding vulnerabilities in privileged binaries so I started my research.

One of the first techniques I use when attacking setuid binaries is to test for PATH injections. The PATH environment variable is a colon separated list of directories that is searched when executing a command by name. As a test I reset the PATH environment variable to a unique value while executing keybase-redirector.  Using the env command  inline ensures that the PATH is only set for the execution and the current value of PATH is unmodified.

[user1@localhost ~]$ env PATH=/foobar /usr/bin/keybase-redirector /keybase
Mount error, exiting cleanly: fusermount: exec: “fusermount”: executable file not found in $PATH

The descriptive error message immediately caught my attention. To confirm the potential vulnerability I executed the strace(1) utility. strace traces system calls and has a variety of options. The common options that I use are -f(follow forks), -s (maximum string size to print) and -u [username]. strace generates verbose output so this is where the unique PATH string becomes useful. We can quickly search the output for that string to find potential injection points. When tracing a setuid binary, strace must be executed from root because privileges are dropped. In some cases the error message may not provide any clues. Regardless of the output I always run strace to verify. As you can see in the below output, the newfstatat() call is checking if /foobar/fusermount exists.

[root@localhost ~]# env PATH=/foobar /usr/bin/strace -u user1 -f /usr/bin/keybase-redirector /keybase 2>&1|grep foobar
[pid 4890] newfstatat(AT_FDCWD, “/foobar/fusermount“, 0xc420070858, 0) = -1 ENOENT (No such file or directory)

Now that it appears the program trusts the value of PATH we can try to exploit it. I crafted a fusermount binary to create the /w00t file. View the original PoC in the Hackerone report 426944. Since then I created a new PoC to get an interactive root shell. Updated PoC can be found at my Github repo CVE-2018-18629.sh

PoC screenshot for CentOS 7.4.1708.
keybase-woot

Summary

Setuid programs should reset the PATH environment variable prior to executing any external binaries. Fully qualified paths can also be used. The response from Keybase was amazing and I really enjoyed the partnership. @maxtaco committed the fix to the master branch within one hour of receiving the report! I appreciate their transparency and technical write-up in the advisory.

References