# CVE-2013-4547 Nginx解析漏洞深入利用及分析

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2014-05-19T03:12:00Z
Canonical: https://wepostx.com/topics/470

> 乌云历史资料归档
>
> **原始作者：** 百度安全中心
> **原始编号：** superkieran-wooyundrops:253
> **原始发布时间：** 2014-05-19 11:12
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

## 0x00 背景

Nginx历史上曾出现过多次解析漏洞，比如80sec发现的解析漏洞，以及后缀名后直接添加%00截断导致代码执行的解析漏洞。
但是在2013年底，nginx再次爆出漏洞（CVE-2013-4547），此漏洞可导致目录跨越及代码执行，其影响版本为：nginx 0.8.41 – 1.5.6，范围较广。
为了更深入的了解漏洞产生的原因，笔者根据官方补丁（[http://nginx.org/download/patch.2013.space.txt](http://nginx.org/download/patch.2013.space.txt)），对此漏洞进行了进一步的分析，

## 0x01 漏洞朔源

1.从官方补丁可以看出nginx在ngx_http_parse_request_line函数处做了代码patch，下载nginx源代码，定位其补丁文件为ngx_http_parse.c，函数ngx_http_parse_request_line中，分别位于代码段：
由此可定位本次漏洞需要分析的点，启用gdb调试，将break点设置为ngx_http_parse_request_line，
并且watch变量state和p，因为此函数为状态机，state为状态值，p为指针所指文志，这将是漏洞触发的关键点。
调试过程中需要跟踪nginx的worker子进程，所以需要设置setfollow-fork-mode child，并且在相应的地方设置断点，

![原文图片](/media/2016/06/561518828a9db0bee9ccce42f1f67e01)

图-1 跟进子进程
2.分别发送正常和攻击语句进行测试：
正常语句：

```text
http://127.0.0.1/a.jpg
```
攻击语句：

```text
http://127.0.0.1/a.jpg（非编码空格）\0.php
```
使用正常语句一直s或n跟踪，会发现在对url的解析过程中，当路径中存在’.’或url存在’\0’会有如下处理：

```text
#!cpp case sw_check_uri: …… case '.': r->complex_uri = 1; //此作为flag会判断使用ngx_http_parse_complex_uri方法，对路径修复 state = sw_uri; break; casesw_check_uri: …… case '\0': //当遇到\0是，将会判断为非法字符 return NGX_HTTP_PARSE_INVALID_REQUEST;
```
但是在检查uri中有空格则会进入到sw_check_uri_http_09的逻辑中，那么当我们发送攻击代码的时候，执行流程将如下：

![原文图片](/media/2016/06/260fd52171e52b73bd3d192ccd1bd66b)

图-2 \0未触发异常
再回到sw_check_uri状态，此时后面的字符串为.php，而“.”将被为是uri的扩展名的分隔符

![原文图片](/media/2016/06/56df6d62031509681f8fea6f6e884dfa)

图-3 取后缀名错误
最终导致nginx认为此次请求的后缀名为php，通过配置，会传给fastcgi进行处理，而fastcgi在查找文件的时候被\0截断，最终取到”a.jpg(非编码空格)”文件（注：Linux下php-fpm默认限制的后缀名为php，如未取消限制，访问将出现access denied。测试想要查看执行结果，需修改php-fpm.conf中的security.limit_extensions为空，即允许任意后缀名文件作为php解析。）
跨越

```text
location /protected / {deny all;}
```
的规则的原理与此类似，均为状态机中判断出现混乱，从导致而可以跨越到protected目录中，访问默认不可访问到的文件。
由此可知，常规利用中如果想触发代码执行，条件为可上传带空格的文件到服务器，并且服务器存储的时候也需要保留空格，而大多数情况下，web应用在处理上传文件时，都会将文件重命名，通过应用自身添加后缀，或者对后缀名去掉特殊字符后，做类型判断。
以上因素都导致此漏洞被认为是鸡肋漏洞，难以利用，而被人们所忽略。

## 0x02 windows下的RCE

此问题在windows的攻击场景中，则从小汽车变身为变形金刚。
首先，我们了解一下windows读取文件时的特点，即文件系统api创建文件名或查找文件名时，默认会去掉文件名后的空格，再执行操作，参见示例代码，目录下放置a.txt不带空格:

```text
#!cpp #include "stdafx.h" #include<windows.h> int _tmain(int argc, _TCHAR* argv[]) { HANDLE hFile =CreateFile(L"a.txt ",GENERIC_WRITE|GENERIC_READ, 0, //注意a.txt后有一个空格 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”不带空格
此时的攻击过程为：

```text
1.上传任意文件（不需要带空格文件）， 2.http://127.0.0.1/a.jpg(非编码空格)\0.php
```

![原文图片](/media/2016/06/92df4b0df75b2acf6c0e44c8dbacb645)

图-4文件a.jpg

![原文图片](/media/2016/06/d857aaf7a3b31e2c929e92642cdd4118)

图-5漏洞利用
成功将a.jpg文件当作php代码执行，达到了攻击成功的目的。
通过windows的此特性，使CVE-2013-4547在windows+nginx的环境中的危害无限扩大，即在windows下，只要普通用户能上传文件，则可利用本次漏洞，导致代码执行，并进一步入侵服务器。
并且在普通站长中使用windows做为操作系统的数量甚广，CVE-2013-4547在windows的场景下将进行华丽的变身。
from:[http://sec.baidu.com/index.php?research/detail/id/19](http://sec.baidu.com/index.php?research/detail/id/19)

## Replies
