# 前言

继续填坑做复现,不知道犯懒和强迫症是怎么同时出现在我身上的,每次都是因为强迫症万分痛苦的填坑。前面复现了常见的 IIS 和 Apache 的漏洞,这篇 blog 简单的记录一下 Nginx 相关的漏洞。

# Nginx

还是很有必要先介绍一下 Nginx,Nginx 是一个高性能的开源 Web 服务器软件,也可以用作反向代理服务器、负载均衡和 Http 缓存。因为 Nginx 采用时间驱动和异步非阻塞的处理模型,它能处理大量并发连接和高负载。在 Netcraft 最新的服务器调查 blog 里,其市场占比非常可观:2024 年 2 月 Web 服务器调查 | 网艺 (netcraft.com)

# 漏洞复现

# Nginx 配置错误导致漏洞

这类漏洞与 Nginx 版本无关,只与 Nginx 的配置有关

# CRLF 注入漏洞

# 漏洞成因

CRLF 是 "回车 + 换行" 的简称,在 http 协议中 HTTP header 域 HTTP body 是用两个 CRLF 分隔的。浏览器会通过这两个 CRFL 来区别 header 和 body,首先来看下面两个场景:

  1. 当访问 http://blog.xcu.icu/ 会自动跳转到 https://blog.xcu.icu/
  2. 当访问 http://example.com 会自动跳转到 http://www.example.com

当跳转的时候我们需要保证用户访问的页面不会发生变化,所以就需要从 Nginx 中获取用户请求的文件路径,参考文档模块 ngx_http_rewrite_module (nginx.org) 对应的中文文档 HttpRewrite 模块 | Nginx 中文官方文档 (gitbooks.io)

Nginx 提供了三个变量

  1. $uri 变量包含请求中的 URI,不包括参数(就是?后面的部分)
  2. $document_uri 变量包含请求的 URI,与上面的 $uri 不同的是它包含所有的查询参数
  3. $requesr_uri 变量包含的是客户端发送的原始请求 URI,包括所有的查询参数(这里的原始是指解码之前的)

所以如果重定向使用的是前两个比如

location / {
    return 302 https://$host$uri;
}

这种写法会导致请求中的换行符也被包含在内,导致修改返回包中的数据

# 环境搭建

修改 /etc/nginx/conf.d/default.conf 配置文件

server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.html;
        return 302 http://$host:$server_port$uri;
    }
    
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

这里我使用 docker 搭建环境,Dockerfile 如下

FROM nginx:latest
COPY files /tmp/files/
COPY conf /tmp/conf/
 
RUN mv /tmp/files/start.sh / && \
    chmod +x  /start.sh && \
    cp /tmp/conf/change.conf /etc/nginx/conf.d/default.conf && \
    rm -rf /tmp/files && \
    rm -rf /tmp/conf
CMD /start.sh
EXPOSE 80

# 漏洞复现

curl -I http://192.168.246.136/%0d%0aSet-test:%20aaabbb

image-20240318175652067

或者多加一个 CRLF 导致反射型 XSS

%0D%0A%0D%0A%3Cimg%20src=1%20test=alert(/xss/)%3E

image-20240318180036910

# 修复建议

在获取用户的请求路径时,配置文件内出现的配置应当是 $request_uri 如下

location / {
    return 302 https://$host$request_uri;
}

# 目录穿越漏洞

# 漏洞成因

同样是一个配置导致的漏洞,如果当管理员在映射本地文件系统中的某个目录的时候少写了一个 / 如下

location /files {
        alias /home/;
    }

这里就是将本地 test 文件映射到 files 上,在 files 后面没有 / 就会导致目录穿越,

# 环境搭建

修改配置文件如下

