0x01 前言

我目前使用naxsi作为我网站的waf,但是naxsi目前还没支持HTTP/2。虽然GitHub项目中已经有相关的分支,但回顾这项目的效率,估计还得等一段时间。

在应用waf之前我是启用了HTTP/2的,不过因为naxsi的缘故我有关闭了。在学习参透naxsi后开始学习ModSecurity这一款开源的waf,计划在2个月内将naxsi替换为ModSecurity并启用一些新技术。

今天先记录ModSecurity的安装过程。

-更新:2017-09-21

因为该文章中的ModSecurity使用了v2.9,与新版的nginx不兼容。请点击以下链接查看ModSecurity v3与nginx编译安装的步骤:

0x02 准备

我依旧使用openresty作为nginx的替代品,可以通过以下地址下载最新版:

然后是ModSecurity for Nginx,打开以下地址,在页面底部即可找到nginx的版本:

有了基础环境,还需要各种各样的规则。因为这是开源的,所以有很多开源的规则,当然也有收费的,打开以下页面即可找到两种不同类型的规则:

我一个小站,只好选用OWASP ModSecurity Core Rule Set (CRS) Version 3这个开源的规则。

0x03 安装

先使用root用户登入系统并下载相关文件:

#新建文件夹
[root@modsecurity ~]# mkdir -p codex/nginx/ codex/modsecurity/

#下载openresty
[root@modsecurity ~]# wget https://openresty.org/download/openresty-1.11.2.5.tar.gz -O codex/nginx/openresty-1.11.2.5.tar.gz

#下载ModSecurity
[root@modsecurity ~]# wget https://www.modsecurity.org/tarball/2.9.2/modsecurity-2.9.2.tar.gz -O codex/modsecurity/modsecurity-2.9.2.tar.gz 

#进入文件夹
[root@modsecurity ~]# cd codex/

#下载OWASP ModSecurity CRS
[root@modsecurity codex]# git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git
Cloning into 'owasp-modsecurity-crs'...
remote: Counting objects: 5025, done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 5025 (delta 13), reused 19 (delta 5), pack-reused 4995
Receiving objects: 100% (5025/5025), 1.84 MiB | 979.00 KiB/s, done.
Resolving deltas: 100% (3446/3446), done.

先进入OWASP ModSecurity CRS目录将crs-setup.conf.example复制一份:

#进入相关文件夹
[root@modsecurity ~]# cd /root/codex/owasp-modsecurity-crs/

#复制文件
[root@modsecurity owasp-modsecurity-crs]# cp crs-setup.conf.example crs-setup.conf

在rules文件夹中也有两份配置文件,我这里也将其复制一份,设为启用:

#进入相关文件夹
[root@modsecurity owasp-modsecurity-crs]# cd rules

#复制文件
[root@modsecurity rules]# cp REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
[root@modsecurity rules]# cp RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

进入ModSecurity文件夹并将其解压:

#进入相关文件夹
[root@modsecurity codex]# cd /root/codex/modsecurity/

#解压文件
[root@modsecurity modsecurity]# tar zxvf modsecurity-2.9.2.tar.gz

因为nginx不同于apache的动态加载模式,所以modsecurity需要以standalone module的形式存在。需要先将其编译,然后再将其通过nginx的编译整合在一起。

这里先进入modsecurity文件夹,并编译:

#进入相关文件夹
[root@modsecurity modsecurity]# cd /root/codex/modsecurity/modsecurity-2.9.2/

在进行编译之前还需要修改两处内容,使用以下命令进行修改:

sed -i '/AC_PROG_CC/a\AM_PROG_CC_C_O' configure.ac
sed -i '1 i\AUTOMAKE_OPTIONS = subdir-objects' Makefile.am

如果不修改,则使用最新automake编译的时候会出错。然后进行编译:

#autogen
./autogen.sh

#configure
./configure --enable-standalone-module --disable-mlogc

#编译
make

这里不需要安装。

完成之后进入nginx的文件夹并将其解压:

#进入文件夹
[root@modsecurity nginx]# cd /root/codex/nginx/

#解压
[root@modsecurity nginx]# tar zxvf openresty-1.11.2.5.tar.gz

然后进入openresty文件夹并编译安装,在这里我使用以下文章里的configure参数:

#进入相关文件夹
[root@modsecurity nginx]# cd openresty-1.11.2.5/

