Archivi tag: dbms

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).

L’importanza dell’ora di sistema per un DBMS

Se avete intenzione di modificare la data o l’ora di un sistema che ospita un DBMS (oppure entrambe) tenete bene a mente quanto segue: “Spostare il datetime in avanti non dovrebbe causare grossi problemi, ma spostarlo indietro potrebbe comportare il crash del DBMS o, ancora peggio, l’inconsistenza dei record“.

Infatti, tutti i DBMS in circolazione associano solitamente un timestamp ai vari record… ed il timestamp, ovviamente, attinge dalla data e dall’ora del SO.

Dunque pensateci bene prima di fare una modifica del genere.

Alla prossima.

Shrinking di un database Firebird

L’ABC dell’informatica ci ha insegnato che non esiste un solo tipo di file system. Infatti, oltre al file system utilizzato dal sistema operativo esiste anche il file system del DBMS, il network file system (ad esempio NFS e Microsoft DFS) e così via.

Bene, solitamente quando si cancellano N record da una o più tabelle del DB, il DBMS a cui l’istanza afferisce non rilascerà automaticamente al sistema operativo lo spazio appena liberato. Questo significa che il file che identifica il DB manterrà le propre dimensioni originarie, nonostante le operazioni di rimozione dei record.

Per quanto riguarda Firebird, l’unico modo per effettuare lo shrinking del database (ovvero la sua contrazione in termini di spazio occupato su disco) è eseguire il backup di quest’ultimo e successivamente ripristinarlo.

database, dbms, shrinking, disk space, restore, backup, gfix, gbak, garbage collection, firebird

Fortunatamente, Firebird ci mette a disposizione un valido strumento per tale scopo: gbak.

Per default tale applicativo effettuerà anche la garbage collection dei record duplicati (generati dai rollback delle transazioni), impiegando un certo lasso di tempo (in quanto trattasi di un’operazione abbastanza onerosa in termini computazionali). Per fare in modo che gbak non proceda con la garbage collection occorre usare la flag -G. Ad esempio:

server ~ # gbak -B nomedatabase.fdb nomedatabase.fbk
-v -y backup.log

eseguirà il backup del nostro DB, salvando le informazioni relative a tale operazione (-v -y) nel file backup.log, mentre:

server ~ # gbak -B -G nomedatabase.fdb nomedatabase.fbk
-v -y backup.log

eviterà di eseguire la garbage collection (che, solitamente, viene messa in atto automaticamente ad intervalli di tempo regolari, secondo quanto definito nel file di configurazione di Firebird).

Inoltre, è possibile effettuare la garbage collection in un secondo momento, utilizzando gfix:

server ~ # gfix -s nomedatabase.fdb

Una volta creato il file di backup (con estensione *.fbk), sarà necessario ripristinarlo. Il comando da utilizzare è il seguente:

server ~ # gbak -C nomedatabase.fbk nomedatabase.fdb
-v -y restore.log

Assegnamo i giusti permessi al file appena creato:

server ~ # chown firebird:firebird nomedatabase.fdb

riavviamo Firebird:

server ~ # /etc/init.d/firebird restart

ed abbiamo finito.

Alla prossima.

Firebird: cancellazione dei record duplicati

Potrebbe accadere che all’interno di un database siano presenti una o più tabelle non dotate di chiavi primarie. Questo significa, in soldoni, che è molto alto il rischio di ridondanza (aka duplicati) e quindi di inconsistenza.

Fortunatamente, Firebird ci mette a disposizione un metodo abbastanza semplice per la cancellazione dei duplicati. Esso si basa sull’uso di uno specifico campo (RDB$DB_KEY), il cui valore univoco viene assegnato automaticamente a ciascun record durante la fase di inserimento nel DB.

firebirdlogo.jpg

Inutile dire che preferisco di gran lunga l’uso del suddetto metodo rispetto a soluzioni alternative, in quanto esso si basa esclusivamente su di una query secca e quindi minimizza il rischio di errore. Infatti, se ad esempio avessi utilizzato le cosiddette prepared statements avvelendomi di un qualche linguaggio di alto livello che le supporta (come Java), avrei dovuto scrivere N righe di codice, incrementando la possibilità di incappare in bachi (ecco perchè preferisco sempre mettere in pratica il motto less is more).

Di seguito la query che ho utilizzato:

DELETE FROM TABLE1 t1
WHERE EXISTS (
SELECT 1 FROM TABLE1 t2
WHERE t1.COL1 = t2.COL1 and t1.COL2 = t2.COL2
AND t1.RDB$DB_KEY < t2.RDB$DB_KEY
);

Dove t1 e t2 sono gli alias associati alla medesima tabella, mentre COL1 e COL2 sono i campi che la dovrebbero identificare univocamente (la probabile chiave primaria).

Ora, per avere la certezza che tale query non cancelli più record del previsto, si dovrebbero coinvolgere tutti i campi della tabella. Però, quando il numero dei campi è piuttosto elevato (>15), risulta più conveniente identificare la presunta chiave primaria ed utilizzare solo i campi che concorrono a formarla.

In questo caso, prima di effettuare il DELETE vero e proprio è opportuno fare delle query di verifica.

Ad esempio, dapprima si contano tutti i record della tabella:

SELECT count(*) FROM TABLE1;

e successivamente si individuano i record duplicati:

SELECT COL1, COL2, count(*) FROM TABLE1 GROUP BY COL1, COL2 HAVING count(*) >= 2;

A questo punto il numero dei record a cancellazione avvenuta dovrebbe essere pari al numero restituito dalla prima query meno il numero restituito dalla seconda query.

Per avere la certezza che il numero di record rimossi sia identico alla risultante dell’operazione di differenza effettuata in precedenza si può eseguire la query:

SELECT count(*) FROM TABLE1 t1
WHERE EXISTS (
SELECT 1 FROM TABLE1 t2
WHERE t1.COL1 = t2.COL1 and t1.COL2 = t2.COL2
AND t1.RDB$DB_KEY < t2.RDB$DB_KEY
);

Se il numero di record restituiti è identico al numero dato dalla differenza, abbiamo una buona probabilità che la chiave primaria individuata sia quella giusta (almeno dal punto di vista quantitativo).

Alla prossima.

Oracle: modificare la password utente e rimuovere la scadenza delle password

Oracle è di gran lunga il DBMS più affidabile e performante che esiste in circolazione. Detto ciò, qualche giorno fa mi si è presentato un problema su alcune macchine virtuali: le password per accedere ai DB erano scadute o stavano per scadere. Cosa fare dunque?

Per prima cosa ho lanciato la console VMWare e successivamente ho aperto il tool SQL*Plus Instant Client.

oracle.gif

A questo punto mi sono loggato come utente system, digitando il comando:

connect system/password

Per cambiare la password ho invece utilizzato la query:

ALTER USER system IDENTIFIED BY nuovapassword;

Questo output:

User altered.

mi ha confermato che la password è stata effettivamente cambiata.

Ora, per quanto riguarda invece la policy di scadenza delle password, posso dirvi che disabilitarla è controproducente dal punto di vista della sicurezza. Se, però, le macchine utilizzate sono di test e soprattutto NON sono esposte all’esterno, la si può disabilitare tranquillamente digitando:

ALTER PROFILE DEFAULT LIMIT

PASSWORD_LIFE_TIME UNLIMITED;

Alla prossima.