ReiserFS .reiserfs priv Vulnerability
Saturday, April 10, 2010
A vulnerability in the ReiserFS filesystem of the Linux kernel (versions <= 2.6.34-rc3) allows for the unprivileged reading and writing of objects in the .reiserfs_priv path. Leveraging extended attributes and POSIX file-based capabilities, this vulnerability allows for privilege escalation on systems with a ReiserFS filesystem.
The vulnerability was introduced in May 2009 in commit 677c9b2. The commit was intended to simplify the logic around ReiserFS's privroot, a virtual path located at .reiserfs_priv in the root of the fs mount that is used for storing internal filesystem information such as extended attributes. The commit also had the unfortunate side effect of exposing the privroot dentry (even without the expose_privroot mount option enabled), allowing an unprivileged user to read/write the filesystem information stored in .reiserfs_priv.
So, what exactly is the security risk in having an unprivileged user modify the ReiserFS privroot information? Well, the primary use of the .reiserfs_priv path is the storage of extended file attributes. Extended attributes, aka "xattrs", can be used to extend past the limitations of traditional UNIX file attributes (permission bits, atime/ctime/mtime, etc) by allowing the association of additional metadata name-value pairs with a file.
While an unprivileged user forging xattrs doesn't directly result in privilege escalation, we can modify particular types of xattrs to achieve that goal. In particular, we can leverage one common type of extended attribute: POSIX file capabilities. POSIX file capabilities are a useful feature that allow the assignment of capabilities to executables at a finer-grained level than the setuid bit. For example, instead of making the ping binary setuid root, POSIX file capabilities allow us to simply grant it the CAP_NET_RAW capability so that it can use raw sockets for its ICMP echo requests/responses. While many POSIX file capabilities are root-equivalent, they can be quite useful in certain threat models to reduce the attack surface of a system.
However, in this case, we're going to piggyback on the functionality of POSIX file capabilities to escalate privileges. Note that since we're able to write arbitrary xattr data in the privroot, we can thereby assign arbitrary capabilities to any file on the filesystem. For example, we could assign the CAP_SETUID to a binary to allow it to use setuid(2) when it is executed.
Indeed, that's exactly what we do. We dump a simple setuid(0)/setgid(0)/execl("/bin/sh") wrapper binary on the ReiserFS filesystem, determine its object id with a bit of a readdir hack, assign CAP_SETUID/CAP_SETGID capabilities to the object id by writing the appropriate xattrs to .reiserfs_priv, and finally execute the binary for a root shell.
The full exploit is here. Example output:
$ python team-edward.py [+] checking for reiserfs mount with user_xattr mount option [+] checking for private xattrs directory at /.reiserfs_priv/xattrs [+] preparing shell in /tmp [+] capturing pre-shell snapshot of private xattrs directory [+] compiling shell in /tmp [+] setting dummy xattr to get reiserfs object id [+] capturing post-shell snapshot of private xattrs directory [+] found 1 new object ids [+] setting cap_setuid/cap_setgid capabilities on object id 192B.1468 [+] spawning setuid shell... # id uid=0(root) gid=0(root) groups=4(adm), ...