Archivi categoria: Sicurezza

SElinux e CentOS 6: ricevere un’email di notifica in caso di policy violate

In questo post ho discusso di SElinux, illustrandone la logica di funzionamento ed i comandi da utilizzare per la sua configurazione e gestione.

Adesso vedremo come rendere tale sistema di sicurezza il più proattivo possibile, ovvero facendo in modo che sia in grado di inviarci una mail di notifica nel caso in cui una o più policy MAC vengano violate.

selinux-penguin-new_medium

Installazione e configurazione di SEtroubleshoot

Il software in grado di implementare la funzionalità in questione prende il nome di setroubleshoot. Per installarlo possiamo utilizzare il packet manager di casa CentOS/RedHat, ovvero yum:

[root@linuxbox ~]# yum install setroubleshoot

Successivamente, passiamo alla configurazione dell’applicativo in questione, editando il file /etc/setroubleshoot/setroubleshoot.conf. Le entry da modificare sono le seguenti:

recipients_filepath = /var/lib/setroubleshoot/email_alert_recipients
smtp_port = 25
smtp_host = localhost
from_address = mittente@vostrodominio.com
subject = SELinux AVC Alert for nomeserver

Va da sè che l’opzione smtp_host deve essere popolata in base al server SMTP che si vuole utilizzare. Ad esempio, nel mio caso, esiste un’unica macchina che funge da STMP “in uscita”, configurata in modo tale da interfacciarsi con un relay host “esterno” ed “affidabile” (in tal modo evito che le mie email vengano respinte costantemente poichè provenienti da un indirizzo IP pubblico di tipo dinamico e non dotato di record DNS PTR).

Inseriamo adesso, all’interno del file /var/lib/setroubleshoot/email_alert_recipients, il destinatario delle email di notifica:

[root@linuxbox ~]# echo "indirizzo.email@vostrodominio.com" >> /var/lib/setroubleshoot/email_alert_recipients

e riavviamo il servizio che si occupa di gestire tale funzionalità (in modo da attivare le suddette modifiche):

[root@linuxbox ~]# service messagebus restart

Test

Per testare il corretto funzionamento del sistema di notifica appena configurato è necessario fare in modo che uno dei moduli SELinux custom che abbiamo realizzato venga momentaneamente disattivato (in tal modo “forzeremo” il popolamento del file audit.log generando così il trigger che causerà l’inoltro della notifica email sulla nostra casella di posta):

[root@linuxbox ~]# semodule -d <nomemodulo>

Se tutto funziona come dovrebbe, riceveremo una notifica dal contenuto simile al seguente:

[SELinux AVC Alert for linuxbox] SELinux is preventing /usr/sbin/sedispatch from sendto access on the unix_dgram_socket 

SELinux is preventing /usr/sbin/sedispatch from sendto access on the unix_dgram_socket .

*****  Plugin catchall (100. confidence) suggests   **************************

... OMISSIS ...

Alla prossima.

CentOS 6: monitorare le ACL del nostro router Cisco mediante Nagios ed snmptt

Durante gli ultimi mesi ho discusso ampiamente della configurazione di Nagios per la ricezione dei check passivi, quali trap SNMP o security alert. Adesso vi mostrerò come integrare le predette tipologie di allarmi in modo da riuscire a monitorare le ACL del nostro router Cisco.

Premessa

Esiste un modo più veloce per ottenere il monitoraggio delle ACL rispetto a quello che sto per illustrare. Esso consiste, fondamentalmente, nella configurazione di un syslog server (dotato dell’applicativo swatch per l’analisi in tempo reale dei file di log) a cui il nostro router Cisco dovrà puntare. Nel caso in cui un determinato pattern (ad esempio / denied /) dovesse essere matchato da swatch, quest’ultimo genererà un’opportuna notifica email da inoltrare all’amministratore di rete.

La mia configurazione, invece, si basa sulla logica seguente: il router Cisco genererà delle opportune trap SNMP segnalando ciò che avviene a livello di ACL (traffico consentito oppure negato). Esse verranno intercettate da snmptrapd e tradotte da snmptt, per poi essere elaborate dall’event handler submit_check_result e date in pasto a Nagios. Ho optato per tale configurazione poichè sulla mia linux box che funge da syslog server e da NMS sono già attivi sia snmptrapd che snmptt e quindi ho ritenuto conveniente sfruttarli piuttosto che mettere in funzione swatch.

nagiosConfigurazione del router Cisco

La configurazione del router Cisco si basa in 3 passaggi: settaggio della direttiva log per ciascuna entry che andrà a formare l’ACL da monitorare,  settaggio del syslog server a cui inviare le trap ed abilitazione di queste ultime.

Ad esempio, l’ACL di nostro interesse dovrà essere formata da entry di questo tipo:

access-list 102 deny ip host 255.255.255.255 any log

Inoltre, per definire la community string RO (read only) e l’indirizzo IP del server che si occuperà della ricezione delle trap, occorrerà digitare le seguenti direttive:

snmp-server host 192.168.1.1 keypublic
snmp-server community keypublic RO

mentre le trap potranno essere abilitate nel modo seguente:

snmp-server enable traps snmp authentication linkdown linkup coldstart warmstart
snmp-server enable traps tty
snmp-server enable traps config-copy
snmp-server enable traps config
snmp-server enable traps resource-policy
snmp-server enable traps cpu threshold
snmp-server enable traps syslog
snmp-server enable traps firewall serverstatus

 Contenuto dello scrip submit_check_result

Secondo quanto già riportato in questo post, sappiamo che snmptt effettua una traduzione “statica” delle trap (mediante il comando snmpttconvertmib). Per tale motivo, affinchè si possa indurre Nagios a generare dei security alert solo dopo la ricezione di trap ben determinate, occorre modificare il codice sorgente relativo all’event handler submit_check_result. Di seguito riporto il contenuto dello scrip in questione da me customizzato:

 echocmd="/bin/echo"

CommandFile="/var/spool/nagios/cmd/nagios.cmd"

# get the current date/time in seconds since UNIX epoch
datetime=`date +%s`

# create the command line to add to the command file
if [[ $1 == "ip router" ]];then

        if [[ $4 =~ "denied igmp" ]];then

                exit 0;

        elif  [[ $4 =~ "denied" ]];then

                service="Router ACL Connection Denied";

                output="$4 | connection_denied=1"
                cmdline="[$datetime] PROCESS_SERVICE_CHECK_RESULT;router;$service;$3;$output";

        else

                cmdline="[$datetime] PROCESS_SERVICE_CHECK_RESULT;router;$2;$3;$4";

        fi

else

   cmdline="[$datetime] PROCESS_SERVICE_CHECK_RESULT;$1;$2;$3;$4";

fi

# append the command to the end of the command file
`$echocmd $cmdline >> $CommandFile`

Nella fattispecie, vengono dapprima identificate le trap che riguardano il router. Successivamente, nel caso in cui esse contengano il pattern igmp denied, lo scrip uscirà senza effettuare alcuna operazione. Tale “scrematura” è stata necessaria poichè il mio ISP effettua regolarmente del polling IGMP mediante il proprio querier 192.168.100.1 (per il servizio IPTV).

Nel caso in cui, invece, le trap dovessero contenere la stringa denied, la variabile cmdline verrà popolata con l’host name dell’oggetto monitorato da Nagios (per il quale si dovrà aggiornare lo stato del servizio che si occupa di tenere d’occhio le ACL). Nel mio caso tale host name è semplicemente router. Inoltre, l’output  verrà rimaneggiato in modo da tenere traccia delle performance data (graficizzandole mediante l’uso di pnp4nagios).

MIB da utilizzare e configurazione di Nagios

Per prima cosa occorre scaricare le MIB CISCO-SYSLOG-MIB e CISCO-SYSLOG-MIB-V1SMI dal repository FTP della Cisco, effettuandone il parsing mediante snmpttconvertmib.

Successivamente, su Nagios occorrerà definire per l’host name router il servizio che si occuperà di monitorare le ACL:

