Archivi categoria: Sicurezza

PIX 501: configurazione del protocollo TACACS+

Premessa

Più volte, nell’ambito dei miei ultimi post, ho discusso della configurazione del protocollo TACACS+ per i Router/Switch di casa Cisco.

Adesso vedremo come configurare il suddetto protocollo su un Cisco PIX 501.

pixPrima di iniziare, occorre precisare che le uniche feature che abiliteremo saranno l’autenticazione e l’accounting (tralasciando quindi la parte di autorizzazione).

Configurazione generale

Dopo aver effettuato il login sul firewall in questione, entriamo in modalità enable e digitiamo il comando:

PIX# conf t

per poi creare una nuova istanza TACACS+:

PIX(config)# aaa-server AuthInbound protocol tacacs+

A questo punto possiamo specificare l’IP del server AAA, l’interfaccia attraverso cui è possibile raggiungerlo, la chiave TACACS+ ed il timeout:

PIX(config)# aaa-server AuthInbound (inside) host <IP> <key> timeout <secondi>

Authentication

Ora possiamo definire i protocolli che dovranno interfacciarsi col server per l’autenticazione dell’utente:

PIX(config)# aaa authentication telnet console AuthInbound LOCAL

Accounting

Infine, facciamo in modo che tutte le sessioni provenienti dall’esterno (Internet) vengano loggate dal nostro server:

PIX(config)# aaa accounting any inbound 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 AuthInbound

Creazione delle utenze locali

Per una questione di fallback, prima di salvare la suddetta configurazione, conviene creare delle utenze locali utilizzando il comando:

PIX(config)# username <user> password <pass>

ed abbiamo finito.

Alla prossima.

Configurazione “IOS resilient” sui dispositivi Cisco

Pensate a cosa accadrebbe se un file di vitale importanza per il fuzionamento del nostro dispositivo Cisco (come l’immagine dell’IOS o lo startup-config) venisse cancellato erroneamente (dall’amministratore) o intenzionalmente (da un hacker/cracker).

cisco

Proprio per evitare che un evento del genere possa accadere, Cisco ci mette a disposizione una serie di funzioni che concorrono a formare la cosiddetta IOS resilient configuration. Esse ci consentono rispettivamente di salvare l’immagine dell’IOS all’interno di una memoria PCMCIA e lo startup-config in una locazione protetta del filesystem. Così facendo, lanciando ad esempio il comando:

Router# show flash

oppure

Router# dir flash:

non verrà mostrato il file *.bin che rappresenta l’immagine dell’IOS.

Inoltre, nel caso in cui lo startup-config venisse cancellato erroneamente digitando:

Router# erase startup-config

e successivamente:

Router# reload

La configurazione potrà essere comunque ripristinata lanciando i comandi:

Router(config)# secure boot-config restore flash:archived-config

e

Router#configure replace flash:archived-config

dove il primo serve ad estrarre lo startup-config archiviato (in modo sicuro) all’interno del filesystem, mentre il secondo è necessario per fare in modo che il running-config venga sostituito con il file di configurazione appena estratto.

Da notare che per abilitare le suddette funzioni occorre che il dispositivo sia dotato di una memoria PCMCIA (indispensabile per la messa in sicurezza dell’IOS) e che, una volta configurate, possono essere disabilitate solo ed esclusivamente tramite console.

Ma veniamo al sodo. I comandi da lanciare sono 2, ovvero:

Router(config)# secure boot-image

per l’IOS, e:

Router(config)# secure boot-config

per lo startup-config.

Infine, per essere certi che i suddetti comandi siano andati a buon fine, possiamo digitare:

Router# show secure bootset

il cui output sarà simile al seguente:

IOS image resilience version 12.4 activated at 02:00:30 UTC Sun Oct 17 2010
Secure archive flash:c181x-advipservicesk9-mz.124-24.T.bin type is image (elf) []
  file size is 23587052 bytes, run size is 23752654 bytes
  Runnable image, entry point 0x80012000, run from ram

IOS configuration resilience version 12.4 activated at 02:00:41 UTC Sun Oct 17 2010
Secure archive flash:.runcfg-20101017-020040.ar type is config
configuration archive size 1544 bytes

Fine del post, alla prossima.

Realizzare un server AAA mediante CentOS 6 e tac_plus

Premessa

Quando si ha a che fare con reti di grandi dimensioni (che contano centinaia e centinaia di dispositivi connessi tra di loro), occorre fare in modo che gli account utente (ed i relativi permessi) vengano gestiti in modo centralizzato. Tale funzione viene svolta dai cosiddetti server AAA, i quali, mediante l’uso di determinati protocolli (come RADIUS, DIAMETER o TACACS+), forniscono dei meccanismi per l’autenticazione dell’utente (Athentication), per la gestione dei relativi permessi (Authorization) e per la “registrazione” delle azioni  compiute dopo aver ottenuto accesso ai dispositivi (Accounting).

