/* ############################################################################### mod_block_worms.c - A module for Apache 1.3.33 Version 0.1.2 beta - 07/DEC/2004 - Second public release (c) 2003, 2004 Juan R. Pozo http://html.conclase.net/cp/scripts/ mailto:jrpozo@conclase.net Mailing-list: http://www.conclase.net/mailman/listinfo/cpanel_conclase.net ############################################################################### This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################### CHANGELOG 7/DEC/2004 - v.0.1.2 beta: Precompiles all signature regexes so we don't have to compile them for every request (doh!) 1/AUG/2003 - v 0.1.1 beta: First public release ############################################################################### INSTALLATION make all && make install Add the configuration directives to your httpd.conf and restart Apache Note: when a request matches one of the signatures, a DONTLOG environment variable is set. This can be used for conditional logging. ############################################################################### CONFIGURATION DIRECTIVES BlockWormsSignature regex code regex is a regular expresion that matches a worm attack pattern code is the code that we want Apache to send back to the attacker set 0 for Apache to process the request normally or set an error code (404, 500, etc.) to answer with a bogus error code or set -1 to terminate the request without notifying the client at all BlockWormsLogFile filename Self explanatory Example: BlockWormsSignature "cmd.exe" -1 BlockWormsSignature "root.exe" -1 BlockWormsSignature "shell.exe" -1 BlockWormsSignature "^/default.ida" -1 BlockWormsSignature "^/passwd$" -1 BlockWormsSignature "^/sumthin$" -1 BlockWormsSignature "^/apache_pb.gif$" 404 BlockWormsLogFile /usr/local/apache/logs/block_worms_log ############################################################################### Please consider making a donation today. Visit my amazon.com wishlist at: http://html.conclase.net/link/wishlist Thank you :) ############################################################################### */ #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_main.h" #include "http_protocol.h" #include "http_request.h" module MODULE_VAR_EXPORT block_worms_module; /* The per-server configuration data structure */ typedef struct { array_header *codes; array_header *regexes; char *logfile; FILE *logfh; } block_worms_server_config; /* Allocate storage for the per-server configuration information and set up appropriate defaults */ static void *block_worms_create_server_config(pool *p, server_rec *s) { block_worms_server_config *scfg = (block_worms_server_config *) ap_pcalloc(p, sizeof(block_worms_server_config)); scfg->logfile = NULL; scfg->logfh = NULL; scfg->codes = ap_make_array(p, 0, sizeof(int)); scfg->regexes = ap_make_array(p, 0, sizeof(regex_t *)); return (void *)scfg; } /* Directive handlers */ /* The block_works_cmd array declares 2 directives: BlockWormsSignature, which is processed by a handler routine named add_signature_cmd(), and BlockWormsLogFile, processed by set_logfile_cmd() */ static const char *block_worms_add_signature_cmd(cmd_parms *parms, void *mconfig, char *sig, char *code) { block_worms_server_config *scfg = (block_worms_server_config *) ap_get_module_config(parms->server->module_config, &block_worms_module); regex_t regex; *(int *)ap_push_array(scfg->codes) = atoi(code); *(regex_t **)ap_push_array(scfg->regexes) = ap_pregcomp(parms->pool, sig, REG_EXTENDED | REG_NOSUB); if (scfg->regexes->nelts != scfg->codes->nelts) { return "There are more error codes than signatures or vice versa"; } return NULL; } static const char *block_worms_set_logfile_cmd(cmd_parms *parms, void *mconfig, char *logfile) { block_worms_server_config *scfg = (block_worms_server_config *) ap_get_module_config(parms->server->module_config, &block_worms_module); scfg->logfile = (char *)ap_pstrdup(parms->pool, logfile); return NULL; } /* Our command_rec definition: */ static const command_rec block_worms_cmds[] = { {"BlockWormsSignature", block_worms_add_signature_cmd, NULL, RSRC_CONF, TAKE2, "A regex signature for the intrusions we want to filter out and the " "response code we should return for the request, or -1 for no response"}, {"BlockWormsLogFile", block_worms_set_logfile_cmd, NULL, RSRC_CONF, TAKE1, "The path to the logfile"}, {NULL} }; /* PROCESSING THE REQUEST */ /* The module initializer phase */ void block_worms_init(server_rec *s, pool *p) { block_worms_server_config *scfg = (block_worms_server_config *) ap_get_module_config(s->module_config, &block_worms_module); if (scfg->logfile) { scfg->logfh = ap_pfopen(p, scfg->logfile, "a"); if (!scfg->logfh) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "mod_block_worms: Cannot open logfile %s", scfg->logfile); exit(1); } } } /* The Post Read Request Phase - This is where we will step in to detect attempts of intrusion. */ int block_worms_post_read_request(request_rec *r) { int i; block_worms_server_config *scfg = (block_worms_server_config *) ap_get_module_config(r->server->module_config, &block_worms_module); /* So let's compare the user given patterns with the requested URI. If any pattern matches, we log the request, and terminate the request */ regex_t **regex = (regex_t **)scfg->regexes->elts; int *code = (int *)scfg->codes->elts; for (i = 0; i < scfg->regexes->nelts; i++) { if (regexec(regex[i], r->unparsed_uri, 0, NULL, 0) == 0) { /* We found a match, so first log error in our log... */ if (scfg->logfh) { fprintf(scfg->logfh, "%d - %s - %s - %s\n", r->request_time, ap_gm_timestr_822(r->pool, r->request_time), r->connection->remote_ip, r->the_request); fflush(scfg->logfh); } else { ap_log_error(APLOG_MARK, APLOG_WARNING, r->server, "I lost mod_block_worms logfile handle!"); } /* ...tell mod_log_config not to log this request... */ ap_table_set(r->subprocess_env, "DONTLOG", "1"); /* ...and send the correct response code */ switch (code[i]) { case -1: return DONE; case 0: return OK; default: return code[i]; } } } return OK; } /* Finally the module structure */ module MODULE_VAR_EXPORT block_worms_module = { STANDARD_MODULE_STUFF, block_worms_init, /* module initializer */ NULL, /* per-directory config creator */ NULL, /* dir config merger */ block_worms_create_server_config, /* server config creator */ NULL, /* server config merger */ block_worms_cmds, /* config directive table */ NULL, /* [9] content handlers */ NULL, /* [2] URI-to-filename translation */ NULL, /* [5] check/validate user_id */ NULL, /* [6] check user_id is valid *here* */ NULL, /* [4] check access by host address */ NULL, /* [7] MIME type checker/setter */ NULL, /* [8] fixups */ NULL, /* [10] logger */ NULL, /* [3] header parser */ NULL, /* process initialization */ NULL, /* process exit/cleanup */ block_worms_post_read_request /* [1] post read_request handling */ };