Introduzione
Il servizio piu’ esposto in rete e’ senza dubbio il web server, che permette di visitare il sito e “navigare” in rete, servendo migliaia di richieste al minuto. Essendo il servizio piu’ esposto in rete, e’ ovvio che ci si sia focalizzati nello scardinare e difendere questi sistemi; ci sono tante soluzioni atte a proteggere un web server ma noi qui ve ne proponiamo una molto interessante: mod_security di Apache e fail2ban in combinazione.
Apache e’ il web server piu’ diffuso in rete data la sua natura multipiattaforma, e sono stati sviluppati tanti moduli per integrare funzioni piu’ o meno interessanti mantenendo il core del progetto abbastanza leggero ma flessibile. Uno dei tanti moduli che prenderemo in considerazione e’ il mod_security.
mod_security
Il mod_security e’ un modulo che permette di loggare i piu’ comuni attacchi ad Apache come XSS, remote command execution, file disclosure e tutto quello che puo’ essere considerato dannoso nei confronti di Apache. Il modulo puo’ essere tranquillamente scaricato da qui: http://www.modsecurity.org/
Il sito e’ pieno di materiale riguardo mod_security e vi consiglio di leggerlo tutto per comprendere a pieno le potenzialita’ di questo modulo. Noi invece tratteremo solo l’aspetto base e l’integrazione di fail2ban con questo modulo.
In questo articolo tratteremo la versione 2.5.9 (anche se disponibile la versione 2.5.10). Una volta scaricato e scompattato, dobbiamo compilarci il modulo con la classica combinazione di comandi
$ ./configure $ make
Per l’installazione del modulo, dipende molto dalla distribuzione. Si puo’ provare a dare da root
# make install
ma io preferisco installare i moduli a mano; su un sistema archlinux (dove e’ stato configurato e testato) il modulomod_security2.so va copiato nella directory /etc/httpd/modules, che e’ un link simbolico a /usr/lib/httpd/modules.
Per quanto riguarda le rules, le regole che mod_security deve rispettare, basta copiarle tutte nella directory/etc/httpd/conf/extra/modsecurity (dove modsecurity e’ una directory che creerete, giusto per tenere separate dagli altri file di configurazione di Apache). Vi consiglio caldamente di studiarvi il modulo ed, eventualmente, modificarne le rules per adattarsi alle vostre esigenze.
E’ importante configurare il logging di mod_security e qualche altra direttiva. Il file di configurazione principale e’/etc/httpd/conf/extra/modsecurity/modsecurity_crs_10_config.conf dove dobbiamo settare la direttiva
#SecAuditLogRelevantStatus "^(?:5|4(?!04))"
E’ importante commentare questa riga altrimenti chiunque riceva un errore 404 verra’ riconosciuto come attaccante, facendo scattare la protezione di fail2ban (anche se dipende dalla propria policy, poiche’ potrebbe essere necessario gestire richieste del genere).
Per completare il tutto bisogna dire ad Apache di caricare il modulo, quindi in httpd.conf (o apache2.conf per i debianisti):
LoadModule security2_module modules/mod_security2.so
e per caricare la configurazione e le regole
Include conf/extra/modsecurity/*.conf
Fatto questo, possiamo riavviare Apache e controllare che tutto funzioni: in /var/log/httpd/ dovremmo avere i filemodsec_audit.log e modsec_debug.log che indicano rispettivamente gli attacchi eseguiti ed il relativo debugging.
Per testare il funzionamento possiamo fare un semplice test:
attacker@host$ nc target.com 80 GET / FUNNY/1.0
Abbiamo inviato al nostro web server una richiesta GET su protocollo FUNNY 1.0 che e’, ovviamente, sconosciuto.
Questo potrebbe essere un tentativo di HTTP fingerprinting o l’inizio di un attacco DoS. Verifichiamo quindi se mod_security ha rilevato l’attacco:
--d986756f-A-- [17/Oct/2009:14:09:56 +0200] Stm0E8CoAQgAAAm@KyAAAAAA 192.168.1.2 45299 192.168.1.8 80 --d986756f-B-- GET / FUNNY/1.0 --d986756f-F-- HTTP/1.1 505 HTTP Version Not Supported Content-Length: 547 Connection: close Content-Type: text/html; charset=iso-8859-1 --d986756f-H-- Message: Warning. Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/httpd/conf/extra/modsecurity/modsecurity_crs_21_protocol_anomalies.conf"] [line "35"] [id "960008"] [msg "Request Missing a Host Header"] [severity "WARNING"] [tag "PROTOCOL_VIOLATION/MISSING_HEADER"] Message: Warning. Match of "rx ^OPTIONS$" against "REQUEST_METHOD" required. [file "/etc/httpd/conf/extra/modsecurity/modsecurity_crs_21_protocol_anomalies.conf"] [line "41"] [id "960015"] [msg "Request Missing an Accept Header"] [severity "CRITICAL"] [tag "PROTOCOL_VIOLATION/MISSING_HEADER"] Message: Warning. Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/httpd/conf/extra/modsecurity/modsecurity_crs_21_protocol_anomalies.conf"] [line "48"] [id "960009"] [msg "Request Missing a User Agent Header"] [severity "WARNING"] [tag "PROTOCOL_VIOLATION/MISSING_HEADER"] Message: Access denied with code 505 (phase 2). Match of "rx ^HTTP/(0\\.9|1\\.[01])$" against "REQUEST_PROTOCOL" required. [file "/etc/httpd/conf/extra/modsecurity/modsecurity_crs_30_http_policy.conf"] [line "83"] [id "960034"] [msg "HTTP protocol version is not allowed by policy"] [severity "CRITICAL"] [tag "POLICY/PROTOCOL_NOT_ALLOWED"] Action: Intercepted (phase 2) Stopwatch: 1255781395665272 493764 (461298 481742 -) Producer: ModSecurity for Apache/2.5.9 (http://www.modsecurity.org/); core ruleset/1.6.1. Server: Apache --d986756f-K-- SecRule "REQUEST_METHOD" "@rx ^(?:GET|HEAD)$" "phase:2,chain,t:none,deny,log,auditlog,status:400,msg:'GET or HEAD requests with bodies',severity:2,id:960011,tag:PROTOCOL_VIOLATION/EVASION" SecRule "&REQUEST_HEADERS:Host" "@eq 0" "phase:2,skip:1,t:none,log,auditlog,msg:'Request Missing a Host Header',id:960008,tag:PROTOCOL_VIOLATION/MISSING_HEADER,severity:4" SecRule "&REQUEST_HEADERS:Accept" "@eq 0" "phase:2,chain,skip:1,t:none,log,auditlog,msg:'Request Missing an Accept Header',severity:2,id:960015,tag:PROTOCOL_VIOLATION/MISSING_HEADER" SecRule "REQUEST_METHOD" "!@rx ^OPTIONS$" "phase:2,log,auditlog,pass,t:none" SecRule "&REQUEST_HEADERS:User-Agent" "@eq 0" "phase:2,skip:1,t:none,log,auditlog,msg:'Request Missing a User Agent Header',id:960009,tag:PROTOCOL_VIOLATION/MISSING_HEADER,severity:4" SecRule "&REQUEST_HEADERS:Content-Type" "@eq 0" "phase:2,pass,chain,t:none,log,auditlog,msg:'Request Containing Content, but Missing Content-Type header',id:960904,severity:4" SecRule "REQUEST_PROTOCOL" "!@rx ^HTTP/(0\\.9|1\\.[01])$" "phase:2,t:none,deny,log,auditlog,status:505,msg:'HTTP protocol version is not allowed by policy',severity:2,id:960034,tag:POLICY/PROTOCOL_NOT_ALLOWED" ... output tagliato ....
Come possiamo vedere, il tentativo e’ stato rilevato (Apache pensa che FUNNY/1.0 sia un protocollo HTTP non supportato).
fail2ban
fail2ban e’ uno dei sistemi di parser log piu’ flessibili in circolazione: scritto in python, segue una architettura client/server ed una serie di filtri ed azioni da associare a qualsiasi evento su logfile che si verifichi, grazie ad un robusto e potente sistema di regexp stile perl: lo scopo e’ quello di tagliare fuori dal sistema tutti gli utenti indesiderati. A differenza di mod_security, fail2ban e’ supportato da qualsiasi packet manager presente in (quasi) tutte le distribuzioni, quindi per l’installazione ci riferiremo al nostro packet manager di fiducia (per installazione manuale o altro, guardare qui).
Come detto, fail2ban ha un file di configurazione generale, jail.conf, nel quale vengono specificate le direttive al daemon, una sezione action, nel quale vengono specificate le azioni da prendere quando si verifica un evento, e filter, dove sono presenti i file di configurazione per ogni servizio con la regexp da applicare al file di log al fine di rilevare l’evento.
Facciamo con ordine. Creiamo un filtro da applicare al file di log di mod_security; tale filtro e’ cosi’ composto:
# Fail2Ban configuration file for mod_security # Author: Florian Roth # [Definition] failregex = \[.*?\]\s[\w-]*\s<HOST>\s ignoreregex =
lo chiamiamo mod_sec.conf e lo piazziamo in /etc/fail2ban/filter.d/. Dobbiamo decidere cosa fare quando viene rilevato un evento da mod_security; dobbiamo quindi vedere in /etc/fail2ban/action.d se c’e’ qualcosa che fa al caso nostro oppure dobbiamo crearla. Il nostro scopo e’ bloccare l’accesso al nostro sito da parte dell’attaccante, quindi possiamo usare l’action iptables-multiport che crea un chain di iptables dove nega l’accesso all’attaccante tramite policy DROP (date uno sguardo ad iptables-multiport.conf).
Oltre a bloccare l’accesso, vogliamo anche loggare l’evento da qualche parte. Se abbiamo un server SMTP possiamo usare una delle tante action presenti, se invece vogliamo avere tutto su file di log, possiamo modificare leggermente simple-log.conf per adattarsi alle nostre necessita’.
Sostanzialmente, basta modificare l’actionban come segue:
actionban = printf %%b "[`date`]Subject: [Fail2Ban] <name>: banned <ip> Hi,\n The IP <ip> has just been banned by Fail2Ban after <failures> attempts against <name>.\n Here are more information about <ip>:\n `/usr/bin/whois <ip>`\n Regards, Fail2Ban\n" >> /var/log/fail2ban-modsecban.log
Cosi’ facendo avremo nel file /var/log/fail2ban-modsecban.log tutti i ban eseguiti da fail2ban con tanto di whois e data. Potete modificare tutto quello che volete dopo il printf %%b e crearvi un log su misura.
Combiniamo tutto questo nel file jail.conf aggiungendo:
[mod_sec] enabled = true filter = mod_sec action = iptables-multiport[name=ModSec, port="http,https"] simple-log[name=modsec] logpath = /var/log/httpd/modsec_audit.log maxretry = 3
Come possiamo vedere, passiamo come argomento di iptables-multiport un nome e le porte su quale applicare il ban; inoltre, sempre nel campo action aggiungiamo la riga relativa al simple-log. Il logpath e’ il file di log al quale fail2ban deve applicare il filtro dichiarato a riga 3 (filter = mod_sec).
Possiamo far partire fail2ban e verifichiamo che tutto funzioni:
root# fail2ban-client status Status |- Number of jail: 1 `- Jail list: mod_sec
root# fail2ban-client status mod_sec Status for the jail: mod_sec |- filter | |- File list: /var/log/httpd/modsec_audit.log | |- Currently failed: 0 | `- Total failed: 0 `- action |- Currently banned: 0 | `- IP list: `- Total banned: 0
Dopo aver eseguito 3 volte un attacco ad Apache avremo questa situazione:
root# fail2ban-client status mod_sec Status for the jail: mod_sec |- filter | |- File list: /var/log/httpd/modsec_audit.log | |- Currently failed: 0 | `- Total failed: 13 `- action |- Currently banned: 1 | `- IP list: 192.168.1.2 `- Total banned: 1
Nel file fail2ban-modsecban.log:
[Thu Oct 15 22:43:03 CEST 2009]Subject: [Fail2Ban] modsec: banned 192.168.1.2 Hi, The IP 192.168.1.2 has just been banned by Fail2Ban after 3 attempts against modsec. Here are more information about 192.168.1.2: Regards, Fail2Ban
Ovviamente il whois per il mio IP LAN non e’ presente.
Possiamo vedere iptables:
root# iptables -nL Chain INPUT (policy DROP) target prot opt source destination fail2ban-ModSec tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 Chain fail2ban-ModSec (1 references) target prot opt source destination DROP all -- 192.168.1.2 0.0.0.0/0
Conclusioni
Spero di avervi mostrato in maniera chiara ed esauriente come bloccare attacchi ripetuti al vostro web server, in modo da aumentare la vostra sicurezza. Ovviamente questa era una configurazione di base: e’ molto importante modificare ed adattare mod_security alle vostre esigenze per prevenire falsi positivi ed essere piu’ performante contro gli attacchi.
Fail2ban, inoltre, e’ molto flessibile e si presta alla configurazione di qualsiasi servizio vogliate; vi consiglio di leggerle la documentazione del progetto.