define service{
        use                             local-service
        host_name                       router
        service_descripion              Router ACL Connection Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

Come ultimo step, a configurazione ultimata possiamo riavviare Nagios per rendere effettive le suddette modifiche:

[root@NMS ~]# service nagios reload

ed abbiamo finito.

A presto.

Avast! free e lo scan che non ti aspetti

Ieri, spulciando gli allarmi di Nagios relativi alla mia rete domestica, ho notato la presenza di una sequela di eventi di questo tipo:

***** Nagios HOME *****

 Notification Type: PROBLEM

 Service: HTTP Not Found
 Host: localhost
 Address: 127.0.0.1
 State: WARNING

 Date/Time: Sat Dec 26 09:04:58 CET 2015

 Additional Info:

 192.168.1.8 - - [26/Dec/2015:09:04:57 +0100] GET /HNAP1/ HTTP/1.1 404 204

ovvero il mio PC client (192.168.1.8) ha provato, in modo automatico, ad accedere a determinate URI HTTP, puntando all’indirizzo IP del suo default gateway (192.168.1.1). In particolare, il file /var/log/httpd/error_log di quest’ultimo riportava le seguenti hit:

[Sat Dec 26 09:04:57 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/HNAP1
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/rom-0
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] scrip not found or unable to stat: /var/www/cgi-bin/webproc
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/a2
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/ajaxmail
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/arr
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/at3
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/atc
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/atx
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/auth
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/bbs
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/bbs
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/bp_revision.cgi
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/br5.cgi
[Sat Dec 26 09:05:03 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/click.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/clicks.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/crtr
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/fg.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/findweather
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/findweather
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/frame_html
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/getattach
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/hotspotlogin.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/hslogin.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/ib
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/index.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/index
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/krcgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/krcgistart
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/link
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/login.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/login
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/logout
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/logout
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/mainmenu.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/mainsrch
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/msglist
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/navega
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/openwebmail
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/out.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/passremind
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/rbaccess
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/rbaccess
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/readmsg
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/rshop.pl
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/search.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/spcnweb
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/sse.dll
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/start
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/te
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/tjcgi1
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/top
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/traffic
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/verify.cgi
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/webproc
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/webscr
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/wingame.pl
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/das
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/fcgi-bin
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/fcgi-bin
[Sat Dec 26 09:05:04 2015] [error] [client 192.168.1.8] File does not exist: /var/www/html/redir

Alla luce di ciò mi sono allarmato, e, credendo che si trattasse di un malware, ho trascorso circa 2 ore tra scansioni antivirus (Avast! Free per l’appunto), Malwarebytes e SuperAntiSpyware, senza ottenere grandi risultati. Infine, giusto per scrupolo, sono andato a controllare il file /var/log/httpd/access_log che riportava lo UA (User Agent) utilizzato per accedere alle suddette URI. Di seguito ne riporto il contenuto:

192.168.1.8 - - [26/Dec/2015:09:04:57 +0100] "GET / HTTP/1.1" 200 - "-" "avast! Antivirus"
192.168.1.8 - - [26/Dec/2015:09:04:57 +0100] "GET /HNAP1/ HTTP/1.1" 404 204 "-" "avast! Antivirus"
192.168.1.8 - - [26/Dec/2015:09:05:03 +0100] "GET /rom-0 HTTP/1.1" 404 203 "-" "avast! Antivirus"
192.168.1.8 - - [26/Dec/2015:09:05:03 +0100] "GET /cgi-bin/webproc?getpage=/../../etc/passwd&var:language=en_us&var:page=* HTTP/1.1" 404 213 "-" "avast! Antivirus"

ovvero l’origine del presunto “attacco” era, molto semplicemente, Avast! free. Infatti, andando a spulciare tra le funzionalità del suddetto antivirus, ho notato la presenza della cosiddetta Protezione rete domestica, la quale non fa altro che scansionare il range di IP della LAN su cui è attestato il client, identificando i vari dispositivi connessi ed i servizi attivi su ciascuno di essi. avast In più, credendo che il mio default gateway fosse uno dei tanti home router dozzinali che si trovano ai discount, ha iniziato a ricercare le suddette URI palesemente vulnerabili (per maggiori info basta cercare home router vulnerabilities su Google).

Tutto è bene quel che finisce bene.

Alla prossima.

CentOS 6: Riavviare automaticamente il servizio barnyard2 mediante Nagios e gli event handlers

In questo post ho mostrato il codice sorgente del demone barnyard2 da me customizzato. Esso, in soldoni, non fa altro che monitorare il contenuto del file alert generato da snort, in modo da poter individuare gli allarmi creati dall’IDS in questione, inserendoli (dopo un’opportuna formattazione) all’interno di uno specifico DBMS (nel nostro caso MySQL).

Purtroppo, però, tale servizio tende a crashare in modo randomico, ragion per cui ho deciso di creare un event handler (per Nagios) in grado di riavviarlo automaticamente.

nagios

Configurazione del SO che ospita L’NMS (Nagios)

Poichè l’operazione di riavvio del demone barnyard2 richiede i privilegi di root, è stato necessario fare in modo che l’utente nagios (che esegue gli event handlers) fosse abilitato all’interno del file /etc/sudoers:

nagios   ALL=NOPASSWD: /sbin/service barnyard2 restart

In particolare, ho fatto in modo che l’esecuzione del comando sudo non richiedesse la password (ALL=NOPASSWD:) solo per il comando /sbin/service barnyard2 restart (per la serie less is more). Inoltre, sempre all’interno del suddetto file, ho inserito, subito dopo la direttiva Defaults    requiretty, la stringa:

Defaults:nagios        !requiretty

in modo tale da consentire all’utente nagios di lanciare il comando sudo anche quando non è in possesso di un terminale (tty). Ciò è necessario poichè tutti gli event handlers vengono lanciati dal nostro NMS in assenza di sessione tty.

Un’altra modifica altrettanto importante ha riguardato SElinux. Esso, infatti, essendo attivo in modalità Enforcing, vietava puntualmente l’esecuzione dell’event handler in questione. Per “aggirare” tale divieto, ho dovuto modificare alcune regole MAC (Mandatory Access Control), attraverso 2 passaggi: il settaggio di una variabile booleana e la creazione di un modulo custom per SElinux.

Nel primo caso è stato sufficiente lanciare il comando:

[root@NMS]# setsebool -P nagios_run_sudo 1

mentre nel secondo caso ho dapprima creato il file permitnagioseventhandlers.te, di cui riporto il contenuto:

module permitnagioseventhandler 1.0;

require {
        type nagios_system_plugin_t;
        type nagios_unconfined_plugin_exec_t;
        type nagios_eventhandler_plugin_t;
        type httpd_t;
        class file { getattr };
        class dir { getattr search };
}

#============= nagios_system_plugin_t ==============
allow nagios_system_plugin_t nagios_unconfined_plugin_exec_t:file {getattr};

#============= httpd_t ==============
allow httpd_t nagios_eventhandler_plugin_t:dir { getattr search };

per poi verificarne la sintassi:

[root@NMS]#  checkmodule -M -m -o permitnagioseventhandler.mod permitnagioseventhandler.te

compliarlo:

[root@NMS]# semodule_package -o permitnagioseventhandler.pp -m permitnagioseventhandler.mod

ed installarlo:

[root@NMS]# semodule -i permitnagioseventhandler.pp

Configurazione di Nagios

Il riavvio del demone barnyard2 richiede parecchio tempo (soprattutto se esso è stato associato a più interfacce di rete, come nel mio caso). Per questo motivo si è reso necessario modificare il paramentro event_handler_timeout presente all’interno del file di configurazione Nagios (/etc/nagios/nagios.cfg), portandolo da 30 secondi (valore di default) a 300 secondi:

event_handler_timeout=400

Per ciò che concerne il servizio (relativo al nostro NMS) che si occupa del monitoraggio di barnyard2, è stata creata la seguente configurazione:

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_descripion             Barnyard2 Service Status
        check_command                   check_local_process_status_all!2!2!barnyard2
        event_handler                   restart_barnyard
        }

dove il comando check_local_process_status_all è così definito:

# 'check_local_process_status_all' command definition
define command{
        command_name    check_local_process_status_all
        command_line    $USER1$/check_procs -c $ARG1$:$ARG2$ -C $ARG3$
        }

Nella fattispecie, le variabili $ARG1$ e $ARG2$ rappresentano, rispettivamente, il numero minimo e massimo di processi (recanti la stringa barnyard2, specificata mediante la variabile $ARG3$) attivi sulla macchina da monitorare.

Inoltre, è stato definito il comando restart_barnyard, il cui scopo è quello di eseguire l’event handler in questione:

# 'restart_barnyard' command definition
define command {
        command_name      restart_barnyard
        command_line      /usr/lib64/nagios/plugins/eventhandlers/restart_barnyard $SERVICESTATE$ $SERVICESTATETYPE$ $SERVICEATTEMPT$
}

Ho quindi riavviato Nagios per rendere effettive le suddette modifiche:

[root@NMS]# service nagios reload

Contenuto dell’event handler (restart_barnyard)

Una volta completata la fase preliminare relativa alla configurazione del SO e dell’NMS, mi sono dedicato alla creazione dell’event handler vero e proprio (che ho chiamato, molto semplicemente, restart_barnyard). Esso presenta il seguente contenuto:

#!/bin/bash

case "$1" in
OK)
        ;;
WARNING)
        ;;
UNKNOWN)
        ;;
CRITICAL)
       case "$2" in
                SOFT)
                        case "$3" in
                        3)
                                echo -n "Restarting barnyard2 service (3rd soft critical state)..."
                                /usr/bin/sudo /sbin/service barnyard2 restart
                                ;;
                                esac
                        ;;
                HARD)
                        echo -n "Restarting barnyard2 service..."
                        /usr/bin/sudo /sbin/service barnyard2 restart
                        ;;
                esac
                ;;
        esac

exit 0

ovvero non fa altro che riavviare il servizio in oggetto nel caso del terzo critical state (soft) o del quarto critical state (hard).

L’ho quindi reso eseguibile:

[root@NMS]# chmod +x restart_barnyard

e l’ho salvato all’interno della dir /usr/lib64/nagios/plugins/eventhandlers:

[root@NMS]# mv restart_barnyard /usr/lib64/nagios/plugins/eventhandlers

Test di funzionamento

Infine, ho testato il tutto semplicemente arrestando il servizio barnyard2:

[root@NMS]# service barnyard2 stop

verificando che Nagios svolgesse tutta la trafila per ritirarlo su in modo automatico:

[root@NMS]# tail -f /var/log/nagios/nagios.log

il cui output mi ha mostrato le diverse fasi di passaggio dallo stato CRITICAL allo stato OK:

