CVE-2013-4547-nginx文件名逻辑漏洞

漏洞原理

这个漏洞其实和代码执行没有太大关系,其主要原因是错误地解析了请求的URI,错误地获取到用户请求的文件名,导致出现权限绕过、代码执行的连带影响。

我们请求1.gif[0x20][0x00].php,这个URI可以匹配上正则\.php$,可以进入这个Location块;但进入后,Nginx却错误地认为请求的文件是1.gif[0x20],就设置其为SCRIPT_FILENAME的值发送给fastcgi。fastcgi根据SCRIPT_FILENAME的值进行解析,最后造成了解析漏洞。

环境搭建

启动漏洞环境:

1
docker-compose up -d

环境启动后,访问http://your-ip:8080/即可看到一个上传页面。

1

漏洞复现过程

这个环境是黑名单验证,我们无法上传php后缀的文件,先创建一个test.png

1
2
GIF98A
<?php phpinfo(); ?>

上传抓包修改,后缀加上一个空格

2

上传成功,成功显示文件路径

3

%00截断解析php文件,访问路径

http://your-ip:8080/uploadfiles/test.pngaaaphp

抓包修改hex,将61 61 61修改为20 00 2e,然后放包

3

回显phpinfo

3

CVE-2017-7529 NGINX越界读取缓存漏洞-nginx整数溢出漏洞

漏洞原理:

在nginx作为反向代理服务器,且开启了缓存时,攻击者可以构造恶意的range域,来获取相应的服务器中的缓存文件头部信息,导致敏感的服务器信息泄露

影响版本:0.5.6-1.13.2

漏洞危害:敏感信息泄露

在header中range的解析过程

image-20220615220120448

ngx_http_range_parse函数中有这样一个循环, 这段代码是要把“-”两边的数字取出分别赋值给startend变量,字符串指针p中即为bytes=后面的内容

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
//部分源码如下
cutoff = NGX_MAX_OFF_T_VALUE / 10;
cutlim = NGX_MAX_OFF_T_VALUE % 10;

for(;;)
{
start=0;
end=0;
suffix=0;
//...
while(*p == ' ') { p++; }

if (*p != '-')
{
if (*p < '0' || *p > '9')
{
return NGX_RANGENOT_SATISFIABLE;
}

while (*p >= '0' && *p <= '9')
{
if (start >= cutoff && (start > cutoff || *p - '0' > cutlim))
{
return NGX_RANGENOT_SATISFIABLE;
}

start = start * 10 + *p++ - '0'; // 更新start
}

while (*p == ' ') { p++; }

if (*p++ != '-')
{
return NGX_RANGENOT_SATISFIABLE;
}

while (*p == ' ') { p++; }

if (*p == ',' || *p == '\0')
{
end = content_length; // 对end做更新
goto found;
}

}else{
suffix = 1;
p++;
}
//...
if (suffix)
{
start = content_length - end; // 第一次byte以“-end”格式传入时,end=0start = content_length
end = content_length - 1; // start > end 不会进入found
}
//...
found:

if (start < end)
{
range = ngx_array_push(&ctx->ranges);
if (range == NULL)
{
return NGX_ERROR;
}

range->start = start;
range->end = end;

size += end - start;

if (ranges-- == 0)
{
return NGX_DECLINED;
}
}

if (*p++ != ',')
{
break;
}
}
//...
if (size > content_length)
{
return NGX_DELINED;
}
//...

在该段代码中存在cutoffcutlim阈值限定了从字符串中读取时不会让startend为负值, 所以这里需要进入suffix = 1的分支,因此使用Range:bytes=-xxx,(-end的格式)即省略初始start值的形式,由此可以绕过*p != '-'的限制,进入suffix=1的分支。

1
2
3
4
5
if (suffix)
{
start = content_length - end;
end = content_length - 1;
}

