0x01 Background

Nginx上一些偏门的漏洞,大多数是因为运维大哥的“粗心”配置导致的,一起来看看自己,是不是曾当过这个“粗心”的运维大哥

0x02 CRLF

OWASP - CRLF 介绍 (https://www.owasp.org/index.php/CRLF_Injection)
The term CRLF refers to Carriage Return (ASCII 13, \r) Line Feed (ASCII 10, \n). They're used to note the termination of a line, however, dealt with differently in today’s popular Operating Systems. For example: in Windows both a CR and LF are required to note the end of a line, whereas in Linux/UNIX a LF is only required. In the HTTP protocol, the CR-LF sequence is always used to terminate a line.
A CRLF Injection attack occurs when a user manages to submit a CRLF into an application. This is most commonly done by modifying an HTTP parameter or URL.

HTTP Splitting

在Nginx配置中,CRLF常出现在HTTP头中不验证用户输入的场合

  • 敏感变量
    • add_header
    • proxy_set_header

如果在上述一些类似设置header头的变量中存在用户可控的数据,那就要注意是否过滤严谨,不然就会造成CRLF注入
每次调整正则配置,如果都要nginx -s reload后进行测试的话,难免会比较浪费时间,由于nginx是基于PCRE,所以可以用grep -P来帮助我们验证自己的正则表达式。
方法如下:

[root@0akarma ~]# echo 'a.jpg' | grep -P '((?<jpg>[^.]*)\.jpg)?$'
a.jpg

然后我们接着来看下面这个vuln配置

location ~ /static/((?<jpg>[^.]*)\.jpg)?$ {
    add_header X-Action $jpg;
    return 200 "OK";
}

-w950
改成这样就可以解决这个问题了

location ~ /static/((?<action>[^.\s]*)\.json)?$ {
            add_header X-Action $action;
            return 200 "OK";
        }

在讲另外的变量之前先讲讲下面三个比较容易搞错的变量

  • $request_uri:包含请求参数的原始URI,并不进行URL解码,如/admin/login.php?username=admin&password=admin
  • $uri:不包含请求参数的当前URI,如/static/style.css
  • \$document_uri:跟上面的$uri一样

所以试想一下,下面这三个变量都用的是$uri或者$document_uri会发生什么~

  • proxy_pass
  • return
  • rewrite
location /static {
    return 302 http://$host$uri;
}

Oh ***
-w977

Header Redefinition

Nginx里面有许多地方可以设置header,如serverlocation

There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.

但是如果,他又有一个子级可覆盖父级的特点,所以,如果存在下面这种配置

server {
  listen 80;
  add_header X-Frame-Options "DENY" always;
  location / {
      return 200 "index";
  }

  location /static {
    add_header Pragma "no-cache" always;
    return 200 "static dir";
  }
}

响应头就会是这样
```nginx
HTTP/1.1 200 OK
Server: nginx/1.14.0
Date: Wed, 24 Apr 2019 14:46:10 GMT
Content-Type: application/octet-stream
Content-Length: 5
Connection: close
X-Frame-Options: DENY

index