aaa

Un po’ di teoria

Come già detto in precedenza, i protocolli maggiormente utilizzati per le funzioni AAA sono RADIUS (anche nella variante più recente DIAMETER) e TACACS+.

Il primo è uno standard open, basato sul protocollo UDP, meno sicuro rispetto al TACACS+ (in quanto cifra solo ed esclusivamente il pacchetto che contiene le credenziali di autentica, lasciando il resto delle comunicazioni in plaintext) e che combina in un unico processo i meccanismi di autenticazione ed autorizzazione.

Il secondo, invece, è uno standard basato sul protocollo TCP (porta 49), proprietario (Cisco), più sicuro rispetto al RADIUS (cifra tutti i pacchetti) e che gestisce ciascuna funzione tipica dell’AAA in modo separato e distinto.

Dati i presupposti, la scelta del protocollo da utilizzare nel nostro ambiente ricade abbondantemente su TACACS+ (essendo inoltre di casa Cisco i dispositivi di rete che si intende gestire).

Installazione e configurazione del server AAA

Come si può banalmente evincere dal titolo, il server in questione è stato realizzato utilizzando una Linux box (CentOS 6) con a bordo il demone tac_plus.

Per prima cosa, occorre quindi installare il suddetto applicativo, aggiungendo il repository yum specifico (nux-misc.repo) alla repolist della nostra macchina:

[root@linuxbox ~]# cd /etc/yum.repos.d/
[root@linuxbox ~]# nano nux-misc.repo

il cui contenuto dovrà essere:

[nux-misc]
name=Nux Misc
baseurl=http://li.nux.ro/download/nux/misc/el6/x86_64/
enabled=0
gpgcheck=1
gpgkey=http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro

Fatto ciò possiamo procedere con l’installazione vera e propria:

[root@linuxbox ~]# yum --enablerepo=nux-misc install tac_plus

Una volta installato il pacchetto facciamo un backup della sua configurazione di default:

[root@linuxbox ~]# cp /etc/tac_plus.conf /etc/tac_plus.conf.bak

e focalizziamo la nostra attenzione sul file di configurazione che andremo a creare ex-novo:

[root@linuxbox ~]# nano /etc/tac_plus.conf

Il cui contenuto dovrà essere simile al seguente:

key = <passphrase tacacs+>

#ACL

acl = default   {
                permit = 192\.168\.0\.1
}

# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
# *                      ACCOUNTING                       *
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

accounting file = /var/log/tac_accounting.log

#

# * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# *                     AUTHENTICATION                    *
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

user = Pippo {
        default service = permit
        login = des 43v/eMDQqTT2o
        member = NOC
}

user = Pluto {
        login = des 44LWBaN31RmGg
        member = NOC

        #AUTHORIZATION ENTRIES
        cmd = show {
                permit .*
        }
        cmd = exit {
                permit .*
        }
}

group = NOC {
        acl = default
}

# End config file

Analizziamo il suddetto file. Esistono fondamentalmente due macro sezioni, ovvero authentication ed accounting.

Nella prima ho specificato i 2 utenti (con relativa password) che possono avere accesso ai dispositivi di rete, mentre nella seconda ho indicato il file di log in cui “registrare” tutti gli eventi associati all’accounting.

Da notare che la password degli utenti è in formato DES (cifrata), ed è stata ottenuta utilizzando il tool tac_pwd nel modo seguente:

[root@linuxbox ~]# tac_pwd <salt>

Inoltre, all’interno della sezione authentication, ho inserito, per l’utente Pluto, alcune restrizioni sui comandi che possono essere lanciati. Nella fattispecie, egli potrà utilizzare solo ed esclusivamente i comandi show (il permit = .* indica tutto ciò che viene dopo la keyword show) ed exit. Per quanto riguarda l’utente Pippo, essendoci un deny implicito per il servizio di authorization (quindi tutti i comandi non espressamente dichiarati vengono automaticamente inibiti), ho dovuto aggiungere la direttiva default service = permit.

Da notare che ho inserito anche un’opportuna ACL per fare in modo che solo i dispositivi autorizzati possano dialogare col suddetto demone (ACL coadiuvata da regole di firewalling ad hoc, in modo da rispettare il più possibile il modello defense in depth).

A configurazione ultimata, possiamo avviare il demone:

[root@linuxbox ~]# service tac_plus start

e fare in modo che venga avviato automaticamente dopo ogni reboot:

[root@linuxbox ~]# chkconfig tac_plus on

Come ultimo step relativo alla configurazione del server AAA, sarà necessario creare un’opportuna regola netfilter (utilizzando iptables) per consentire il traffico TACACS+ in ingresso:

-A INPUT -m state --state NEW -m tcp -p tcp -s 192.168.0.1/32 --dport 49 -j ACCEPT -m comment --comment "router"

 Configurazione dei dispositivi di rete

Per semplificare un po’ le cose utilizzerò come modello di riferimento la configurazione di un router 2811, anche se essa dovrebbe essere comunque molto simile (se non identica) per la stragrande maggioranza dei dispositivi marchiati Cisco.

Per prima cosa abilitiamo le funzionalità AAA:

Router(config)# aaa new-model

per poi soffermarci sull’autentica:

Router(config)# aaa authentication login default group tacacs+ local

e sulla definizione del server TACACS+ con relativa chiave:

Router(config)# tacacs-server host <ip>
Router(config)# tacacs-server key 0 <pass>

Occorre precisare che l’autenticazione è stata configurata in modo da prevedere un meccanismo di fallback, ovvero nel caso in cui il server AAA non fosse più raggiungibile, sarà comunque possibile loggarsi sul dispositivo utilizzando gli account utente definiti localmente.

Inoltre, nel caso in cui il suddetto server fosse raggiungibile dagli uffici periferici mediante dei tunnel VPN dedicati, occorrerà specificare nella loro configurazione l’interfaccia dalla quale esso puotrà essere contattato:

Router(config)# ip tacacs source-interface <int>

Successivamente possiamo procedere con la configurazione dell’authorization:

aaa authorization exec default group tacacs+ local
aaa authorization commands 1 default group tacacs+ local
aaa authorization commands 15 default group tacacs+ local

e dell’accounting:

Router(config)# aaa accounting system default start-stop group tacacs+
Router(config)# aaa accounting network default start-stop group tacacs+
Router(config)# aaa accounting exec default start-stop group tacacs+
Router(config)# aaa accounting commands 0 default start-stop group tacacs+
Router(config)# aaa accounting commands 15 default start-stop group tacacs+
Router(config)# aaa accounting session-duration ntp-adjusted

Prima di salvare la configurazione, testiamo il corretto funzionamento del meccanismo di autentica, digitando:

Router# test aaa group tacacs+ <user> <pass> legacy

il cui output dovrebbe essere:

Attempting authentication test to server-group tacacs+ using tacacs+
User was successfully authenticated.

Adesso si può finalmente procedere con il salvataggio della configurazione:

Router# copy run start

ed abbiamo finito.

Alla prossima.

CentOS 6 e contromisure agli attacchi DDoS: regole di firewalling basate sui netblock dei provider italiani

Scenario

Server Web Linux (basato su Apache) con CentOS 6 a bordo, dotato di 16 GB di RAM e 2 CPU con 4 core ciascuna. Totale assenza di firewall di frontend, ergo il filtraggio del traffico viene demandato direttamente al server in questione.

Problema

Da N giorni la suddetta macchina è vittima di attacchi di tipo DDoS, provenienti per lo più da IP stranieri (macchine zombie facenti parte di una botnet).

Soluzione

Creare delle regole netfilter ad hoc (mediante iptables), consentendo solo ed esclusivamente i netblock degli ISP italiani. Inoltre, per evitare che l’attaccante possa avvalersi di qualche proxy “aperto” made in Italy, sono stati bloccati ulteriori IP pubblici recuperati da un sito specifico. Infine, sono stati consentiti gli IP pubblici degli spider (aka crawler) utilizzati dai più importanti motori di ricerca (Google, Bing, Yahoo!), in modo tale da impedire che il sito Web hostato sul server venga penalizzato in termini di ranking.

Step 1: consentire gli IP italiani

Lo scrip bash (permit_ita.sh) che esegue tale operazione è il seguente:

#!/bin/bash

iptables -A INPUT -p tcp --dport 80 -j DROP
iptables -A INPUT -p tcp --dport 443 -j DROP

wget http://www.ipdeny.com/ipblocks/data/countries/it.zone -O ip_italiani.txt

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j ACCEPT
    iptables -I INPUT -s $line -p tcp --dport 443 -j ACCEPT
done < ip_italiani.txt

iptables-save

Il suo funzionamento è banale: per prima cosa vengono create 2 regole netfilter per droppare tutto il traffico HTTP/HTTPS diretto al sito Web. Successivamente viene scaricato (mediante wget) il contenuto del sito http://www.ip-deny.com/ipblocks/data/countries/it.zone, in cui è presente l’elenco dei netblock italiani. Infine, vegnono consentiti i netblock in questione.

