Keep Server Online
If you find the Apache Lounge, the downloads and overall help useful, please express your satisfaction with a donation.
or
A donation makes a contribution towards the costs, the time and effort that's going in this site and building.
Thank You! Steffen
Your donations will help to keep this site alive and well, and continuing building binaries. Apache Lounge is not sponsored.
| |
|
Topic: Hardening rules for mod_security |
|
Author |
|
Steffen Moderator
Joined: 15 Oct 2005 Posts: 3094 Location: Hilversum, NL, EU
|
Posted: Sun 25 Dec '05 22:08 Post subject: Hardening rules for mod_security |
|
|
Just to share some mod_security rules with you. When you get false positives for your server, let us know here.
If you have a usefull rule, please post it here.
Code: |
<IfModule mod_security.c>
# Turn ModSecurity On
SecFilterEngine On
#SecFilterScanPOST On
SecFilterCheckURLEncoding On
SecFilterCheckUnicodeEncoding Off
# Accept almost all byte values
SecFilterForceByteRange 1 255
# Server masking is optional
# SecServerSignature "Steffen :)"
#SecUploadDir logs
#SecUploadKeepFiles Off
# Only record the interesting stuff
SecAuditEngine RelevantOnly
SecAuditLog logs/sec.log
## -- Common attacks --------------------
SecFilterDefaultAction "deny,log,msg:'Common attacks',status:403"
#Web Proxy GET Request
SecFilter "^GET (http|https|ftp)\:/"
#Web Proxy HEAD Request
SecFilter "^HEAD (http|https|ftp)\:/"
#Proxy POST Request
SecFilter "^POST (http|https|ftp)\:/"
#Proxy CONNECT Request
SecFilterSelective THE_REQUEST "^CONNECT "
# Only accept request encodings we know how to handle.
SecFilterSelective REQUEST_METHOD "!^(GET|HEAD)$" chain
SecFilterSelective HTTP_Content-Type "!(^application/x-www-form-urlencoded$|^multipart/form-data;)"
# Do not accept GET or HEAD requests with bodies
SecFilterSelective REQUEST_METHOD "^(GET|HEAD)$" chain
SecFilterSelective HTTP_Content-Length "!^$"
# Restrict which request methods can be used
SecFilterSelective REQUEST_METHOD "!^(GET|HEAD|POST)$"
# Restrict protocol versions.
SecFilterSelective SERVER_PROTOCOL "!^HTTP/(0\.9|1\.0|1\.1)$"
# Require Content-Length to be provided with every POST request.
SecFilterSelective REQUEST_METHOD "^POST$" chain
SecFilterSelective HTTP_Content-Length "^$"
# Don't accept transfer encodings we know we don't know how to handle
SecFilterSelective HTTP_Transfer-Encoding "!^$"
## -- PHP attacks --------------------
SecFilterSignatureAction "log,deny,msg:'PHP attack'"
# Possible code execution attack (targets valid PHP streams constructs)
SecFilterSelective ARGS_NAMES "^php:/"
#phpBB attack
SecFilterSelective ARG_highlight "(\x27|%27|\x2527|%2527)"
## -- Awstats-------------------------
SecFilterSignatureAction "log,deny,msg:'Awstats Attack'"
SecFilterSelective ARGS_NAMES "configdir"
## -- SQL Injection Attacks --------------------
SecFilterSignatureAction "log,deny,msg:'SQL Injection attack'"
# Generic
SecFilterSelective ARGS "delete[[:space:]]+from"
SecFilterSelective ARGS "drop[[:space:]]+database"
SecFilterSelective ARGS "drop[[:space:]]+table"
SecFilterSelective ARGS "drop[[:space:]]+column"
SecFilterSelective ARGS "drop[[:space:]]+procedure"
SecFilterSelective ARGS "create[[::space:]]+table"
SecFilterSelective ARGS "update.+set.+="
SecFilterSelective ARGS "insert[[:space:]]+into.+values"
SecFilterSelective ARGS "select.+from"
SecFilterSelective ARGS "bulk[[:space:]]+insert"
SecFilterSelective ARGS "union.+select"
SecFilterSelective ARGS "or.+1[[:space:]]*=[[:space:]]1"
SecFilterSelective ARGS "alter[[:space:]]+table"
SecFilterSelective ARGS "or 1=1--'"
SecFilterSelective ARGS "'.+--"
# MySQL
SecFilterSelective ARGS "into[[:space:]]+outfile"
SecFilterSelective ARGS "load[[:space:]]+data
SecFilterSelective ARGS "/\*.+\*/"
## -- Command execution --------------------
SecFilterSignatureAction "log,deny,msg:'Command execution attack'"
SecFilterSelective ARGS_VALUES "^(uname|id|ls|rm|kill)"
SecFilterSelective ARGS_VALUES "^(ls|id|pwd|wget)"
SecFilterSelective ARGS_VALUES ";[[:space:]]*(ls|id|pwd|wget)"
</IfModule>
|
|
|
Back to top |
|
raffe
Joined: 20 Dec 2005 Posts: 15
|
Posted: Tue 27 Dec '05 22:56 Post subject: |
|
|
I replaced the standard rules with yours, then Apache didnt want to start (copy - paste). How come?
Today I use http://www.wampserver.com/en/download.php on WinXP:
- Includes MySQL 5.0 and the mysqli extension, mysql connections are opened with mysqli_connect()
- Apache 2.0.55
- PHP 5.1.1 + PECL
- SQLitemanager
- MySQL 5.0.17
- Phpmyadmin
These are the standard rules I use now (I know I should change the rules, but don't know enough, don't even have this file exec:/home/users/ivanr/apache/bin/report-attack.pl )
Quote: | <IfModule mod_security.c>
# Turn module advertising On or Off
# SecServerResponseToken On
# Turn the filtering engine On or Off
SecFilterEngine On
# Make sure that URL encoding is valid
SecFilterCheckURLEncoding On
# Only allow bytes from this range
SecFilterForceByteRange 32 126
# The audit engine works independently and
# can be turned On of Off on the per-server or
# on the per-directory basis. "On" will log everything,
# "DynamicOrRelevant" will log dynamic requests or violations,
# and "RelevantOnly" will only log policy violations
SecAuditEngine RelevantOnly
# The name of the audit log file
SecAuditLog logs/audit_log
SecFilterDebugLog logs/modsec_debug_log
SecFilterDebugLevel 0
# Should mod_security inspect POST payloads
SecFilterScanPOST On
# Action to take by default
SecFilterDefaultAction "deny,log,status:500"
# Redirect user on filter match
SecFilter xxx redirect:http://www.webkreator.com
# Execute the external script on filter match
SecFilter yyy log,exec:/home/users/ivanr/apache/bin/report-attack.pl
# Simple filter
SecFilter 111
# Only check the QUERY_STRING variable
SecFilterSelective QUERY_STRING 222
# Only check the body of the POST request
SecFilterSelective POST_PAYLOAD 333
# Only check arguments (will work for GET and POST)
SecFilterSelective ARGS 444
# Test filter
SecFilter "/cgi-bin/modsec-test.pl/keyword"
# Another test filter, will be denied with 404 but not logged
# action supplied as a parameter overrides the default action
SecFilter 999 "deny,nolog,status:500"
# Prevent OS specific keywords
SecFilter /etc/passwd
# Prevent path traversal (..) attacks
SecFilter "\.\./"
# Weaker XSS protection but allows common HTML tags
SecFilter "<[[:space:]]*script"
# Prevent XSS atacks (HTML/Javascript injection)
SecFilter "<(.|\n)+>"
# Very crude filters to prevent SQL injection attacks
SecFilter "delete[[:space:]]+from"
SecFilter "insert[[:space:]]+into"
SecFilter "select.+from"
# Require HTTP_USER_AGENT and HTTP_HOST headers
SecFilterSelective "HTTP_USER_AGENT|HTTP_HOST" "^$"
# Forbid file upload
SecFilterSelective "HTTP_CONTENT_TYPE" multipart/form-data
# Only watch argument p1
SecFilterSelective "ARG_p1" 555
# Watch all arguments except p1
SecFilterSelective "ARGS|!ARG_p2" 666
# Only allow our own test utility to send requests (or Mozilla)
SecFilterSelective HTTP_USER_AGENT "!(mod_security|mozilla)"
# Do not allow variables with this name
SecFilterSelective ARGS_NAMES 777
# Do now allow this variable value (names are ok)
SecFilterSelective ARGS_VALUES 888
# Test for a POST variable parsing bug, see test #41
SecFilterSelective ARG_p2 AAA
# Stop spamming through FormMail
# note the exclamation mark at the beginning
# of the filter - only requests that match this regex will
# be allowed
<Location /cgi-bin/FormMail>
SecFilterSelective "ARG_recipient" "!@webkreator.com$"
</Location>
# when allowing upload, only allow images
# note that this is not foolproof, a determined attacker
# could get around this
<Location /fileupload.php>
SecFilterInheritance Off
SecFilterSelective POST_PAYLOAD "!image/(jpeg|bmp|gif)"
</Location>
</IfModule> |
|
|
Back to top |
|
Steffen Moderator
Joined: 15 Oct 2005 Posts: 3094 Location: Hilversum, NL, EU
|
Posted: Tue 27 Dec '05 23:12 Post subject: |
|
|
Should work, Any error message ?
Try to start apache in a DOS box and see if you get a error message.
Indeed, the example in the Readme First of the .zip not that good, I removed it now from the zip and replaced with an other.
Steffen |
|
Back to top |
|
raffe
Joined: 20 Dec 2005 Posts: 15
|
Posted: Tue 27 Dec '05 23:45 Post subject: |
|
|
Hi!
Ehh I tried again, and got the same problem when I restarted the apache server as before (and nothing in apache_error.log). Suddenly after the second time I tried to restart (if it don't work the first time, look suprised and try again wihout changing anything ) I got the Windows dialog "The Apache server has got a problem bla bla... Do you like to send an Error report to Microsoft?"
After that it works OK with your rules ... Strange ... I have restarted several times and nothing wrong now (feeling kind of stupid )
Or, really, I am happy it works (but, still, very strange). Is this "normal" with Apache?...
Can I use your rules without getting problems (for an example, I don't have phpBB installed)? Or is the new one in the zip better? This one is the new one, is'nt it?:
Quote: | <IfModule mod_security.c>
# Enable ModSecurity
SecFilterEngine On
# Reject requests with status 403
SecFilterDefaultAction "deny,log,status:403"
# Some sane defaults
#SecFilterScanPOST On
SecFilterCheckURLEncoding On
SecFilterCheckUnicodeEncoding Off
# Accept almost all byte values
SecFilterForceByteRange 1 255
# Server masking is optional
# SecServerSignature "Microsoft-IIS/5.0"
# Designate a directory for temporary files
# storage. It is a good idea to change the
# value below to a private directory, just as
# an additional measure against race conditions
#SecUploadDir /tmp
#SecUploadKeepFiles Off
# Only record the interesting stuff
SecAuditEngine RelevantOnly
# Uncomment below to record responses with unusual statuses
# SecAuditLogRelevantStatus ^5
SecAuditLog logs/audit_log
# You normally won't need debug logging
#SecFilterDebugLevel 0
#SecFilterDebugLog logs/modsec_debug_log
# Only accept request encodings we know how to handle
# we exclude GET requests from this because some (automated)
# clients supply "text/html" as Content-Type
SecFilterSelective REQUEST_METHOD "!^(GET|HEAD)$" chain
SecFilterSelective HTTP_Content-Type "!(^application/x-www-form-urlencoded$|^multipart/form-data;)"
# Do not accept GET or HEAD requests with bodies
SecFilterSelective REQUEST_METHOD "^(GET|HEAD)$" chain
SecFilterSelective HTTP_Content-Length "!^$"
# Require Content-Length to be provided with
# every POST request
SecFilterSelective REQUEST_METHOD "^POST$" chain
SecFilterSelective HTTP_Content-Length "^$"
# Don't accept transfer encodings we know we don't handle
SecFilterSelective HTTP_Transfer-Encoding "!^$"
</IfModule> |
|
|
Back to top |
|
raffe
Joined: 20 Dec 2005 Posts: 15
|
Posted: Wed 28 Dec '05 0:16 Post subject: Re: Hardening rules for mod_security |
|
|
Steffen wrote: | When you get false positives for your server, let us know here. | I think I have one. I have PsychoStats on my server, and if I first click on a player and then click on a weapon (to get statistics about that weapon) I get a URL similar to this:
http://cstrike.vnet.ee/stats/player.php?id=201302&weaponid=8&wsort=kills&worder=desc#hitbox
But on my server, if I click that URL I get:
"Forbidden. You don't have permission to access /stats/player.php on this server"
In apache_error.log i get
Quote: | [Tue Dec 27 23:00:47 2005] [error] [client 192.168.0.1] mod_security: Access denied with code 403. Pattern match "^(uname|id|ls|rm|kill)" at ARGS_VALUES("wsort") [msg "Command execution attack"] [hostname "12.34.56.78"] [uri "/stats/player.php?id=33&weaponid=8&wsort=kills&worder=desc"] |
I guess it has to do with this line in httpd.conf:
SecFilterSelective ARGS_VALUES "^(uname|id|ls|rm|kill)"
And it finds "...wsort=kills&worder..." (or something, I'm only guessing )
How can we fix this, without taking away the good SecFilterSelective line (I'm sure it is good to have there)... Can we somehow add that "kills" is OK but not "kill"? |
|
Back to top |
|
Steffen Moderator
Joined: 15 Oct 2005 Posts: 3094 Location: Hilversum, NL, EU
|
Posted: Wed 28 Dec '05 0:26 Post subject: |
|
|
Good catch.
It is a matter of adjusting the rules to your configuration.
Best is to remove the "kill" :
SecFilterSelective ARGS_VALUES "^(uname|id|ls|rm)"
What you can also do is, not to deny but only logging:
Change:
SecFilterSignatureAction "log,deny,msg:'Command execution attack'"
To:
SecFilterSignatureAction "log,pass,msg:'Command execution attack'"
Steffen |
|
Back to top |
|
raffe
Joined: 20 Dec 2005 Posts: 15
|
Posted: Wed 28 Dec '05 0:37 Post subject: |
|
|
Q1: Is it possible to do both? something like this?
Code: |
...
...
## -- Command execution --------------------
## REMOVE "kill" HERE (to work with Psychostats)
SecFilterSignatureAction "log,deny,msg:'Command execution attack'"
SecFilterSelective ARGS_VALUES "^(uname|id|ls|rm)"
SecFilterSelective ARGS_VALUES "^(ls|id|pwd|wget)"
SecFilterSelective ARGS_VALUES ";[[:space:]]*(ls|id|pwd|wget)"
## PUT "kill" BACK HERE (we will still logg "kill")
SecFilterSignatureAction "log,pass,msg:'Psychostats .wsort=kills. & .v=kills. = OK, Else command execution attack'"
SecFilterSelective ARGS_VALUES "^(kill)"
</IfModule> |
I mean, move kill to another place?
Q2: You write both "ARGS_VALUES" and "ARG_VALUES" above, do the "ARG_VALUES" line mean it belongs to the line above it?
Last edited by raffe on Wed 28 Dec '05 15:56; edited 2 times in total |
|
Back to top |
|
Steffen Moderator
Joined: 15 Oct 2005 Posts: 3094 Location: Hilversum, NL, EU
|
Posted: Wed 28 Dec '05 1:03 Post subject: |
|
|
Q1
A good idea to split them.
Q2.
I do not know if there is a diffenrence between ARGS_VALUES and ARG_VALUES . The documentation has also no clue.
I got the rule from the author of mod_security. I asked him if there is a difference. As soon I have an answer I let you know.
Steffen |
|
Back to top |
|
Steffen Moderator
Joined: 15 Oct 2005 Posts: 3094 Location: Hilversum, NL, EU
|
Posted: Wed 28 Dec '05 15:09 Post subject: |
|
|
The answer from Ivan is:
ARG_VALUES is an error. It's supposed to say ARGS_VALUES in both places.
Steffen |
|
Back to top |
|
|
|
|
|
|