[1448964811] SERVICE EVENT HANDLER: localhost;Barnyard2 Service Status;CRITICAL;SOFT;3;restart_barnyard
[1448965026] SERVICE ALERT: localhost;Barnyard2 Service Status;CRITICAL;HARD;4;PROCS CRITICAL: 0 processes with command name 'barnyard2'
[1448965026] SERVICE EVENT HANDLER: localhost;Barnyard2 Service Status;CRITICAL;HARD;4;restart_barnyard
[1448965313] SERVICE ALERT: localhost;Barnyard2 Service Status;OK;HARD;4;PROCS OK: 2 processes with command name 'barnyard2'
[1448965313] SERVICE EVENT HANDLER: localhost;Barnyard2 Service Status;OK;HARD;4;restart_barnyard

Inoltre, digitando il comando:

[root@NMS]# ps aux | grep barn

ho visualizzato i processi di barnyard2 durante il loro avvio da parte dell’event handler:

nagios    2799  0.0  0.0 108208  1352 ?        S    11:17   0:00 /bin/bash /usr/lib64/nagios/plugins/eventhandlers/restart_barnyard CRITICAL HARD 4
root      2800  0.1  0.1 189744  3392 ?        S    11:17   0:00 /usr/bin/sudo /sbin/service barnyard2 restart
root      2803  0.0  0.0 106460  1680 ?        S    11:17   0:00 /bin/sh /sbin/service barnyard2 restart
root      2809  0.0  0.0 108568  1868 ?        S    11:17   0:00 /bin/sh /etc/init.d/barnyard2 restart
root      3194 65.8  1.2  92668 40796 ?        Rs   11:18   1:06 barnyard2 -D -c /etc/snort/barnyard2eth0.conf -d /var/log/snort/eth0 -w /var/log/snort/eth0/barnyard2.waldo -l /var/log/snort/eth0 -a /var/log/snort/eth0/archive -f snort.log --pid-path /var/run
root      3196  0.0  0.0 108200  1284 ?        S    11:18   0:00 /bin/bash -c ulimit -S -c 0 >/dev/null 2>&1 ; barnyard2 -D -c /etc/snort/barnyard2eth1.conf -d /var/log/snort/eth1 -w /var/log/snort/eth1/barnyard2.waldo -l /var/log/snort/eth1 -a /var/log/snort/eth1/archive -f snort.log --pid-path /var/run
root      3197 61.4  0.2  58856  7808 ?        R    11:18   1:01 barnyard2 -D -c /etc/snort/barnyard2eth1.conf -d /var/log/snort/eth1 -w /var/log/snort/eth1/barnyard2.waldo -l /var/log/snort/eth1 -a /var/log/snort/eth1/archive -f snort.log --pid-path /var/run
root      3710  0.0  0.0 103268   864 pts/2    S+   11:20   0:00 grep barn

E’ tutto. Alla prossima.

Modifica delle ACL NTFS mediante PowerShell

Scenario

Una macchina con a bordo Windows Server 2008 R2 che funge da Web server (IIS7). Si vuole fare in modo che gli utenti possano effettuare l’upload (mediante un form opportunamente creato) di immagini e file di vario genere.

Problema

Le ACL NTFS relative alla root directory di IIS (ovvero C:\inetpub\wwwroot) non consentono le operazioni di modifica agli utenti Web anonimi (appartenenti al gruppo IIS_IUSRS), ergo qualsiasi tentativo di upload avrà esito negativo. Inoltre, l’alberatura delle sottodirectory è abbastanza complessa ed è qualcosa del tipo /nomesubdir/immagini, in cui nomesubdir è variabile (ce ne sono circa un migliaio), mentre immagini è la dir di destinazione degli upload (sulla quale bisogna garantire i permessi di modifica).

Soluzione

La prima soluzione che viene in mente prevede per lo più tanta pazienza ed un lavoro certosino da attuare, fondamentalmente, in 2 passaggi: l’accesso manuale a ciascuna subdir e la modifica delle ACL NTFS per la directory immagini ivi contenuta.

La seconda soluzione è certamente più rapida e smart: creare uno scrip PowerShell in grado di modificare le suddette ACL per tutte le directory immagini poste all’interno delle subdir.

powershellEcco lo scrip:

$Acl = Get-Acl "C:\inetpub\wwwroot\*\immagini"
$Ar = New-Object  system.security.accesscontrol.filesystemaccessrule("IIS_IUSRS","Modify","ContainerInherit, ObjectInherit", "None","Allow")
foreach($Ac in $Acl)
{
    $Ac.SetAccessRule($Ar)
    Set-Acl "C:\inetpub\wwwroot\*\immagini" $Ac
}

Esso prevede, in soldoni, 2 fasi: la prima in cui vengono identificati i permessi relativi alla directory immagini presente in ciascuna subdir  (mediante la cmdlet Get-Acl); la seconda in vengono definiti i nuovi permessi per il gruppo IIS_IUSRS, applicandoli a tutte le  immagini (ed ai file in esse contenuti).

Rollback

Naturalmente la modifica dei permessi NTFS associati a file e cartelle è sempre un’operazione abbastanza invasiva e delicata, ergo è opportuno garantirsi la possibilità di ripristinare la situazione iniziale (ovvero quella precedente alle suddette modifiche).

Ecco lo scrip in grado di effettuare il rollback dei permessi:

$Acl = Get-Acl "C:\inetpub\wwwroot\*\immagini"
$Ar = New-Object  system.security.accesscontrol.filesystemaccessrule("IIS_IUSRS","Modify","ContainerInherit, ObjectInherit", "None","Allow")
foreach($Ac in $Acl)
{
    $Ac.RemoveAccessRuleAll($Ar)
    Set-Acl "C:\inetpub\wwwroot\*\immagini" $Ac
}

La logica è sempre la stessa, l’unica variazione riguarda la funzione RemoveAccessRuleAll($Ar) che ha sostituito la SetAccessRule($Ar) utilizzata in precedenza.

Alla prossima.

CentOS 6: configurare Nagios per la ricezione dei security alert

In questo post abbiamo visto come configurare e gestire i check passivi su Nagios. Ora vedremo come utilizzare tale configurazione per ricevere i security alert relativi agli host monitorati.

nagiosIngredienti

Ovviamente il primo ingrediente è l‘NMS (Nagios), integrato ad NRDP Server. Sulle macchine monitorate è installato NRDP Client, il quale dovrà interagire con un log analyzer in tempo reale (swatch).

Scenario

La topologia utilizzata nell’ambito di questa guida è abbastanza minimale e prevede un server su cui è installato Nagios ed un altro server (da monitorare) che funge da antispam. Si vuole fare in modo che i security alert generati da quest’ultimo vengano inoltrati all’NMS, il quale dovrà successivamente aggiornare lo stato dei check passivi di riferimento, inviando opportune notifiche ai sysadmin.

Configurazione di Nagios

La configurazione dell’NMS è del tutto simile a quella vista qui, ma la riporto per completezza:

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Access Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Domain Not Found
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Cannot Find Your Reverse Hostname
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam SPF Reject
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Relay Access Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Amavis Blocked
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Spam
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Spammy
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

Il comando check_passive, invece, è così definito:

# 'check_passive' command definition
define command{
        command_name check_passive
        command_line $USER1$/check_dummy 0 "No Security Alert"
}

La logica di funzionamento è banale: se un security alert non viene ricevuto entro 600 secondi significa che non vi sono eventi rilevanti e, di conseguenza, lo stato del check passivo tornerà ad essere OK. Inoltre, poichè l’alert deve generare immediatamente una notifica (HARD STATE), è necessario settare il campo max_check_attempts a 1 (anzichè 4 che è il valore di default).

Come ultimo step ricarichiamo la configurazione di Nagios:

[root@NMS ~]# service nagios reload

Configurazione del server antispam

Una volta configurato l’NMS possiamo dedicarci alla configurazione del server da monitorare. In questo caso il lavoro sporco verrà svolto da swatch, il cui compito è quello di analizzare in tempo reale (tail -f) il contenuto del file di log relativo al servizio di antispam (/var/log/maillog), alla ricerca di determinati error code. Ad ogni error code corrisponderà un security alert specifico, e, una volta identificato, verrà richiamato NRDP Client per l’invio dell’evento a Nagios.

Ma bando alle ciance ed ecco la configurazione di swatch:

#SMTP Domain not found
watchfor  /Domain not found/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Domain Not Found' --output\='$_'"

#SMTP Sender address rejected
watchfor  /Access denied/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Access Denied' --output\='$_'"

#SMTP Cannot find your reverse hostname
watchfor  /cannot find your reverse hostname/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Cannot Find Your Reverse Hostname' --output\='$_'"

#SMTP SPF reject
watchfor  /openspf/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam SPF Reject' --output\='$_'"

#SMTP Relay access denied/
watchfor /Relay access denied/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Relay Access Denied' --output\='$_'"

#SMTP Amavis blocked
watchfor /Blocked/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Amavis Blocked' --output\='$_'"

#SMTP Spam
watchfor /SPAM/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Spam' --output\='$_'"

watchfor /SPAMMY/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Spammy' --output\='$_'"

Nella fattispecie, NRDP Client viene richiamato mediante la direttiva exec, facendo attenzione al carattere = (utilizzato per specificare i dati da inviare a Nagios), poichè trattasi di un carattere speciale per swatch (che quindi dovrà essere munito di escape \).

A questo punto lanciamo il comando:

[root@server-antispam ~]# swatch -c /etc/swatch.conf -t /var/log/maillog --daemon

ed inseriamolo all’interno del file /etc/rc.local (per automatizzare l’esecuzione del suddetto applicativo dopo ogni riavvio).

Test

Per testare il corretto funzionamento della configurazione appena riportata, possiamo, ad esempio, generare un error code 450 (cannot find your reverse hostname).
Lanciamo dunque il comando:

[root@client ~]# telnet server-antispam.vostrodominio.com 25