Step 2: bloccare i proxy made in Italy

A questo punto possiamo procedere con il blocco dei proxy “open” italiani. Per fare ciò possiamo utilizzare il seguente scrip bash (block_proxy.sh):

#!/bin/bash

wget --user-agent="Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092416 Firefox/3.0.3"  http://spys.ru/free-proxy-list/IT/ -O lista_proxy.txt

grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" lista_proxy.txt | uniq > ip_proxy.txt

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j DROP
    iptables -I INPUT -s $line -p tcp --dport 443 -j DROP
done < ip_proxy.txt

iptables-save

Il sito target (ovvero quello che contiene la lista dei proxy da bloccare) è http://spys.ru/free-proxy-list/IT/, il quale effettua un filtraggio dei client che possono accedervi utilizzando lo User Agent come discriminante (quindi non è possibile scaricarne il contenuto se non si effettua uno spoofing di tale parametro tramite wget e l’opzione –user-agent).

Inoltre, poichè il contenuto del sito non è una “lista piatta” di IP pubblici, è stato necessario filtrare il tutto utilizzando un’espressione regolare in grado di individuare i 4 ottetti tipici dell’IPv4.

Step 3: consentire gli spider dei motori di ricerca

Come ultima fase, occorre consentire gli IP degli spider, utilizzando tale scrip (permit_spider.sh):

#!/bin/bash

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j ACCEPT -m comment --comment "crawler"
done < ip_spider.txt

iptables-save

Il contenuto del file ip_spider.txt potete ricavarlo da qui (Google), qui (Yahoo!) e qui (Bing ed altri).

A configurazione completata, possiamo saggiare il carico sul server (intento a droppare il traffico proveniente dalla botnet) utilizzando htop.

Se la macchina regge e le risorse hardware locali non sono allo stremo potremo finalmente dire di aver vinto.

Alla prossima.

sniffer.sh: script bash per l’individuazione dei site grabber

Scenario

Supponiamo che il vostro sito sia diventato oggetto delle attenzioni di un grabber (di cui non si conosce l’indirizzo IP pubblico), che ogni X tempo ne preleva il contenuto forzosamente.

Supponiamo, inoltre, che il suddetto grabber sia abbastanza intelligente da coprire le proprie tracce “spoofando” lo user agent in modo da apparire come un client lecito.

590x300

Nel caso in cui non si abbiano a disposizione strumenti di log analysis avanzati quali Splunk, l’unica alternativa per individuare l’IP pubblico del grabber consiste nel crearsi degli strumenti ad-hoc,  in grado di fare un conteggio del numero di hit per ciascun IP pubblico che ha contattato il nostro sito.

In soldoni si tratta di un semplice scrip bash, che riporto di seguito.

#!/bin/bash

filename1="/var/log/sniffer.log"

filename2="/var/log/sources.log"

filename3="/var/log/sources_sorted.log"

filename4="/var/log/sources_sorted_by_hits.log"

if [ -e $filename1 ];then

cat /dev/null > $filename1

fi

if [ -e $filename2 ];then

cat /dev/null > $filename2

fi

if [ -e $filename3 ];then

cat /dev/null > $filename3

fi

if [ -e $filename4 ];then

cat /dev/null > $filename4

fi

echo ""

echo -e "33[32mSniffing traffic... Press CTRL+C to stop"

echo -e "33[37m"

START=$(date +%s);

iftop -i eth0 -n -f 'port (80 or 443)' -t > $filename1

echo ""

read -p "Press [Enter] key to continue..."

END=$(date +%s);

ELAPSED_TIME=$((END-START))

echo -e "33[32mShowing hit number provided in $ELAPSED_TIME seconds, ordered by source..."

echo -e "33[37m"

cat $filename1 | grep '<=' | awk '{ print $1 }' > $filename2

cat $filename2 | sort -u > $filename3

while read line

do
 hits=`cat $filename2 | grep $line | wc -l`

host=`host $line`

echo "hits for IP $line ($host): $hits" >> $filename4

done < $filename3

cat $filename4 | sort -k 5 -nr

exit 0

Esso si basa principalmente sul software iftop e, una volta lanciato, rimane in ascolto sulle porte di interesse (nel nostro caso la TCP/80 e la TCP/443), per poi stilare una “classifica” di IP pubblici in base al numero di hit che hanno prodotto durante il tempo di osservazione.

Come informazione aggiuntiva, per ogni IP viene ricavato anche il suo FQDN (attraverso il comando host), in modo da individuare ancora più facilmente la provenienza del grabber.