start等于content_length减去end值,所以如果传入的end比实际长度还要长,就可以使start变为负数。其中content_length为不包含文件头的文件长度。最终end的值会被设定为content_length - 1(因此我们需要构造一个小包)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (start < end) 
{
range = ngx_array_push(&ctx->ranges);
if (range == NULL)
{
return NGX_ERROR;
}

range->start = start;
range->end = end;

size += end - start;
if (ranges-- == 0)
{
return NGX_DECLINED;
}
}

start相当于分片区间的头指针,end相当于分片区间的尾指针。如果此时end值要比文件长度(content_length)数值大的话,就可以将start解析为负值。与Range相关的还有一个size值,它是每段Range相加后的总长度

1
2
3
4
if (size > content_length)
{
return NGX_DELINED;
}

size(即所有range相加的总长度)超过文件长度content_length时,会返回默认的NGX_DELINED

注意到此处有一个退出条件:

1
2
3
4
if (*p++ != ',')
{
break;
}

支持支持range的值为start1-end1,start2-end2……的形式。

因此,可以构造range:bytes=-x,-y。一大一小两个end值,只需要 控制前面一个end值小而后一个end值大,从而实现start值和size值皆为负数,控制start值负到一个合适的位置,那么就能成功读到缓存文件头部了。

环境搭建

启动漏洞环境:

1
docker-compose up -d

访问http://your-ip:8080/,即可查看到Nginx默认页面,这个页面实际上是反向代理的8081端口的内容。

3

漏洞复现过程

调用python3 poc.py http://your-ip:8080/,读取返回结果:

3

Nginx 配置错误导致漏洞

环境搭建

启动漏洞环境:

1
docker-compose up -d

3

运行成功后,Nginx将会监听8080/8081/8082三个端口,分别对应三种漏洞。

CRLF注入漏洞

漏洞原理

CRLF是“回车 + 换行”(\r\n)的简称。在HTTP协议中,HTTP Header与HTTP Body是用两个CRLF分隔的,浏览器就是根据这两个CRLF(使用payload %0a%0d%0a%0d进行测试)来取出HTTP内容并显示出来。所以,一旦我们能够控制HTTP消息头中的字符,注入一些恶意的换行,这样我们就能注入一些会话Cookie([http://www.xx.com%0a%0d%0a%0dSet-cookie:JSPSESSID%3Dxxx)或者HTML代码(http://www.xx.com/?url=%0a%0d%0a%0d](https://www.freebuf.com/articles/web/265135.html?url= )<img src=1 onerror=alert("xss")>),所以CRLF Injection又叫HTTP Response Splitting,简称HRS。

Nginx会将$uri进行解码,导致传入%0a%0d即可引入换行符,造成CRLF注入漏洞。

错误的配置文件示例(原本的目的是为了让http的请求跳转到https上):

Payload: http://your-ip:8080/%0a%0dSet-Cookie:%20a=1

3

也可以利用这个漏洞进行xss

目录穿越漏洞

Nginx在配置别名(Alias)的时候,如果忘记加/,将造成一个目录穿越漏洞。

错误的配置文件示例(原本的目的是为了让用户访问到/home/目录下的文件):

1
2
3
location /files {
alias /home/;
}

Payload:http://your-ip:8081/files../,成功穿越到根目录:

3

add_header被覆盖

Nginx配置文件子块(server、location、if)中的add_header,将会覆盖父块中的add_header添加的HTTP头,造成一些安全隐患。

文件解析漏洞

漏洞描述

该漏洞与nginx、php版本无关,属于用户配置不当造成的解析漏洞。由于nginx.conf的如下配置导致nginx把以’.php’结尾的文件交给fastcgi处理,对于任意文件名,在后面添加/xxx.php(xxx)为任意字符后,即可将文件作为php解析。

环境搭建

启动漏洞环境:

1
docker-compose up -d

环境启动后,访问http://your-ip/即可看到一个上传页面。

漏洞复现过程

上传一个test.png

3

3