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 结语
因为这是通用的规则,在拦截上会比较严格,安装完成后还需要进一步的调整才可以用在生产环境中。
如果可以,建议先不打开拦截模式,收集一段时间的日志,根据实际情况编写好规则后再上线使用。