Per maggiore chiarezza, ecco un esempio di output relativo al suddetto script:

hits for IP 87.18.215.154 (154.215.18.87.in-addr.arpa domain name pointer host154-215-dynamic.18-87-r.retail.telecomitalia.it.): 18
hits for IP 84.223.145.17 (17.145.223.84.in-addr.arpa domain name pointer dynamic-adsl-84-223-145-17.clienti.tiscali.it.): 23
hits for IP 84.222.212.172 (172.212.222.84.in-addr.arpa domain name pointer dynamic-adsl-84-222-212-172.clienti.tiscali.it.): 23
hits for IP 79.18.99.217 (217.99.18.79.in-addr.arpa domain name pointer host217-99-dynamic.18-79-r.retail.telecomitalia.it.): 24
hits for IP 2.35.156.49 (49.156.35.2.in-addr.arpa domain name pointer net-2-35-156-49.cust.vodafonedsl.it.): 21
hits for IP 188.87.64.235 (235.64.87.188.in-addr.arpa domain name pointer static-235-64-87-188.ipcom.comunitel.net.): 23
hits for IP 151.45.153.218 (218.153.45.151.in-addr.arpa domain name pointer adsl-ull-218-153.45-151.net24.it.): 14

Inoltre, consultando il file /var/log/sources_sorted_by_hits.log, sarà possibile ricavare la lista degli IP/FQDN ordinati (in modo decrescente) in base al numero delle hit che hanno effettuato.

Una volta individuato l’IP che ci interessa non ci resta che bloccarlo utilizzando, ad esempio, iptables:

iptables -I INPUT -s <ip del grabber> -j DROP

ed abbiamo finito.

Alla prossima.

Firewall Cisco ASA ed attacchi DDoS/DoS

Ultimamente mi è capitato di dover far fronte a tutta una serie di attacchi DDoS, per lo più basati sul protocollo HTTP (connessioni half-open/embryonic, in cui manca il l’ACK finale poichè l’indirizzo IP sorgente del SYN è falso o soggetto a spoofing), mitigati senza troppe difficoltà da un cluster di Firewall Cisco ASA.

ddosLa configurazione che ho utilizzato per mitigare tale tipologia di attacchi è simile alla seguente:

ASA(config)# class-map mpf-policy
ASA(config-cmap)# match access-list outside_access_in
ASA(config-cmap)# exit
ASA(config)# policy-map mpf-policy-map
ASA(config-pmap)# class mpf-policy
ASA(config-pmap-c)# set connection conn-max 11500
ASA(config-pmap-c)# set connection embryonic-conn-max 3000
ASA(config-pmap-c)# set connection per-client-embryonic-max 200
ASA(config-pmap-c)# set connection per-client-max 95
ASA(config-pmap-c)# exit
ASA(config-pmap)# exit
ASA(config)# service-policy mpf-policy-map interface outside
ASA(config)# exit

Tutto è filato liscio per un po’ di tempo, fino a quando l’attaccante non ha deciso di cambiare strategia, passando da un attacco DDoS ad uno DoS (dunque con un solo IP sorgente) e dal protocollo TCP a quello UDP (molto più adatto a questa tipologia di attacco poichè connection-less).

La VPS utilizzata come sorgente di traffico, dotata di ampia banda (si trovava in una farm tedesca) è stata in grado, in un lasso di tempo brevissimo, di far collassare i firewall. Una volta identificato il suo IP ho creato un’ACL del tipo:

ASA(config)#deny ip host <IP attaccante> any

che però si è rivelata essere un’arma a doppio taglio visto che il firewall si è visto costretto a “maneggiare” e “bloccare” una mole di traffico tale per cui la sua CPU ha raggiunto livelli di carico assurdi (la dashboard di ASDM indicava un picco di oltre il 300% a fronte di un rate di pacchetti droppati superiore ai 100k  – vedi immagine sottostante).

dropped_ratedropped_rate

Fondamentalmente ciò è dovuto al fatto che ciascun modello di ASA può gestire solo una determinata mole di traffico (sessioni concorrenti, nuove connessioni/secondo, pacchetti/secondo, ecc – per ulteriori dettagli vedi qui), limite imposto soprattutto dalle caratteristiche hardware di cui è dotato (CPU, RAM, ecc.). Inoltre, per ciascun pacchetto scartato, è necessario un certo overhead, ragion per cui la suddetta ACL ha prodotto effetti collaterali che hanno portato ad un peggioramento della situazione.

Dopo qualche minuto di smarrimento, ho deciso di modificare la mia strategia (sulla falsariga di quella dell’attaccante), consentendo sul firewall tutto il traffico in ingresso dall’IP della VPS incriminata, demandando ai server la sua gestione. Nella fattispecie, ho configurato dei blackhole (aka null route) a livello 3, mediante il seguente comando:

route add -net <IP attaccante> gw 127.0.0.1 lo

Ho scelto questa strategia per 2 motivi:

1) I server sono dotati di maggiori risorse hardware rispetto ai firewall, quindi più “propensi” a gestire una tale mole di traffico in ingresso;

2) Lavorare a livello 3 anzichè a livello 4 implica un minor overhead.

Alla fine tale strategia si è rivelata vincente e l’attaccante ha deposto le armi.

E’ tutto, alla prossima.

checksecurity.sh: script bash per monitorare gli aggiornamenti critici su CentOS 6

Poichè devo gestire un elevato numero di VM *nix, mi è indispensabile riuscire ad automatizzare quanti più task possibili, tenendo sempre a mente tale regola:

                                                                        a good sysadmin is a lazy one

Uno di questi task riguarda le notifiche per gli aggiornamenti critici di sistema, soprattutto per ciò che concerne l’aspetto della cyber security.

A tal proposito, ho realizzato uno scrip bash in grado di verificare la presenza di eventuali aggiornamenti e di inviarmi successiva notifica via email.  Starà a me, in un secondo momento, decidere quando e se installare gli aggiornamenti proposti.

I tool necessari al suo funzionamento sono 2, ovvero yum-security e mutt. Procediamo dunque con la loro installazione mediante yum:

[root@linuxbox ~]# yum install yum-plugin-security mutt -y

bashEd ecco lo scrip:

#!/bin/bash

logfile=/var/log/checksecurity.log

data=`date +%d-%m-%Y`

destinatario=vostro.indirizzo@email.it

echo "$data: Checking for security updates..." >> $logfile

yum clean all

yum list-security >> /root/checksec/tmp

security=`cat /root/chcksec/tmp | grep security | grep -v Loaded`

bugfix=`cat /root/checksec/tmp | grep bugfix`

cve=`cat /root/checksec/tmp | grep cve`

if [ -n "$security" ];then
echo "$data: security updates available" > /root/checksec/out
fi

if [ -n "$bugfix" ];then
echo "$data: bugfix updates available" >> /root/checksec/out
fi

if [ -n "$cve" ];then
echo "$data: cve updates available" >> /root/checksec/out
fi

if [ -s /root/checksec/out ];then

cat /root/checksec/tmp >> /root/checksec/out

cat /root/checksec/out >> $logfile

cat /root/checksec/out | mutt -s "GESTORE01: security, bugfix and cve system report" $destinatario

rm /root/checksec/out

else

echo "$data: Nothing to do, exiting..." | tee -a $logfile

fi

rm /root/checksec/tmp

exit 0;

Ci rimane solo rendere lo scrip eseguibile (chmod +x /root/checksec/checksecurity.sh) ed aggiungerlo a crontab.

Alla prossima.

Script powershell per identificare le password di dominio “deboli”

Ogni tanto fare una sorta di security audit sulla nostra rete è cosa buona e giusta, soprattutto se in passato questo task è stato totalmente ingnorato dai sistemisti di turno.

Proprio per questo motivo, ho pensato di realizzare un scrip powershell in grado di testare la robustezza delle password utilizzate dalle varie utenze di dominio.

powershellPreparazione

Per prima cosa occorre creare una lista di password “deboli” all’interno di un file di testo (weakpasswords.txt). Tale file dovrà contenere una sola password per riga, ad esempio:

 password1
 password2
 password3

Una volta fatto ciò occorre salvare in un altro file di testo le utenze di dominio, lanciando tale comando direttamente sul domain controller:

NET USERS /DOMAIN > users.txt

Il contenuto del file users.txt sarà simile al seguente:

User accounts for \\DC
------------------------------------------------------------------ utente1                        utente2               utente3  utente4                        utente5               utente6

Affinchè lo scrip possa funzionare, però, è necessario che vi sia un solo utente per riga, ergo bisogna parsare il file users.txt e salvare il suo contenuto (opportunamente formattato) all’interno di un altro file (parsed.txt). Per farè ciò ho utilizzato awk (su una Linux box):

[root@server ~]# cat users.txt | awk '{print $1}' >> parsed.txt
[root@server ~]# cat users.txt | awk '{print $2}' >> parsed.txt
[root@server ~]# cat users.txt | awk '{print $3}' >> parsed.txt

Contenuto dello script

Adesso il file parsed.txt può essere spostato sul DC e possiamo creare il nostro scrip (che chiameremo testauth.ps1) il cui contenuto dovrà essere:

Function Test-ADAuthentication {
    param($username,$password)
    (new-object directoryservices.directoryentry "",$username,$password).psbase.name -ne $null
}

$users = Get-Content parsed.txt 
foreach ($user in $users) {
    $user = $user.Trim()
    $passwords = Get-Content weakpasswords.txt
    foreach ($password in $passwords) {
        $password = $password.Trim()
        $result = Test-ADAuthentication "NOMEDOMINIO\$user" "$password"
        if ($result -like "True") {
            echo "Username $user has got a the weak password $password" >> passresult.txt
        }
        else
        {
            echo "Password for user $user did not match" 
        }
    }
}

Esecuzione

Non ci resta che eseguire tale scrip powershell mediante il comando:

./testauth.ps1

e successivamente verificare il contenuto del file passresult.txt, in cui saranno presenti le associazioni utente/password “debole”.

Alla prossima.

Configurare una VPN IPsec site-to-site tra un router Cisco 2811 ed un router Cisco 877W

Affinchè si possa realizzare un canale di comunicazione “sicuro” tra due o più filiali, sfruttando, ad esempio, una normale linea ADSL, è necessario affidarsi ad una tecnologia VPN che supporti tale funzionalità. Lo standard “de facto” per i collegamenti Site-to-Site è rappresentato dal protocollo IPsec.

Adesso vedremo come configurare tale tipologia di VPN, utilizzando come piattaforme hardware un router Cisco 2811 (main office) ed un router Cisco 877W (branch office).

Lo schema di rete si può riassumere come segue:

vpn-ipsecConfigurazione del router Cisco 2811 (Main Office)

La prima cosa da fare è creare la policy ISAKMP per gestire le Security Associations (in gergo dette semplicemente SA), ovvero le due entità che vogliono instaurare il tunnel VPN.

R1(config)crypto isakmp policy 1
R1(config-isakmp)# encr 3des
R1(config-isakmp)# hash md5
R1(config-isakmp)# authentication pre-share
R1(config-isakmp)# group 2
R1(config-isakmp)# lifetime 86400

In particolare, sto definendo alcuni parametri relativi alla fase 1 IKE (in realtà ISAKMP è solo uno dei 3 protocolli definiti nella suite IKE), ovvero:

1) il tipo di cifratura simmetrica da utilizzare (3des);

2) l’algoritmo di hashing per l’HMAC (md5), utilizzato per garantire l’integrità dei pacchetti scambiati tra le parti;

3) il tipo di autentica (tramite chiave condivisa – pre-shared);

4) il gruppo Diffie-Helman da utilizzare (l’algoritmo in questione definisce un metodo “sicuro” per lo scambio delle chiavi tra le parti);

5) la durata del tunnel IPSec (in secondi).

Ora si può procedere con la definizione della chiave condivisa:

R1(config)# crypto isakmp key cisco address 2.2.2.3

A questo punto possiamo configurare la fase 2 IKE, impostando l’apposito transform set:

R1(config)# crypto ipsec transform-set TS esp-3des esp-md5-hmac

Esso si occupa di cifrare i dati trasmessi tra le due parti dopo l’instaurazione del tunnel.

Definiamo adesso l’ACL che si occuperà di indentificare il traffico VPN (detto, in gergo, interesting traffic):

R1(config)# ip access-list extended VPN-TRAFFIC
R1(config-ext-nacl)# permit ip 192.168.1.0 0.0.0.255 192.168.2.0 0.0.0.255

A questo punto sarà possibile definire la crypto map:

R1(config)# crypto map CMAP 6 ipsec-isakmp 
R1(config-crypto-map)# set peer 2.2.2.3
R1(config-crypto-map)# set transform-set TS
R1(config-crypto-map)# match address VPN-TRAFFIC

Inoltre, dobbiamo evitare che il traffico LAN-to-LAN venga nattato. E’ possibile fare ciò definendo un’ACL ad hoc:

R1(config)# access-list 100 remark --NO-NAT--
R1(config)# access-list 100 deny ip 192.168.1.0 0.0.0.255 192.168.2.0 0.0.0.255
R1(config)# access-list 100 permit ip 192.168.1.0 0.0.0.255 any
R1(config)# access-list 100 remark

associandola, successivamente, al processo di NAT vero e proprio:

R1(config)# ip nat inside source list 100 interface fastethernet0/0 overload

Come ultimo step dobbiamo associare la crypto MAP precedentemente definita all’interfaccia fa0/0 (Internet):

R1(config)# int fa0/0
R1(config-if)# crypto map CMAP

Configurazione del router Cisco 877W (Branch Office)