#configure
./configure --prefix=/usr/local/nginx --sbin-path=/usr/sbin/nginx --conf-path=/usr/local/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --lock-path=/var/lock/nginx.lock --with-luajit --with-http_gunzip_module --with-pcre --with-pcre-jit --with-http_perl_module --with-ld-opt="-Wl,-E" --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-select_module --with-poll_module --with-file-aio --with-http_degradation_module --with-libatomic --http-client-body-temp-path=/var/tmp/nginx/client_body --http-proxy-temp-path=/var/tmp/nginx/proxy --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi --http-scgi-temp-path=/var/tmp/nginx/scgi --add-module=/root/codex/modsecurity/modsecurity-2.9.2/nginx/modsecurity

#编译
make

#安装
make install

需要注意在最后的一个函数,请按你的实际情况进行修改:

--add-module=/root/codex/modsecurity/modsecurity-2.9.2/nginx/modsecurity

安装完成后通过以下命令查看nginx信息:

[root@modsecurity ~]# nginx -V
nginx version: openresty/1.11.2.5
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) 
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3.0 --add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.05 --add-module=../ngx_coolkit-0.2rc3 --add-module=../set-misc-nginx-module-0.31 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.06 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.10 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.32 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.18 --add-module=../redis2-nginx-module-0.14 --add-module=../redis-nginx-module-0.3.7 --add-module=../rds-json-nginx-module-0.14 --add-module=../rds-csv-nginx-module-0.07 --with-ld-opt='-Wl,-rpath,/usr/local/nginx/luajit/lib -Wl,-E' --sbin-path=/usr/sbin/nginx --conf-path=/usr/local/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --lock-path=/var/lock/nginx.lock --with-http_gunzip_module --with-pcre --with-pcre-jit --with-http_perl_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-select_module --with-poll_module --with-file-aio --with-http_degradation_module --with-libatomic --http-client-body-temp-path=/var/tmp/nginx/client_body --http-proxy-temp-path=/var/tmp/nginx/proxy --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi --http-scgi-temp-path=/var/tmp/nginx/scgi --add-module=/root/codex/modsecurity/modsecurity-2.9.2/nginx/modsecurity

至此安装已完毕。

0x04 配置

modsecurity灵活性很高,你可以将ModSecurityEnabled这个指令放置在server或location块,以此控制modsecurity的启用与否。

以下使用nginx默认的配置文件nginx.conf进行修改,首先在文件顶部添加以下内容:

load_module /usr/local/nginx/nginx/modules/ngx_http_modsecurity_module.so;

让nginx加载动态模块,这样才能识别下方ModSecurity的配置内容。

然后将以下两行内容放置在location块中:

ModSecurityEnabled on;
ModSecurityConfig modsec_includes.conf;

到这里nginx配置文件的修改就完成了。然后将modsecurity.conf的配置文件复制一份到nginx目录下:

[root@modsecurity nginx]# cp /root/codex/modsecurity/modsecurity-2.9.2/modsecurity.conf-recommended ./modsecurity.conf

然后在nginx.conf同级目录下新建一个名为modsec_includes.conf的文件并填入owasp modsecurity crs配置文件与modsecurity.conf的路径:

[root@modsecurity nginx]# cat modsec_includes.conf 
include /usr/local/nginx/modsecurity.conf
include /root/codex/owasp-modsecurity-crs/crs-setup.conf
include /root/codex/owasp-modsecurity-crs/rules/*.conf

至此,所有配置均已完成。

如果你是使用我的configure参数,那么测试nginx配置文件的时候会出现一个错误:

[root@modsecurity ~]# nginx -t
nginx: the configuration file /usr/local/nginx/nginx.conf syntax is ok
nginx: [emerg] mkdir() "/var/tmp/nginx/client_body" failed (2: No such file or directory)
nginx: configuration file /usr/local/nginx/nginx.conf test failed

这时候只需要建立一个文件夹即可:

#建立文件夹
[root@modsecurity ~]# mkdir /var/tmp/nginx

#测试配置文件
[root@modsecurity ~]# nginx -t
nginx: the configuration file /usr/local/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/nginx.conf test is successful

然后启动

[root@modsecurity ~]# nginx

0x05 测试与拦截

成功启动nginx后即可展开测试,先在终端中使用tail查看日志:

[root@modsecurity ~]# tail -n 1 -f /var/log/nginx/error.log 
2017/09/05 15:56:38 [notice] 3732#0: ModSecurity: StatusEngine call successfully sent. For more information visit: http://status.modsecurity.org/

然后在浏览器打开以下地址:

http://[your ip or hostname]/?../../passwd

例如:

再回到终端,即可看到相关记录:

2017/09/05 16:02:01 [error] 3734#0: [client 10.1.1.16] ModSecurity: Warning. Pattern match "(?i)(?:\\x5c|(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\\/))(?:%(?:(?:f(?:(?:c%80|8)%8)?0%8 ..." at REQUEST_URI_RAW. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "50"] [id "930100"] [rev "3"] [msg "Path Traversal Attack (/../)"] [data "Matched Data: /?../ found within REQUEST_URI_RAW: /?../../passwd"] [severity "CRITICAL"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "7"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"] [hostname ""] [uri "/"] [unique_id "AcAnAyAcAc5cA4AcAcAcAcAW"]
2017/09/05 16:02:01 [error] 3734#0: [client 10.1.1.16] ModSecurity: Warning. Matched phrase "../" at REQUEST_URI. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "77"] [id "930110"] [rev "1"] [msg "Path Traversal Attack (/../)"] [data "Matched Data: ../ found within REQUEST_URI: /?../../passwd"] [severity "CRITICAL"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "7"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"] [hostname ""] [uri "/"] [unique_id "AcAnAyAcAc5cA4AcAcAcAcAW"]
2017/09/05 16:02:01 [error] 3734#0: [client 10.1.1.16] ModSecurity: Warning. Matched phrase "../" at REQUEST_URI. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "77"] [id "930110"] [rev "1"] [msg "Path Traversal Attack (/../)"] [data "Matched Data: ../ found within REQUEST_URI: /?../../passwd"] [severity "CRITICAL"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "7"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"] [hostname ""] [uri "/"] [unique_id "AcAnAyAcAc5cA4AcAcAcAcAW"]
2017/09/05 16:02:01 [error] 3734#0: [client 10.1.1.16] ModSecurity: Warning. Pattern match "^[\\d.:]+$" at REQUEST_HEADERS:Host. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "810"] [id "920350"] [rev "2"] [msg "Host header is a numeric IP address"] [data "10.1.1.113"] [severity "WARNING"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "9"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname ""] [uri "/"] [unique_id "AcAnAyAcAc5cA4AcAcAcAcAW"]

但目前只有记录日志,并没有实施拦截。如果想实施拦截动作,则需求修改modsecurity.conf与crs-setup.conf这两个配置文件:

#打开modsecurity.conf并编辑
[root@modsecurity ~]# vim /usr/local/nginx/modsecurity.conf 

#修改SecRuleEngine
SecRuleEngine On

#打开crs-setup.conf 
[root@modsecurity ~]# vim /root/codex/owasp-modsecurity-crs/crs-setup.conf

#注释以下内容,95和96行
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"

#取消以下内容的注释,115和116行
SecDefaultAction "phase:1,log,auditlog,deny,status:403"
SecDefaultAction "phase:2,log,auditlog,deny,status:403"

完成后重新加在nginx并再次打开日志监控终端:

[root@modsecurity ~]# nginx -s reload

然后刷新一下页面,会发现恶意访问已经被拦截了:

日志也有相关记录,已经返还403状态码:

2017/09/05 16:12:00 [error] 3952#0: [client 10.1.1.16] ModSecurity: Access denied with code 403 (phase 2). Pattern match "(?i)(?:\\x5c|(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\\/))(?:%(?:(?:f(?:(?:c%80|8)%8)?0%8 ..." at REQUEST_URI_RAW. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "50"] [id "930100"] [rev "3"] [msg "Path Traversal Attack (/../)"] [data "Matched Data: /?../ found within REQUEST_URI_RAW: /?../../passwd"] [severity "CRITICAL"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "7"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL"] [hostname "modsecurity"] [uri "/"] [unique_id "AcAtXcAcATAiZnAcAcJcKc6c"]

0x06 结语

因为这是通用的规则,在拦截上会比较严格,安装完成后还需要进一步的调整才可以用在生产环境中。

如果可以,建议先不打开拦截模式,收集一段时间的日志,根据实际情况编写好规则后再上线使用。