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.
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
- Keybase advisory: Local Privilege Escalation on Linux via keybase-redirector (KB002).
- Hackerone Report: Linux privilege escalation via trusted $PATH in keybase-redirector.
- BleepingComputer article: Keybase Pays $5,000 Bounties for Privilege Escalation Bugs in Linux and macOS Apps.