Requirements:
- Modsecurity library which is /usr/local in my environment
- modsecurity 3 connector for nginx which is /etc/nginx/modsec in my envionment
- 1 line patches to /opt/zimbra/nginx (web and main). load module the above connector and include a modsecurity .conf file
The more I use this, the more I am convinced this is a valuable and essential tool that has a lot of application with Zimbra. This morning, I checked my blacklist24hr ipset and saw that it stopped 80+ active ip addresses in a little over 10 mins. I have 1 specific zimbra rule in place but the complete OWASP_CRS at paranoia 1 (least likely to cause false positives) and 100% sampling meaning every request is being looked at. All that is configurable. It is also checking for other active attacks including bots, web shells, cross scripting, etc, etc. I have all these rules enabled
Code: Select all
crawlers-user-agents.data REQUEST-901-INITIALIZATION.conf REQUEST-942-APPLICATION-ATTACK-SQLI.conf restricted-files.data
iis-errors.data REQUEST-905-COMMON-EXCEPTIONS.conf REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf restricted-upload.data
java-classes.data REQUEST-911-METHOD-ENFORCEMENT.conf REQUEST-944-APPLICATION-ATTACK-JAVA.conf scanners-headers.data
java-code-leakages.data REQUEST-913-SCANNER-DETECTION.conf REQUEST-949-BLOCKING-EVALUATION.conf scanners-urls.data
java-errors.data REQUEST-920-PROTOCOL-ENFORCEMENT.conf RESPONSE-950-DATA-LEAKAGES.conf scanners-user-agents.data
lfi-os-files.data REQUEST-921-PROTOCOL-ATTACK.conf RESPONSE-951-DATA-LEAKAGES-SQL.conf scripting-user-agents.data
php-config-directives.data REQUEST-922-MULTIPART-ATTACK.conf RESPONSE-952-DATA-LEAKAGES-JAVA.conf sql-errors.data
php-errors.data REQUEST-930-APPLICATION-ATTACK-LFI.conf RESPONSE-953-DATA-LEAKAGES-PHP.conf ssrf.data
php-errors-pl2.data REQUEST-931-APPLICATION-ATTACK-RFI.conf RESPONSE-954-DATA-LEAKAGES-IIS.conf unix-shell.data
php-function-names-933150.data REQUEST-932-APPLICATION-ATTACK-RCE.conf RESPONSE-955-WEB-SHELLS.conf web-shells-php.data
php-function-names-933151.data REQUEST-933-APPLICATION-ATTACK-PHP.conf RESPONSE-959-BLOCKING-EVALUATION.conf windows-powershell-commands.data
php-variables.data REQUEST-934-APPLICATION-ATTACK-GENERIC.conf RESPONSE-980-CORRELATION.conf
REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-941-APPLICATION-ATTACK-XSS.conf RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example
From my perspective, it feels no different with the rules on/off but no performance testing is being done at this point during the evaluation. I am convinced we can disable almost all the rules for our users and large sites can move into this gradually with sampling to make sure performance isn't impacted. There is also this from trustwave.
Ref:
https://www.trustwave.com/en-us/resourc ... endations/
The logging and debugging levels are really helpful to see what lurks in some of those innocent looking requests we often see in our logs..
I am almost convinced at this point to do this as a zimbra plugin for modsecurity vs publishing rules only.
My only and first working rule is the following which is an interesting example because it extends modsecurity 3 with the ability to execute commands. This rule will put bots into a 24 hour timeout if they come at us with an ip address vs using our FQDN on port 443. It is accomplished with the following rule which may not be optimal but appears to work.
Code: Select all
SecRule REQUEST_HEADERS:Host "@rx ^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" \
"id:950000,log, pass, t:none, capture, setvar:'tx.host_was_ip=1', chain"
SecRule REMOTE_ADDR "^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" \
"capture,nolog,setvar:tx.addr=%{tx.1},setvar:tx.ip_block=1,chain"
SecRule TX:ip_block "@streq 1" \
"id:950003, block, log, msg:'Blocked IP address: %{REMOTE_ADDR}', status:403, setenv:REMOTE_ADDR=tx.addr,\
exec:/etc/nginx/modsec/add_to_blacklist.lua"
And the following lua included code. Note: Checking rules with nginx -t also will check lua syntax in case you have errors. The following lua code could be adapted to fail2ban but be warned that nginx is running this as worker threads as the zimbra user so make sure any database or application called is re-entrant. I have some ideas how to map an ipset into a fail2ban jail if that is a desire with an external script to switch an empty ipset into place while the script drains current ip's into the fail2ban jail. In other words, use an ipset but not attached to a fw rule.
Code: Select all
-- verify what uid we are using
function get_process_uid()
local handle = io.popen("id -u")
local uid = handle:read("*a")
handle:close()
return tonumber(uid)
end
-- Note: cp /usr/sbin/ipset /usr/local/bin/ipset; chmod 4555 !$; or sudo entry for /usr/sbin/ipset
-- add_to_blacklist.lua (this runs as zimbra's uid but ipset needs root)
function add_to_blacklist(remote_addr)
-- %%% ipset is thread safe but is fail2ban or its db, or other programs?
-- %%% Do we trust REMOTE_ADDR from nginx parsing? Perhaps sanitize again before execute
local cmd = "/usr/local/bin/ipset add blacklist24hr " .. remote_addr .. " -exist "
os.execute(cmd)
--local uid = get_process_uid()
--local cmd = "/bin/logger -p local2.info NETWORK setting " .. remote_addr .. " uid: " .. uid
local cmd = "/bin/logger -p local2.info NETWORK zimbra is adding blacklist24hr " .. remote_addr
os.execute(cmd)
end
--add_to_blacklist("2.1.1.1")
-- modsecurity rule setenv REMOTE_ADDR and we extract here
add_to_blacklist(m.getvar("REMOTE_ADDR"))
These rules will get tighter and better as I become more adept with the tool.
If anyone needs the steps to install modsecurity 3, let me know and I'll post more information. I broke them into 4 steps/scripts
- step0-modsecurity.sh - install components needed to compile everything
- step1-modsecurity.sh - grab, build, and install ModSecurity into /usr/local
- step2-connector.sh - build and install the nginx connector. Currently 2 ways. One using the Zimbra 3rd party nginx and without
- step3-install-modsecurity.sh - bash script with options that will be renamed to do all the steps at some point.
I run the step3 script to test my rules and restart the proxy. It can also patch zimbra's nginx and install /etc/nginx/modsec
I am unsure of the best way to build the connector. If I had any pull with Zimbra, I would ask them to include 2 files (modsecurity library and nginx connector) with their nginx rpm. I currently modify their spec file myself with the addition of 2 lines for the connector. I also built it statically into nginx like how they do all their nginx modules but like the option to load the module when I need it.
Code: Select all
% cat step0-modsecurity.sh
dnf groupinstall "Development Tools"
dnf install openssl-devel pcre-devel zlib-devel libxml2-devel libxslt-devel gd-devel perl-ExtUtils-Embed GeoIP-devel
dnf install expat-devel yajl-devel
# so we can do exec
dnf install lua-devel
# to use syslog in lua, need posfix. Easiest way to install
dnf install luarocks
luarocks install luaposix
And ModSecurity library
Code: Select all
% cat step1-modsecurity.sh
git clone --depth 1 -b v3.0.9 --single-branch https://github.com/SpiderLabs/ModSecurity
#git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init
git submodule update
./build.sh
make clean #if you want to reconfigure anything with ./configure
./configure --with-pcre2 --with-lua
make
make install
It should go without saying that I am running this on a staging server which is acting like a honeypot as I learn how the tool will behave and learn to write better rules. Frankly, I had no idea that it could be extended this easily, had scoring or the abilities to turn off large swaths of rule sets or even the ability to identify slow performing rules. It is a flexible tool where we could put up a captcha or redirect to a landing page vs strict blocking.
Jim