ed inviamo al server antispam le seguenti direttive:

helo server-antispam.vostrodominio.com
250 server-antispam
mail from:<n.latella@ciao.it>
250 2.1.0 Ok
rcpt to:<n.latella@ciao.ot>
450 4.7.1 Client host rejected: cannot find your reverse hostname, [5.170.*.*]

A questo punto il servizio Antispam Cannot Find Your Reverse Hostname dovrebbe generare un WARNING, segnalando quanto avvenuto mediante email.

Nei prossimi post vedremo come configurare Nagios per la ricezione delle trap SNMP.

Alla prossima.

Breve guida su SElinux

Premesso che per i server esposti direttamente su Internet la sicurezza non è mai troppa, è sempre buona norma abilitare, lato sistema operativo, dei meccanismi stringenti per il controllo degli accessi.

In particolare, le principali tecniche di questo tipo sono 3, ovvero:

1) DAC (Discretionary Access Control), in cui è l’owner (proprietario) del file o della directory a decidere chi (e come) può averne accesso;

2) RBAC (Role Based Access Control), in cui i permessi associati a ciascun utente sono strettamente correlati al loro ruolo (ne sono un tipico esempio le view della CLI relativa ai dispositivi Cisco, oppure i meccanismi di AAA previsti nell’ambito del protocollo TACACS+);

3) MAC (Mandatory Access Control), in cui è il sistema operativo stesso a decidere chi (e come) può avere accesso ad un file o ad una directory (tale concetto, nel caso dei sistemi *nix, è estendibile anche a socket, thread e processi, poichè in Unix everything is a file). SElinux fa parte di questa categoria.

Logica di funzionamento

SElinux non fa altro che associare un security context  a ciascun elemento che compone il sistema operativo. Il security context presenta il seguente formato:

user:role:domain:level

ad esempio:

system_u:object_r:nagios_spool_t:s0

e l’interazione è consentita (di default) solo tra gli elementi appartenenti al medesimo contesto.

selinux-penguin-new_medium

Inoltre, il file di log in cui vengono salvati gli eventi generati da SElinux è audit.log, presente all’interno della directory /var/log/audit. Analizzando questo file è possibile capire se un determinato processo (o utente) che cerca di accedere ad un determinato file (o directory) è stato autorizzato o bloccato. Un esempio di accesso bloccato è il seguente:

type=AVC msg=audit(1443184099.487:4197): avc:  denied  { open } for  pid=15608 comm="submit_check_re" name="nagios.cmd" dev=dm-0 ino=394145 scontext=system_u:system_r:snmpd_t:s0 tcontext=system_u:object_r:nagios_spool_t:s0 tclass=fifo_file type=SYSCALL msg=audit(1443184099.487:4197): arch=c000003e syscall=2 success=no exit=-13 a0=1b8f490 a1=401 a2=1b6 a3=76 items=0 ppid=15607 pid=15608 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="submit_check_re" exe="/bin/bash" subj=system_u:system_r:snmpd_t:s0 key=(null)

Analizzando il suddetta entry si possono notare alcuni elementi distintivi:

type=AVC

ovvero l’azione bloccata è stata effettuata a livello di kernel (AVC) e non di user space (USER-AVC);

msg=audit(1443184099.487:4197):

che rappresenta lo Unix timestamp associato all’evento;

avc:  denied  { open }

in cui viene indicata l’azione che è stata bloccata (open);

scontext=system_u:system_r:snmpd_t:s0

ovvero il source security context;

tcontext=system_u:object_r:nagios_spool_t:s0

in cui viene specificato il target security context;

tclass=fifo_file

ovvero la target class (che può essere file, directory, fifo_file, ecc – vedi qui per approfondire).

Source security context, target security context e target class sono gli elementi essenziali per la creazione delle regole SElinux (allow o deny). Tali regole andranno a popolare un file con estensione *.te (type enforcement).

Modalità di funzionamento

SElinux prevede 2 modalità di funzionamento, enforcing e permessive. Quest’ultima è molto utile quando si vuole fare un po’ di troubleshooting (ad esempio per capire se una determianta applicazione non sta funzionando correttamente proprio a causa di qualche regola di tipo MAC), poichè in tal caso non verrà bloccato nulla ma verranno registrate (all’interno di audit.log)  tutte quelle operazioni che stanno violando una o più policy.

E’ possibile passare da una modalità all’altra utilizzando il comando setenforce, dove:

[root@server ~]# setenforce 1

abilita la modalità enforcing, mentre:

[root@server ~]# setenforce 0

abilitata la modalità permessive.

Inoltre, per visualizzare la modalità di funzionamento attuale di SElinux è necessario digitare il comando:

[root@server ~]# getenforce

o, in alternativa (ottenendo un output più dettagliato):

[root@server ~]# sestatus

Occorre precisare che la modalità enforcing prevede alcune sotto-modalità di funzionamento (se così le si può definire), ovvero:

1) targeted (quella da me utilizzata), in cui solo determinati processi sono protetti da SElinux (tutto il resto viene marcato come unconfined);

2) strict, in cui tutte le operazioni che avvegono a livello di SO sono controllate da SElinux;

3) mls (Multi-level security), in cui (e lo dice il nome stesso) sono previsti diversi livelli di sicurezza (unclassified, confidential, secret e top secret – vedi qui per ulteriori dettagli);

4) mcs (Multi-category security), in cui l’utente può associare ai propri file una determinata categoria (in base alla quale il SO deciderà chi e come potrà averne accesso).

Per definire la modalità di funzionamento in fase di boot, occorre editare il file /etc/sysconfig/selinux, il cui contenuto dovrà essere simile al seguente:

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

Visualizzazione del security context

Per visualizzare il security context associato a file o directory basta utilizzare il classico comando ls, affiancato dalla flag Z. Ad esempio:

[root@server ~]# ls -ilahZ

il cui output sarà simile al seguente:

dr-xr-x---. root root system_u:object_r:admin_home_t:s0 .
dr-xr-xr-x. root root system_u:object_r:root_t:s0      ..
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 acl_home

Per ciò che concerne i processi, si può, invece, utilizzare il comando:

[root@server ~]# ps auxZ

il cui output potrebbe contenere:

system_u:system_r:postfix_pickup_t:s0 postfix 31620 0.0  0.1 81416 3820 ?      S    11:20   0:00 pickup -l -t fifo -u

Visualizzazione e gestione delle policy

Prima di tutto occorre precisare che SElinux può gestire l’interazione tra elementi appartenenti a security context differenti attraverso due metodi:

1) utilizzo delle variabili booleane;

2) utilizzo dei moduli.

Per visualizzare i valori associati alle variabili booleane occorre lanciare il comando:

[root@server ~]# getsebool -a

mentre per modificare il valore di una variabile (da true a false e viceversa), è necessario utilizzare il comando:

[root@server ~]# setsebool <nomevariabile> <0|1>

Da notare che una modifica può essere fatta in modo permanente avvalendosi della flag -P, oppure editando il contenuto del file /etc/selinux/SELINUXTYPE/booleans.

Il comando che ci consente di visualizzare tutte le policy presenti sul sistema è il seguente:

[root@server ~]# sesearch --all

utile anche per filtrare ulteriormente le suddette policy, visualizzando, ad esempio, solo quelle di tipo allow:

[root@server ~]# sesearch --allow

E’ anche possibile listare i moduli attualmente in uso:

[root@server ~]#  semodule -l

Creazione di regole custom

Per effettuare tale operazione si possono seguire 2 strade: avvalersi di un’apposita utility che automatizza il tutto (audit2allow) oppure creare delle regole “a mano”. Personalmente, credo che la seconda opzione sia la più sicura, in quanto ci permette di avere un controllo maggiore su ciò che deve essere effettivamente consentito.

Per utilizzare audit2allow è necessario, dapprima, scaricare il pacchetto policycoreutils-python mediante yum:

[root@server ~]# yum install policycoreutils-python

A questo punto, è possibile avvalersi dell’utility in questione per listare il contenuto del file audit.log, ottenendo una descrizione dettagliata di quanto sta avvenendo (attraverso la flag -w):

[root@server ~]# audit2allow -a -w

Come accennavo in precedenza, tale applicativo può essere utilizzato per creare dei moduli custom da dare in pasto a SElinux. Ad esempio, se volessimo consentire l’interazione tra un oggetto appartenente al dominio httpd_t ed uno appartenente al dominio nagios_t, potremmo utilizzare il comando:

[root@server ~]# grep httpd_t | audit2allow -a -M <nomemodulo.pp>

Una volta creato il modulo lo si può installare lanciando il comando:

[root@server ~]# semodule -i <nomemodulo.pp>

Una nota a margine di quanto appena detto: se il file audit.log viene popolato costantemente da nuove entry, la creazione del modulo custom mediante la suddetta utility richiederà molto (per non dire troppo) tempo. Anche per questo motivo preferisco creare “a mano” le regole che andranno a formare i miei moduli personalizzati.

Per ottenere in maniera semi-automatica le regole da inserire all’interno dei suddetti moduli è sufficiente digitare il comando:

[root@servers]# audit2allow -i /var/log/audit/audit.log

il cui output sarà simile al seguente:

#============= nagios_log_t ==============

#!!!! This avc is allowed in the current policy
allow mrtg_t nagios_log_t:file { open };

Alla luce di ciò,  il contenuto di un modulo (da me creato) necessario per consentire l’accesso in lettura da parte di MRTG al file status.dat di Nagios (affinchè possano essere monitorate le prestazioni dell’NMS in questione), sarà il seguente:

