IBM MQ for Linux and UNIX systems is vulnerable to a privilege escalation attack by forcing a setuid root binary to load a malicious library. A local attacker with access to the mqm account can execute arbitrary code as root. In October 2018 IBM published an advisory along with patches for several versions.
The goal of this post is to show how the RPATH/RUNPATH value could potentially be leveraged for privilege escalation. When specified at compile time this path is embedded in the binary and is the first path searched when searching for a library if the dependent library specified does contain a slash. Details on how this works can be found in the ld.so man page.
As with most file path type vulnerabilities, if you control the path, you may control the application in some way. In this case the mqm user is the owner of the directories listed in the RUNPATH.
List setuid root applications.
[mqm@localhost]$ find /opt/mqm -perm -4000 -user root|xargs ls -l
-r-sr-x---. 1 root mqm 13384 Jul 9 07:09 /opt/mqm/bin/security/amqoamax
-r-sr-x---. 1 root mqm 13704 Jul 9 07:09 /opt/mqm/bin/security/amqoampx
Use readelf to read the dynamic section to extract the RPATH/RUNPATH.
[mqm@localhost ~]$ readelf -d /opt/mqm/bin/security/amqoamax |grep -e RPATH -e RUNPATH
0x000000000000001d (RUNPATH) Library runpath: [/opt/mqm/lib64:/opt/mqm/gskit8/lib64:/
Using my favorite utility strace, we can see the open() calls for libm.so.6 fails with ENOENT under /opt/mqm/lib64 and /opt/mqm/gskit8. We’re using libm.so.6 for this PoC but other libraries can be used. The dependency is ultimately resolved at /usr/lib64/libm.so.6. This gets interesting because the mqm user owns the directories under /opt/mqm.
[mqm@localhost ~]$ strace -f /opt/mqm/bin/security/amqoamax 2>&1|grep libm.so
open("/opt/mqm/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/opt/mqm/gskit8/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3