server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.html;
    }
    location /files {
        alias /home/;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

dockerfile 文件如下

FROM nginx:latest
COPY files /tmp/files/
COPY conf /tmp/conf/
 
RUN mv /tmp/files/flag.sh / && \
    mv /tmp/files/start.sh / && \
    chmod +x /flag.sh /start.sh && \
    cp /tmp/conf/change.conf /etc/nginx/conf.d/default.conf && \
    rm -rf /tmp/files && \
    rm -rf /tmp/conf
CMD /start.sh
EXPOSE 80
ENV FLAG flag{test123}

这里我加上了 flag 字段,读取这个文件即可

# 漏洞复现

payload: /files../flag

image-20240318184346342

# 漏洞建议

修复就针对配置文件

location /files/ {
        alias /home/;
    }

这里将 files 后的 / 加上即可

# Nginx 解析漏洞

# 漏洞成因

当服务器配置有下面的内容时

location ~ \.php$ {}

这个配置用于处理 php 后缀结尾的请求,当收到 php 结尾的请求后会将请求传递给 php 解释器处理。而 php 解析器默认有配置

cgi.fix_pathinfo = 1

开启的情况下会对文件路经做一个修复。比如是访问一个 /aaa.png/bbb 如果这里没有找到 bbb 这个文件会删除 bbb 这个路径,如果解析规则没做限制会尝试解析 aaaa.png

# 环境搭建

nginx 对应的配置文件

server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.php;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
    
    location ~ \.php$ {
		fastcgi_index index.php;
		include fastcgi_params;
		fastcgi_param  REDIRECT_STATUS    200;
		fastcgi_param  SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
		fastcgi_param  DOCUMENT_ROOT /var/www/html;
		fastcgi_pass php:9000;
	}
}

php 对应的配置文件

[www]
security.limit_extensions =

上传文件的代码这里不再展示

# 漏洞复现

尝试上传一个 info.png 文件

image-20240318214244013

然后去尝试访问这个 png 文件

image-20240318214235391

后面加上.php

image-20240318210706181

# 修复建议

  1. 将 php.ini 文件中的 cgi.fix_pathinfo 的值设置为 0
  2. php-fpm.conf 中的 security.limit_extensions 后面的值设置为.php

# Nginx 程序漏洞

下面的漏洞就已经是 Nginx 本身的问题了,我们能做的修复就是更新版本

# CVE-2013-4547

# 影响版本

Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7

# 漏洞成因

首先要大概了解 Nginx 中 php 是如何被解析的

image-20240319180718472

还是这张图,当浏览器发出静态请求在 nginx 上直接就处理后返回给浏览器,但是当我们尝试访问一个动态资源,Nginx 就会根据请求的文件去选择解释器,像上面的请求就会去尝试使用 php 解析器。Nginx 是如何知道将什么样的文件当作 PHP 文件处理?是在 nginx.conf 配置文件中的

location ~ \.php$ {
           root           html;
           include        fastcgi_params;
           fastcgi_pass   php:9000;
           fastcgi_index  index.php;
           fastcgi_param  SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
           fastcgi_param  DOCUMENT_ROOT /var/www/html;
        }

\.php$ 代表了以 .php 结尾的文件都按照花括号中的内容执行。问题同样也出现在正则这里,当我们尝试请求 info.png[0x20][0x00].php 时会匹配到这个正则交由 php 解析器处理,但是因为 0x00 是截断所以 Nginx 会认为请求的文件是 info.png[0x20] ,如果这里 php 服务器上没有指定 php 扩展名就会导致 info.png[0x20] 被解析

# 环境搭建

# Nginx 部分

配置文件如下

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        root   html;
        index  index.php;
        charset utf-8;
        location ~ \.php$ {
           root           html;
           include        fastcgi_params;
           fastcgi_pass   php:9000;
           fastcgi_index  index.php;
           fastcgi_param  SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
           fastcgi_param  DOCUMENT_ROOT /var/www/html;
        }
    }
}
# php 部分
[www]
security.limit_extensions = 
php_admin_flag[cgi.fix_pathinfo] = off

# 漏洞复现

尝试上传一个文件 info.png[0x20]

然后访问如下

image-20240319180330569