module permitmrtgnagios 1.0;

require {
        type mrtg_t;
        type nagios_log_t;
        class file { open };
}

#============= nagios_log_t ==============

#!!!! This avc is allowed in the current policy
allow mrtg_t nagios_log_t:file { open };

Il suddetto contenuto si riferisce ad un file con estensione *.te. Tale file va compilato lanciando il comando:

[root@server ~]# checkmodule -M -m -o permitmrtgnagios.mod permitmrtgnagios.te

e successivamente:

[root@server ~]# semodule_package -o permitmrtgnagios.pp -m  permitmrtgnagios.mod

Una volta creato il modulo vero e proprio (con estensione *.pp), si può procedere con la sua installazione:

[root@server ~]# semodule -i permitmrtgnagios.pp

Altro consiglio: scegliete un prefisso (o suffisso) standard per i moduli da voi creati, in modo da identificarli facilmente tra quelli già presenti sul sistema (ed impiegati da SElinux). Inoltre, nel caso in cui venga installato un modulo già presente ed utilizzato, quest’ultimo verrà sovrascritto (motivo più che valido per scegliere dei nomi con un costrutto particolare e standard).

Infine, un avvertimento: alcune azioni di blocco effettuate da SElinux non vengono loggate all’interno del file di audit (donotaudit), principalmente per evitare che quest’ultimo raggiunga dimensioni eccessive. Per disabilitare temporaneamente tale opzione è necessario utilizzare il comando:

[root@server ~]# semodule -BD

mentre per riabilitarla nuovamente occorre digitare:

[root@server ~]# semodule -B

E’ tutto. Da adesso in poi SElinux non dovrebbe più essere un mistero.

Alla prossima.

CentOS 6: realizzare un network intrusion detection system open source – Parte 3

Dopo aver installato e configurato snort, barnyard2, pulledpork e MySQL (vedi qui e qui), ora vedremo come installare l’interfaccia Web del nostro sistema NIDS, ovvero Snorby.

Poichè tale interfaccia si basa su Ruby, è necessario predisporre il nostro sistema per il supporto del linguaggio di scripting in questione.

snorby-dashboard

Preparazione della macchina

Per prima cosa installiamo i software prerequisiti, mediante i comandi:

yum -y groupinstall "Development Tools"

yum install -y openssl-devel readline-devel libxml2-devel libxslt-devel mysql mysql-devel mysql-libs mysql-server urw-fonts libX11-devel libXext-devel qconf fontconfig-devel libXrender-devel unzip

yum -y install xz urw-fonts libXext openssl-devel libXrender

Successivamente, scarichiamo ed installiamo ImageMagick , per la creazione di immagini bitmap, e wkhtmltopdf, per la conversione delle pagine HTML in PDF (funzionalità indispensabile durante la generazione dei report):

cd /usr/local/src

wget ftp://ftp.fifi.org/pub/ImageMagick/ImageMagick-6.8.9-6.tar.gz

tar -xvf ImageMagick-6.8.9-6.tar.gz

cd ImageMagick-6.8.9-6

./configure

make

make install

ldconfig 

cd ..

wget http://sourceforge.net/projects/wkhtmltopdf/files/0.12.1/wkhtmltox-0.12.1_linux-centos6-amd64.rpm/download

rpm -Uvh wkhtmltox-0.12.1_linux-centos6-amd64.rpm

Adesso scarichiamo rvm, attraverso il quale sarà possibile installare la versione di Ruby compatibile con Snorby (ovvero la 1.9.3, che, purtroppo, è ormai obsoleta e non più mantenuta):

curl -L get.rvm.io | bash -s stable

Installiamo dunque Ruby e facciamo in modo che il sistema utilizzi la versione 1.9.3 come default:

rvm install 1.9.3

rvm use --default 1.9.3

Ora, utilizzando il packet manager di Ruby (ovvero gem), procediamo con l’installazione di Rails (il framework) e di passenger (necessario per integrare Snorby e Apache):

gem install rails

gem install passenger

passenger-install-apache2-module

Installiamo alcuni pacchetti prerequisiti:

gem install devise_cas_authenticatable -v '1.1.0'

e

gem install bundler

In particolare, quest’ultimo si occupa di gestire le dipendenze tra i gem (ed è il software responsabile della creazione dei file Gemfile e Gemfile.lock).

Installazione e configurazione di Snorby

Creiamo la directory nella quale ospitare Snorby:

mkdir -p /var/www/html/snorby

e scarichiamo l’applicazione vera e propria:

cd /var/www/html/snorby

wget -O snorby.zip --no-check-certificate https://github.com/Snorby/snorby/archive/master.zip

Scompattiamo l’archivio, posizioniamoci nella directory snorby-master e spostiamone il contenuto all’interno di /var/www/html/snorby:

unzip snorby.zip

cd snorby-master/

mv * ../

Modifichiamo ora il contenuto del file Gemfile, sostituendo le direttive di default per rake, json e devise_cas_authenticatable con le seguenti:

gem 'rake', '0.9.2.2'
gem 'json', '~> 1.8.3'
gem 'thin'

gem 'devise_cas_authenticatable',  '~> 1.1.0'

Inoltre, è necessario inserire la direttiva gem ‘thin’ subito dopo gem ‘json’, commentando quella dopo gem “letter_open”:

gem 'json', '~> 1.8.3'
gem 'thin'

group(:development) do
     gem "letter_opener"
   # gem 'thin'

Discorso simile vale per il file Gemfile.lock, in cui bisogna modificare le direttive rake e json nel seguente modo:

rake (0.9.2.2)

json (1.8.3)

Lanciamo il comando bundle install in modo da installare i pacchetti gem (con le relative dipendenze) definiti all’interno del Gemfile precedentemente editato:

bundle install

Eliminiamo la dir snorby-master (ormai vuota) e passiamo alla configurazione di Snorby:

rm -rf snorby-master/

cd config

cp snorby_config.yml.example snorby_config.yml

nano snorby_config.yml

definendo la giusta timezone:

time_zone: Europe/Rome

A questo punto possiamo configurare la connessione al database, editando il file config/database.yml:

cd ..

cp config/database.yml.example config/database.yml

nano config/database.yml

il cui contenuto sarà simile al seguente:

# Snorby Database Configuration
#
# Please set your database password/user below
# NOTE: Indentation is important.
#
snorby: &snorby
  adapter: mysql
  username: vostrouser
  password: "vostrapassword" # Example: password: "s3cr3tsauce"
  host: localhost

development:
  database: snorby
  <<: *snorby

test:
  database: snorby
  <<: *snorby

production:
  database: snorby

Avviamo l’applicazione (con finalità di test), mediante i comandi:

rake snorby:setup

rails server thin -e production

da lanciare all’interno della dir /var/www/html/snorby ed il cui output dovrebbe essere simile al seguente:

=> Booting Thin
=> Rails 3.1.12 application starting in production on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on 0.0.0.0:3000, CTRL+C to stop

http://ip:3000/users/login

Provando ora a connetterci (con il nostro browser) a http://ip:3000/users/login dovremmo riuscire a visualizzare l’interfaccia di Snorby (con il relativo form per il login, dove l’email di default è snorby@example.com e la password è semplicemente snorby).

Integrazione tra Snorby e Apache

Come già affermato in precedenza, il modulo di Apache che consente al nostro server Web di interfacciarsi con le applicazioni scritte in Ruby prende il nome di passenger.

Per prima cosa occorre dunque configurare il suddetto modulo:

nano /etc/httpd/conf.d/mod_passenger.conf

il cui contenuto dovrà essere:

LoadModule passenger_module /usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-5.0.16/buildout/apache2/mod_passenger.so

PassengerRoot /usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-5.0.16
PassengerDefaultRuby /usr/local/rvm/gems/ruby-1.9.3-p551/wrappers/ruby

Infine, modifichiamo il file di configurazione di Apache (/etc/httpd/conf/httpd.conf), creando un virtual host opportuno (in ascolto sulla porta TCP 82):

Listen 82

<VirtualHost *:82>
     Servername vostroserver.vostrodominio.com
     DocumentRoot /var/www/html/snorby/public
     <Directory /var/www/html/snorby/public>
        Order deny,allow
        Allow from all
        Options -MultiViews
        AuthName "Snorby Access"
        AuthType Basic
        AuthUserFile /etc/snorby/passwd
        Require valid-user
    </Directory>
</VirtualHost>

Tale virtual host richiede l’autentica HTTP, ergo occorre creare il file in cui verranno salvate le coppie username/password da utilizzare:

mkdir -p /etc/snorby

htpasswd -c /etc/snorby/passwd vostroutente

Infine, riavviamo Apache:

service httpd reload

ed abbiamo finito.

Alla prossima.

CentOS 6: realizzare un network intrusion detection system open source – Parte 2

In questo post ho mostrato come configurare il software che funge da sensore, ovvero snort. Adesso vedremo come installare e configurare pulledpork (che si occuperà dell’aggiornamento delle firme) e barnyard2 (per il salvataggio degli allarmi all’interno di un DB).

Barnyard2Installazione e configurazione di pulledpork

Per prima cosa occorre installare i prerequisiti, ovvero perl-libwww-perl perl-Crypt-SSLeay e perl-Archive-Tar:

yum -y install perl-libwww-perl perl-Crypt-SSLeay perl-Archive-Tar

Posizioniamoci nella dir /usr/local/src  e scarichiamo l’applicativo in questione (scritto in Perl):

wget https://pulledpork.googlecode.com/files/pulledpork-0.7.0.tar.gz