La configurazione del Branch Office è del tutto speculare a quella del Main office. L’unica stostaziale differenza sta nell’interfaccia esposta ad Internet: per il main office è la fa0/0 mentre per il branch office è la dia1 (protocollo PPPoE).

IKE fase 1:

R2(config)#  crypto isakmp policy 1
R2(config-isakmp)# encr 3des
R2(config-isakmp)# hash md5
R2(config-isakmp)# authentication pre-share
R2(config-isakmp)# group 2
R2(config-isakmp)# lifetime 86400

Pre-shared key:

R2(config)# crypto isakmp key cisco address 2.2.2.2

IKE fase 2 (transform set):

R2(config)# crypto ipsec transform-set TS esp-3des esp-md5-hmac

 ACL per il traffico LAN-to-LAN:

R2(config)# ip access-list extended VPN-TRAFFIC
R2(config-ext-nacl)# permit ip 192.168.2.0 0.0.0.255 192.168.1.0 0.0.0.255

 Crypto map:

R2(config)# crypto map CMAP 6 ipsec-isakmp 
R2(config-crypto-map)# set peer 2.2.2.2
R2(config-crypto-map)# set transform-set TS
R2(config-crypto-map)# match address VPN-TRAFFIC

No-NAT:

R2(config)# access-list 100 remark --NO-NAT--
R2(config)# access-list 100 deny ip 192.168.2.0 0.0.0.255 192.168.1.0 0.0.0.255
R2(config)# access-list 100 permit ip 192.168.2.0 0.0.0.255 any
R2(config)# access-list 100 remark
R2(config)# ip nat inside source list 100 int dia1 overload

Binding crypto map/interfaccia:

R2(config)# int dia1
R2(config-if)# crypto map CMAP
R2(config-if)# crypto ipsec df-bit clear

L’ultimo comando relativo alla configurazione dell’interfaccia dia1 ci mette al riparo da eventuali problemi dovuti ad un MTU mismatch (ad esempio, il router Cisco 2811 utilizza una MTU pari a 1500 byte mentre il router Cisco 877W, essendo configurato per un accesso ad Internet di tipo PPPoE, usa una MTU pari a 1492 byte).

Test e troubleshooting

Per testare l’effettivo funzionamento del tunnel VPN appena configurato è sufficiente, in primo luogo, lanciare un semplice ping verso la LAN del peer, avendo cura di definire come interfaccia sorgente quella esposta sulla rete privata:

R1(config)ping 192.168.2.1 source fa0/1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.2.1, timeout is 2 seconds:
Packet sent with a source address of 192.168.1.1
.!!!!
Success rate is 80 percent (4/5), round-trip min/avg/max = 41/44/46 m

Il primo ping ha restituito un timeout poichè il tunnel VPN viene tirato su solo on-demand, ovvero dopo aver appurato la presenza di traffico LAN-to-LAN, per poi rimanere attivo fino al timeout definito nella policy ISAKMP (86400 secondi).

Altri comandi utili per verificare lo stato del tunnel VPN sono i seguenti:

show crypto session
show crypto isakmp sa
show crypto ipsec sa
debug crypto isakmp
debug crypto ipsec

E’ tutto. Alla prossima.

Record SPF troppo lunghi: ecco la soluzione

Alcuni DNS provider (come GoDaddy) sono in grado di gestire automaticamente i record TXT/SPF troppo lunghi, “spezzandoli” in stringhe separate (la lunghezza massima per ciascuna stringa contenuta in un record TXT è pari a 255 caratteri). Altri, invece, permettono di inserire dei record TXT/SPF contenuti in strighe lunghe a piacere, senza prevedere alcun meccanismo per lo “split” automatico del loro contenuto.

spf

Ciò è profondamente sbagliato, in quanto qualunque interrogazione DNS (ad esempio dig vostrodominio.com TXT), riporterà un numero eccessivo du bytes nella risposta, non consentendo la consultazione dei record SPF e quindi compromettendo del tutto il funzionamento di tale protocollo sperimentale.

Per evitare ciò è sufficiente utilizzare la direttiva include. Ad esempio, inserendo tale record TXT per la zona @:

"v=spf1 include:spf1.vostrodominio.com include:spf2.vostrodominio.com -all"

richiameremo altri 2 record TXT, ovvero:

spf1.vostrodominio.com  "v=spf1 ip4:244.11.23.13 ip4:144.21.23.13 -all"
spf2.vostrodominio.com  "v=spf1 ip4:222.11.11.13 ip4:244.182.23.191 ip4:203.101.22.13 -all"

aggirando quindi il problema delle stringhe eccessivamente lunghe.

Per testare il corretto funzionamento di tale settaggio potete consultare questo sito.

Alla prossima.