per poi scompattare l’archivio, rendere lo scrip eseguibile e copiarlo all’interno di /usr/sbin (assegnandogli i giusti privilegi):

tar -xvf pulledpork-0.7.0.tar.gz
cd pulledpork-0.7.0
chmod +x pulledpork.pl
cp pulledpork.pl /usr/sbin
chmod 755 /usr/sbin/pulledpork.pl

A questo punto possiamo copiare i file *.conf (presenti nella directory etc) all’interno di /etc/snort, con il successivo editing dei permessi:

cd etc
cp * /etc/snort
chown -R snort:snort /etc/snort

Ora modifichiamo il contenuto del file /etc/snort/pulledpork.conf, apportando le seguenti modifiche:

snort_path=/usr/sbin/snort
config_path=/etc/snort/snort.conf
distro=Centos-5-4
rule_path=/etc/snort/rules/snort.rules
out_path=/etc/snort/rules/
sid_msg=/etc/snort/sid-msg.map
black_list=/etc/snort/rules/black_list.rules
#IPRVersion=/usr/local/etc/snort/rules/iplists
enablesid=/etc/snort/enablesid.conf
dropsid=/etc/snort/dropsid.conf
disablesid=/etc/snort/disablesid.conf
modifysid=/etc/snort/modifysid.conf

rule_url=https://www.snort.org/reg-rules/|snortrules-snapshot-2975.tar.gz|<vostro oinkcode>
rule_url=https://s3.amazonaws.com/snort-org/www/rules/community/|community-rules.tar.gz|Community
rule_url=http://labs.snort.org/feeds/ip-filter.blf|IPBLACKLIST|open
rule_url=https://www.snort.org/reg-rules/|opensource.gz|<vostro oinkcode>

Da notare che ho commentato la direttiva IPRVersion ed ho scelto un nome specifico per le blacklist (ovvero black_list.rules), in quando devono essere differenziate da quelle utilizzate da snort (reputation preprocessor). Per la precisione, il file black_list.rules non è altro che una lista piatta di indirizzi IP, a differenza del file blacklist.rules che possiede il tipico formato delle regole di snort (ad esempio alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS).

Testiamo adesso la configurazione di pulledpork mediante il comando:

pulledpork.pl -vv -c /etc/snort/pulledpork.conf -T -l

e se il relativo output contiene la stringa:

Fly Piggy Fly!

vuol dire che il suddetto applicativo sta funzionando correttamente. Creaiamo un task su crontab per eseguire l’update delle firme ogni notte:

nano /etc/crontab

il cui contenuto dovrà essere:

00 04 * * * root /usr/sbin/pulledpork.pl -c /etc/snort/pulledpork.conf && /sbin/service snortd restart

e passiamo alla configurazione di barnyard2.

Installazione e configurazione di barnyard2

Prima di cominciare occorre fare una premessa: il file di configurazione che daremo in pasto a barnyard2 può riferirsi ad una sola interfaccia. Ciò significa che dovremo creare un file di configurazione specifico per ciascuna interfaccia su cui i sensori (le istanze di snort) sono in ascolto, in modo tale che il loro output possa essere parsato (in modo indipendente) dalle due istanze distinte di barnyard2.

Come al solito, il primo step consiste nell’installazione del software necessario per la compilazione del suddetto applicativo:

yum install libtool

e successivamente, dopo esserci posizionati nella directory /usr/local/src, possiamo scaricare i sorgenti:

cd /usr/local/src
git clone git://github.com/firnsy/barnyard2.git

Compiliamo ed installiamo:

cd barnyard2
./autogen.sh
./configure --with-mysql --with-mysql-libraries=/usr/lib64/mysql/
make
make install

copiamo il file di configurazione di barnyard2 all’interno della directory /etc/snort

cp etc/barnyard2.conf /etc/snort

e modifichiamolo in base alle nostre esigenze:

config logdir: /var/log/snort
config interface:  eth0
config daemon
input unified2
output alert_full
config waldo_file: /var/log/snort/eth0/barnyard2-log.waldo
output log_tcpdump: tcpdump.log
output database: log, mysql, user=<vostrouser> password=<vostrapassword> dbname=snorby host=localhost

copiamo il suddetto file in barnyard2-eth0.conf ed in barnyard2-eth1.conf:

cp /etc/snort/barnyard2.conf /etc/snort/barnyard2-eth0.conf

cp /etc/snort/barnyard2.conf /etc/snort/barnyard2-eth1.conf

Modifichiamo quest’ultimo sostituendo le diciture:

config interface:  eth0

config waldo_file: /var/log/snort/eth0/barnyard2-log.waldo

con:

config interface:  eth1

config waldo_file: /var/log/snort/eth1/barnyard2-log.wald

Inoltre, per fare in modo che le due istanze di barnyard2 vengano avviate come “demone”, ho modificato il file di startup presente nella dir rpm, dopo averlo copiato in /etc/init.d ed averlo reso eseguibile:

cp rpm/barnyard2 /etc/init.d
chmod +x /etc/init.d/barnyard2

Di seguito riporto il contenuto del suddetto file, in cui sono presenti le modifiche da me effettuate:

#!/bin/sh
#
# Init file for Barnyard2
#
#
# chkconfig: 2345 60 60
# description:  Barnyard2 is an output processor for snort.
#
# processname: barnyard2
# config: /etc/sysconfig/barnyard2
# config: /etc/snort/barnyard.conf
# pidfile: /var/lock/subsys/barnyard2.pid

source /etc/rc.d/init.d/functions
source /etc/sysconfig/network

### Check that networking is up.
[ "${NETWORKING}" == "no" ] && exit 0

[ -x /usr/sbin/snort ] || exit 1
[ -r /etc/snort/snort.conf ] || exit 1

### Default variables
SYSCONFIG="/etc/sysconfig/barnyard2"

### Read configuration
[ -r "$SYSCONFIG" ] && source "$SYSCONFIG"

RETVAL=0
prog="barnyard2"
desc="Snort Output Processor"

start() {
        echo -n $"Starting $desc ($prog): "
        for INT in $INTERFACES; do
                echo " "
                echo "binding over $INT..."
                ARCHIVEDIR="$SNORTDIR/$INT/archive"
                WALDO_FILE="$SNORTDIR/$INT/barnyard2.waldo"
                if [ $INT == 'eth0' ];then
                BARNYARD_OPTS="-D -c $CONF1 -d $SNORTDIR/${INT} -w $WALDO_FILE -l $SNORTDIR/${INT} -a $ARCHIVEDIR -f $LOG_FILE $EXTRA_ARGS"
                elif [ $INT == 'eth1' ];then
                BARNYARD_OPTS="-D -c $CONF2 -d $SNORTDIR/${INT} -w $WALDO_FILE -l $SNORTDIR/${INT} -a $ARCHIVEDIR -f $LOG_FILE $EXTRA_ARGS"
                fi
                daemon $prog $BARNYARD_OPTS
        done
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
        return $RETVAL
}

stop() {
        echo -n $"Shutting down $desc ($prog): "
        killproc $prog
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && rm -f /var/run/barnyard2*
        return $RETVAL
}

restart() {
        stop
        start
}

reload() {
        echo -n $"Reloading $desc ($prog): "
        killproc $prog -HUP
        RETVAL=$?
        echo
        return $RETVAL
}

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        restart
        ;;
  reload)
        reload
        ;;
  condrestart)
        [ -e /var/lock/subsys/$prog ] && restart
        RETVAL=$?
        ;;
  status)
        status $prog
        RETVAL=$?
        ;;
  dump)
        dump
        ;;
  *)
        echo $"Usage: $0 {start|stop|restart|reload|condrestart|status|dump}"
        RETVAL=1
esac

exit $RETVAL

Il contenuto del file /etc/sysconfig/barnyard2 (in cui sono contenute le opzioni di avvio del demone) è, invece, il seguente:

LOG_FILE="snort.log"
SNORTDIR="/var/log/snort"
INTERFACES="eth0 eth1"
PIDPATH="/var/run"
CONF1=/etc/snort/barnyard2-eth0.conf
CONF2=/etc/snort/barnyard2-eth1.conf
EXTRA_ARGS="--pid-path /var/run"

Creiamo i file con estenzione *.waldo:

touch /var/log/snort/eth0/barnyard2-log.waldo

touch /var/log/snort/eth1/barnyard2-log.waldo

e facciamo in modo che il suddetto demone venga avviato in modo automatico dopo ogni riavvio della macchina:

chkconfig --add barnyard2

chkconfig barnyard2 on

Creaiamo ora il DB snorby (in cui barnyard2 dovrà salvare gli allarmi generati da snort) attraverso l’interfaccia a linea di comando di MySQL. I comandi da lanciare sono i seguenti:

create schema snorby;
grant all on snorby.* to vostrouser@localhost;
set password for vostrouser@localhost=password('vostrapassword');
use snorby;
source /usr/local/src/barnyard2/schemas/create_mysql
flush privileges;
exit

Prima di avviare il suddetto demone, occorre verificare che la sua priorità di avvio minore rispetto a quella di MySQL (valori bassi corrispondono a priorità alte). Infatti, in caso contrario, barnyard2 tenterà di parlare (via file mysql.sock) con il DBMS in questione, cosa impossibile nel caso in cui MySQL non sia ancora avviato (restituendoci, molto banalmente, l’errore file not found). In particolare, all’interno del codice associato al demone barnyard2 (da me modificato), è presente una priorità di avvio pari a 60 (definita tramite la direttiva chkconfig), mentre, a titolo di cronaca, la priorità di avvio relativa al demone mysqld è pari a 49.

Verifichiamo che tutto funzioni correttamente mediante i comandi:

barnyard2 -c /etc/snort/barnyard2-eth0.conf -d /var/log/snort/eth0 -f snort.log -w /var/log/snort/barnyard2-log.waldo -D

e

barnyard2 -c /etc/snort/barnyard2-eth1.conf -d /var/log/snort/eth1 -f snort.log -w /var/log/snort/barnyard2-log.waldo -D

per poi avviare il demone vero e proprio:

service barnyard2 start

A demone avviato, come ulteriore verifica, possiamo collegarci al DB snorby e lanciare la query:

select count(*) from events;

e se il valore restituito è > 0 vuol dire che barnyard2 e snort stanno operando correttamente.

Per ora è tutto. Nel prossimo post vedremo come installare e configurare Snorby (la Web GUI).

CentOS 6: realizzare un network intrusion detection system open source – Parte 1

Premessa

A differenza delle numerose guide cooked e dei vari howto che si possono trovare in rete, questo post (primo di una serie di 3), ha come scopo quello di illustrare in modo esaustivo i vari passi necessari per la realizzazione di una sistema NIDS.

Un po’ di teoria

Esistono diverse metodologie per difendere l’infrastruttura IT dai cyber attacchi, e, tutto sommato, le si può riassumere in 2 macro categorie, ovvero quelle attive e quelli passive. Per strategia difensiva attiva basti pensare ad un firewall, ad un antivirus oppure ad un IPS (Intrusion Preventetion System). Per contro, un tipico esempio di strategia difensiva di tipo passivo è rappresentato dai sistemi IDS (Intrusion Detection System), i quali possono agire localmente sulla macchina interessata (in tal caso parliamo di HIDS, ovvero Host IDS), oppure a livello di rete (in questo caso parliamo di NIDS, ovvero Network IDS).

I sistemi NIDS (detti anche sonde o sensori), non fanno altro che analizzare il traffico del segmento di rete a cui sono collegati (DMZ, LAN, Outside), alla ricerca di eventuali tentativi di attacco.

Solitamente, essi non vengono posizionati inline (come invece avviene per i sistemi IPS), ma sono collegati ad una porta dello switch configurata in mirror (monitor/span), sulla quale viene inoltrata una replica esatta di tutto il traffico passante per lo switch in questione. In questo modo un eventuale sovraccarico del sensore non comporterà automaticamente un rallentamento della rete in termini di throughput.

Topoligia

Poichè la rete sulla quale ho configurato il sistema NIDS è dotata di un firewall *nix che filtra tutto il traffico in ingresso ed in uscita, per questioni di budget e di praticità, ho ritenuto opportuno installare la sonda sulla macchina in questione. Va da se che l’analisi preventiva del carico computazionale a cui era soggetto il firewall ha restituito valori di overhead davvero irrisori, dunque l’installazione della sonda non ha comportato grossi cambiamenti in termini prestazionali.

NIDS

Ingredienti

Il software che fungerà da sensore prende il nome di snort. Inoltre, per aggiornare in modo automatico le signature/pattern degli attacchi verrà utilizzato pulledpork (a tutti gli effetti il successore di oinkmaster), mentre per convertire in formato SQL e salvare gli alert generati da snort all’interno di un DB (MySQL) verrà utilizzato barnyard2. Infine, verrà installata sulla macchina ospite un’interfaccia Web (GUI) scritta in Ruby ed accessibile tramite Apache, dalla quale poter estrapolare gli allarmi con le relative statistiche,  il cui nome è snorby (SNORt ruBY).

Occorre precisare che MySQL (DBMS) ed Apache (server Web) sono già installati sulla macchina ospite.

Installazione e configurazione di snort

Tale attività si divide in 3 step:

1) l’installazione dei software prerequisiti;

2) l’installazione delle librerie daq;

3) l’installazione e la configurazione di snort.

I software prerequisiti sono bison, flex, libpcap e libdnet e li si può installare utilizzando il packet manager di casa CentOS/Red Hat, ovvero yum:

yum install bison flex libpcap libpcap-devel libdnet libdnet-devel

Posizioniamoci nella directory /usr/local/src per poi scaricare, compilare ed installare le librerie daq (le quali servono a reindirizzare il network I/O ai software di “cattura” veri e propri, quali, ad esempio, PCAP, AFPACKET e simili):

wget https://www.snort.org/downloads/snort/daq-2.0.6.tar.gz
tar -xvf daq-2.0.6.tar.gz
cd daq-2.0.6
./configure
make
make install
ldconfig
cd ..

A questo punto possiamo scaricare ed installare snort:

wget https://www.snort.org/downloads/snort/snort-2.9.7.5.tar.gz
tar -xvf snort-2.9.7.5.tar.gz
cd snort-2.9.7.5
./configure
make
make install

Ad installazione completata creiamo utente e gruppo per il suddetto applicativo:

groupadd snort
useradd snort -g snort -s /sbin/nologin

per poi creare la directory su cui salvare i file di configurazione e le regole per la rilevazione delle intrusioni:

mkdir -p /etc/snort
mkdir -p /etc/snort/rules
cd etc
cp -R * /etc/snort
cd ..

Inoltre, scarichiamo le regole vere e proprie e salviamole all’interno della dir /etc/snort/rules:

wget https://www.snort.org/downloads/community/community-rules.tar.gz
tar -xvf community-rules.tar.gz
cd community-rules
cp * /etc/snort/rules
wget https://www.snort.org/downloads/registered/snortrules-snapshot-2975.tar.gz?oinkcode=<vostro oinkcode ricavabile dalla pagina Web di snort, previa registrazione>
tar -xvf nortrules-snapshot-2975.tar.gz
cd snortrules-snapshot-2975
cp -R preproc_rules/ /etc/snort/rules
cp -R so_rules/ /etc/snort/rules
cd rules
cp * /etc/snort/rules

Assegniamo il giusto owner alla directory /etc/snort:

chown snort:snort -R /etc/snort

e concentriamoci sulle dynamic rules (con relative librerie):

mkdir -p /usr/local/lib/snort_dynamicrules
chown -R snort:snort /usr/local/lib/snort_dynamicrules
cp /usr/local/src/so_rules/precompiled/RHEL-6-0/x86-64/2.9.7.5 /usr/local/lib/snort_dynamicrules
chmod -R 700 /usr/local/lib/snort_dynamicrules

Ora passiamo alla configurazione di snort:

nano /etc/snort/snort.conf

nella quale occorre definire le reti locali (HOME_NET), le reti esterne (EXTERNAL_NET), il pathname delle regole utilizzate da snort e quello delle whitelist/blacklist (basate sulla reputazione). Inoltre, bisogna definire il tipo di output generato da snort (il quale dovrà essere interpretabile da barnyard2).

Ecco uno stralcio delle modifiche apportate al file di configurazione di snort:

ipvar HOME_NET [192.168.1.0,192.168.12.0]
ipvar EXTERNAL_NET !$HOME_NET

var RULE_PATH /etc/snort/rules
var SO_RULE_PATH /etc/snort/rules/so_rules
var PREPROC_RULE_PATH /etc/snort/rules/preproc_rules

var WHITE_LIST_PATH /etc/snort/rules
var BLACK_LIST_PATH /etc/snort/rules

# Reputation preprocessor. For more information see README.reputation
preprocessor reputation: \
   memcap 500, \
   priority whitelist, \
   nested_ip inner, \
#   whitelist $WHITE_LIST_PATH/white_list.rules, \
   blacklist $BLACK_LIST_PATH/black_list.rules

output unified2: filename snort.log, limit 128

Creiamo la directory in cui snort dovrà salvare i log e gli allarmi, assegnandole il giusto owner:

mkdir -p /var/log/snort/
chown snort:snort /var/log/snort/

Infine, testiamo la configurazione di snort, lanciando il comando:

snort -T -i <interface-name> -u snort -g snort -c /etc/snort/snort.conf

il cui output (se non vi sono errori) dovrà contenere la seguente stringa:

Snort successfully validated the configuration!

Eseguire snort come demone

Per fare in modo che snort venga eseguito sulla macchina ospite come demone, occorre, prima di tutto, configurare le opzioni di avvio (definendole all’interno del file /etc/sysconfig/snort):

nano /etc/sysconfig/snort

il cui contenuto dovrà essere simile al seguente:

# /etc/sysconfig/snort
# $Id$

# All of these options with the exception of -c, which tells Snort where
# the configuration file is, may be specified in that configuration file as
# well as the command line. Both the command line and config file options
# are listed here for reference.

#### General Configuration

# What interface should snort listen on?  [Pick only 1 of the next 3!]
# This is -i {interface} on the command line
# This is the snort.conf config interface: {interface} directive
#INTERFACE=eth0
#
# The following two options are not directly supported on the command line
# or in the conf file and assume the same Snort configuration for all
# instances
#
# To listen on all interfaces use this:
INTERFACE=ALL
#
# To listen only on given interfaces use this:
#INTERFACE="eth1 eth2 eth3 eth4 eth5"

# Where is Snort's configuration file?
# -c {/path/to/snort.conf}
CONF=/etc/snort/snort.conf

# What user and group should Snort drop to after starting? This user and
# group should have very few privileges.
# -u {user} -g {group}
# config set_uid: user
# config set_gid: group
USER=snort
GROUP=snort

# Should Snort change the order in which the rules are applied to packets.
# Instead of being applied in the standard Alert->Pass->Log order, this will
# apply them in Pass->Alert->Log order.
# -o
# config order: {actions in order}
# e.g. config order: log alert pass activation dynamic suspicious redalert
PASS_FIRST=0

#### Logging & Alerting

# NOTE: NO_PACKET_LOG and BINARY_LOG, ALERTMODE, etc. are mutually
# exclusive. Use either NO_PACKET_LOG or any/all of the other logging
# options. But the more logging options use you, the slower Snort will run.

# Where should Snort log?
#
#-l {/path/to/logdir}
# config logdir: {/path/to/logdir}
LOGDIR=/var/log/snort

# config basename:
BASENAME=snort.log

# How should Snort alert? Valid alert modes include fast, full, none, and
# unsock.  Fast writes alerts to the default "alert" file in a single-line,
# syslog style alert message.  Full writes the alert to the "alert" file
# with the full decoded header as well as the alert message.  None turns off
# alerting. Unsock is an experimental mode that sends the alert information
# out over a UNIX socket to another process that attaches to that socket.
# -A {alert-mode}
# output alert_{type}: {options}
#ALERTMODE=full

# Should Snort dump the application layer data when displaying packets in
# verbose or packet logging mode.
# -d
# config dump_payload
DUMP_APP=1

# Should Snort keep binary (AKA pcap, AKA tcpdump) logs also? This is
# recommended as it provides very useful information for investigations.
# -b
# output log_tcpdump: {log name}
#BINARY_LOG=1

# Should Snort turn off packet logging?  The program still generates
# alerts normally.
# -N
# config nolog
NO_PACKET_LOG=0

# Print out the receiving interface name in alerts.
# -I
# config alert_with_interface_name
PRINT_INTERFACE=0

# When dumping the stats, what log file should we look in
SYSLOG=/var/log/messages

# When dumping the stats, how long to wait to make sure that syslog can
# flush data to disk
SECS=5

# To add a BPF filter to the command line uncomment the following variable
# syntax corresponds to tcpdump(8)
#BPF="not host 192.168.1.1"

# To use an external BPF filter file uncomment the following variable
# syntax corresponds to tcpdump(8)
# -F {/path/to/bpf_file}
# config bpf_file: /path/to/bpf_file
#BPFFILE=/etc/snort/bpf_file

a tal proposito, occorre precisare che è necessario commentare le direttive ALERTMODE e BINARY_LOG, altrimenti barnyard2 non sarà in grado di inserire gli allarmi all’interno del database.

Inoltre, poichè il sensore è posizionato inline, esso si trova in ascolto su tutte le interfacce della macchina (INTERFACE=ALL).

Di seguito riporto lo script che consente di demonizzare l’applicativo in questione:

#!/bin/sh
# $Id$
#
# snortd         Start/Stop the snort IDS daemon.
#
# chkconfig: 2345 40 60
# description:  snort is a lightweight network intrusion detection tool that \
#                currently detects more than 1100 host and network \
#                vulnerabilities, portscans, backdoors, and more.
#

# Source function library.
. /etc/rc.d/init.d/functions

# Source the local configuration file
. /etc/sysconfig/snort

#PID file location
PID=/var/run/snort

# Convert the /etc/sysconfig/snort settings to something snort can
# use on the startup line.
if [ "$ALERTMODE"X = "X" ]; then
   ALERTMODE=""
else
   ALERTMODE="-A $ALERTMODE"
fi

if [ "$USER"X = "X" ]; then
   USER="snort"
fi

if [ "$GROUP"X = "X" ]; then
   GROUP="snort"
fi

if [ "$BINARY_LOG"X = "1X" ]; then
   BINARY_LOG="-b"
else
   BINARY_LOG=""
fi

if [ "$CONF"X = "X" ]; then
   CONF="-c /etc/snort/snort.conf"
else
   CONF="-c $CONF"
fi

if [ "$INTERFACE"X = "X" ]; then
   INTERFACE="-i eth0"
else
   INTERFACE="-i $INTERFACE"
fi

if [ "$DUMP_APP"X = "1X" ]; then
   DUMP_APP="-d"
else
   DUMP_APP=""
fi

if [ "$NO_PACKET_LOG"X = "1X" ]; then
   NO_PACKET_LOG="-N"
else
   NO_PACKET_LOG=""
fi

if [ "$PRINT_INTERFACE"X = "1X" ]; then
   PRINT_INTERFACE="-I"
else
   PRINT_INTERFACE=""
fi

if [ "$PASS_FIRST"X = "1X" ]; then
   PASS_FIRST="-o"
else
   PASS_FIRST=""
fi

if [ "$LOGDIR"X = "X" ]; then
   LOGDIR=/var/log/snort
fi

# These are used by the 'stats' option
if [ "$SYSLOG"X = "X" ]; then
   SYSLOG=/var/log/messages
fi

if [ "$SECS"X = "X" ]; then
   SECS=5
fi

if [ ! "$BPFFILE"X = "X" ]; then
   BPFFILE="-F $BPFFILE"
fi

######################################
# Now to the real heart of the matter:

# See how we were called.
case "$1" in
  start)
        echo -n "Starting snort: "
        cd $LOGDIR
        if [ "$INTERFACE" = "-i ALL" ]; then
           for i in `cat /proc/net/dev|grep eth|awk -F ":" '{ print $1; }'`
           do
                mkdir -p "$LOGDIR/$i"
                chown -R $USER:$GROUP $LOGDIR
                daemon /usr/sbin/snort $ALERTMODE $BINARY_LOG $NO_PACKET_LOG $DUMP_APP -D $PRINT_INTERFACE -i $i -u $USER -g $GROUP $CONF -l $LOGDIR/$i 

$PASS_FIRST $BPFFILE $BPF
           done
        else
           # check if more than one interface is given
           if [ `echo $INTERFACE|wc -w` -gt 2 ]; then
              for i in `echo $INTERFACE | sed s/"-i "//`
                do
                  mkdir -p "$LOGDIR/$i"
                  chown -R $USER:$GROUP $LOGDIR
                  daemon /usr/sbin/snort $ALERTMODE $BINARY_LOG $NO_PACKET_LOG $DUMP_APP -D $PRINT_INTERFACE -i $i -u $USER -g $GROUP $CONF -l $LOGDIR/$i 

$PASS_FIRST $BPFFILE $BPF
             done
           else
              # Run with a single interface (default)
              daemon /usr/sbin/snort $ALERTMODE $BINARY_LOG $NO_PACKET_LOG $DUMP_APP -D $PRINT_INTERFACE $INTERFACE -u $USER -g $GROUP $CONF -l $LOGDIR 

$PASS_FIRST $BPFFILE $BPF --pid-path $PID
           fi
        fi
        touch /var/lock/subsys/snort
        echo
        ;;
  stop)
        echo -n "Stopping snort: "
        killproc snort
        rm -f /var/lock/subsys/snort
        echo
        ;;
  reload)
        echo "Sorry, not implemented yet"
        ;;
  restart)
        $0 stop
        $0 start
        ;;
  condrestart)
        [ -e /var/lock/subsys/snort ] && $0 restart
        ;;
  status)
        status snort
        ;;
  stats)
        TC=125                          # Trailing context to grep
        SNORTNAME='snort'               # Process name to look for

        if [ ! -x "/sbin/pidof" ]; then
           echo "/sbin/pidof not present, sorry, I cannot go on like this!"
           exit 1
        fi

        #Grab Snort's PID
        PID=`pidof -o $$ -o $PPID -o %PPID -x ${SNORTNAME}`

        if [ ! -n "$PID" ]; then        # if we got no PID then:
           echo "No PID found: ${SNORTNAME} must not running."
           exit 2
        fi

        echo ""
        echo "*******"
        echo "WARNING:  This feature is EXPERIMENTAL - please report errors!"
        echo "*******"
        echo ""
        echo "You can also run: $0 stats [long | opt]"
        echo ""
        echo "Dumping ${SNORTNAME}'s ($PID) statistics"
        echo "please wait..."

        # Get the date and tell Snort to dump stats as close together in
        # time as possible--not 100%, but it seems to work.
        startdate=`date '+%b %e %H:%M:%S'`

        # This causes the stats to be dumped to syslog
        kill -USR1 $PID

        # Sleep for $SECS secs to give syslog a chance to catch up
        # May need to be adjusted for slow/busy systems
        sleep $SECS

        if [ "$2" = "long" ]; then              # Long format
            egrep -B 3 -A $TC "^$startdate .* snort.*: ={79}" $SYSLOG | \
                grep snort.*:
        elif [ "$2" = "opt" ]; then             # OPTimize format
           # Just show stuff useful for optimizing Snort
            egrep -B 3 -A $TC "^$startdate .* snort.*: ={79}" $SYSLOG | \
                egrep "snort.*: Snort analyzed |snort.*: dropping|emory .aults:"
        else                                    # Default format
            egrep -B 3 -A $TC "^$startdate .* snort.*: ={79}" $SYSLOG | \
                grep snort.*: | cut -d: -f4-
        fi
        ;;
  *)
        echo "Usage: $0 {start|stop|reload|restart|condrestart|status|stats (long|opt)}"
        exit 2
esac

exit 0

Copiamo il binario di snort nella dir /usr/sbin:

cp /usr/local/bin/snort /usr/sbin/

e rendiamo il suddetto scrip eseguibile, per poi avviarlo e fare in modo che venga eseguito automaticamente dopo ogni riavvio della macchina:

chmod +x /etc/init.d/snortd
chkconfig --add snortd
chkconfig snortd on

Per ora abbiamo finito. Nel prossimo post vedremo come installare e configurare pulledpork e barnyard2.

A presto.