Netfilter è il framework con cui vengono gestite tutte le operazioni di firewalling, natting e manipolazione di pacchetti nel kernel Linux.
Netfilter viene gestito con il comando iptables con cui si determinano e configurano tutte le regole con cui gestire il traffico di rete.
Breve storia dei firewall Linux
Il codice di firewalling di Linux ha subito diverse modifiche nella storia del kernel.
Nella versione 2.0.x viene usato il sistema ipfwadm che viene sostituito nelle versione 2.2.x dalle ipchains che introducono il concetto di catene di regole (access-list) a cui un pacchetto può essere indirizzato.
Dalla versione 2.4 in poi il kernel si basa sull'infrastruttura netfilter/iptables che permette con semplicità estrema di configurare un firewall di fare packet filtering (stateless, statefull), diversi tipi di NAT (Network Address Translation) e packet mangling (modifica di alcuni flag dei pacchetti trattati).
Il progetto NETFILTER/IPTABLES nasce da Paul "Rusty" Russell e dal Core Team (i quali tutt'ora continuano il lavoro di sviluppo), nel lontano 1999.
Componenti
Il framework netfilter/iptables si può identificare in diversi componenti:
1- la parte riguardante il kernel, ovvero tutto il codice che lavora in kernel space e che con diversi moduli introduce funzionalità base e avanzate.
In quasi tutte le distribuzioni netfilter è installato, in alcune specifiche sulla sicurezza possono essere anche installati moduli aggiuntivi sperimentali.
2- L'interfaccia utente, ovvero sostanzialmente il comando iptables
che permette di impostare regole e gestire il firewall.
Solitamente fornita con un pacchetto chiamato... iptables.
E' essenziale capire e familiarizzare con la logica di iptables prima di cimentarsi nella stesura delle policy di un firewall, altrimenti si rischia di non ottenere i risultati voluti o comprometterne la funzionalità.
Logica di tabelle, catene, regole.
Di default iptables lavora su 3 tabelle (tables) (filter, nat, mangle) che prevedono diverse catene (chains) (INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING...) all'interno delle quali esistono elenchi di regole (rules).
Ogni regola identifica pacchetti di rete secondo diversi criteri sulla base di variegati match (tcp, udp, state, pkttype e molti altri, alcuni sperimentali) con le relative opzioni e termina con un target che determina cosa fare del pacchetto matchato (ACCEPT, DROP, REJECT, SNAT, DNAT, LOG...).
Tabella di filter
Quando si usa il comando iptables questa è la tabella di default, implicita.
Prevede 3 catene di default che di fatto corrispondono alle possibili destinazioni del pacchetto rispetto alla macchina che funziona da firewall:
INPUT
Catena in cui passano tutti i pacchetti in entrata dalle interfacce di rete del sistema. Si usa comunemente per permettere o negare l'accesso da IP remoti a porte locali.
OUTPUT:
Considera tutti i pacchetti che sono originati ed escono dal proprio sistema. Si usa per controllare il traffico in uscita, sia per le risposte a pacchetti permessi in INPUT che per nuove connessioni in uscita.
FORWARD:
Riguarda i pacchetti che devono "attraversare" il firewall, avendo IP sorgente e destinazione diversi da quello della macchina su cui gira iptables.
Si usa tipicamente su router o firewall di rete.
Tabella di nat
Questa tabella riguarda alcune alterazioni che si possono fare su un pacchetto, in particolare la variazione degli IP e delle porte sorgenti o di destinazione . Viene richiamata con l'opzione -t nat
e prevede le seguenti catene di default:
PREROUTING
- Catena in cui vengono processati i pacchetti in ingresso, prima che il sistema prenda le decisioni di routing. Si usa tipicamente per fare destination natting usando il target DNAT
.
POSTROUTING
- Catena in cui passano i pacchetti dopo che sono stati routati sulla interfaccia di destinazione. Si usa per modificare l'IP e/o la porta sorgente di un pacchetto, tipicamente usato su default gateway di una rete con funzioni di Port Address Translation (su Linux definito Masquerading). Prevede i target SNAT
e MASQUERADE
.
OUTPUT
- Catena utilizzata per modificare l'IP sorgente di un pacchetto uscito dal sistema stesso.
Tabella di mangle
Si può utilizzare per modificare vari parametri negli header di un pacchetto. Viene richiamata con -t mangle
e prevede le catene di default PREROTING, INPUT, FORWARD, OUTPOUT, POSTROUTING. L'uso più comune è per alterare il TOS di un pacchetto IP. Non ci si ritroverà ad usarla spesso.
Il comando iptables
Iptables è sia il nome dell'infrastruttura a catene con cui si definiscono le policy di firewalling di un sistema basato su netfilter che il comando, utilizzabile da shell, con cui si configura e gestisce il tutto.
La sua sintassi è piuttosto variegata e prevede opzioni e impostazioni anche sulla base dei moduli aggiuntivi supportati e permette di: azzerare le catene esistenti, aggiungere regole, rimuovere regole, impostare le policy di default, creare nuove catene custom, azzerare i contatori ecc.
Comodi comandi ausiliari sono iptables-save
e iptables-restore
che si usano rispettivamente per salvare e ripristinare le configurazioni del firewall.
Le impostazioni sono immediatamente applicate sul sistema fino al momento in cui non si riavvia, per ripristinarle dopo un reboot, è necessario salvare su un file.
Le distribuzioni Linux possono avere file diversi di configurazione e diversi script di avvio, con cui le iptables sono gestite come un servizio, ma la sintassi del comando iptables resta comunque comune.
Attraversamento delle catene
La sequenza con cui vengono processate le varie catene dal Kernel ha questa logica, nel caso si faccia forwarding:
RETE A - MANGLE PREROUTING - NAT PREROUTING - ROUTING - FILTER FORWARD - ROUTING - RETE B
Oppure, per pacchetti in entrata o in uscita:
RETE A - MANGLE PREROUTING - NAT PREROUTING - ROUTING - FILTER INPUT - LOCAL PROCESS - MANGLE OUTPUT - NAT OUTPUT - FILTER OUTPUT - ROUTING - RETE B
I pacchetti attraversano le catene che sono destinati a percorrere, secondo l'ordine delle regole impostate. Se un pacchetto matcha le condizioni definite in una regola, allora segue le indicazioni specificate nel target (ACCEPT, DROP, DNAT) e , in molti casi, interrompe l'attraversamento. Se non matcha nessuna regola di una catena, segue la policy di default impostata per quella catena.
Per questo motivo è fondamentale l'ordine con cui sono inserite le regole in una catena.
Iptables è il comando utilizzato per settare, modificare e cancellare rule riguardanti il packet filtering del kernel linux.
Di seguito verranno riportati le principali opzioni e le sintassi più utilizzate:
Aggiunge una regola alla fine della catena scelta oppure la modifica o cancella:
iptables -[ADC] chain rule-specification [options]
Sostituisce regola o la inserisce all'inizio della catena
iptables -[RI] chain rulenum rule-specification [options]
Visualizza, svuota o azzera i contatori della catena selezionata:
iptables -[LFZ] [chain] [options]
Crea o aggiunge una nuova catena
iptables -[NX] chain
Setta la policy di default della catena
iptables -P chain target [options]
COMANDI
-A, --append
Aggiunge una regola in fondo alla catena
-D, --delete
Cancella una regola
-R, --replace
Esegue il replace di una regola
-I, --insert
Inserisce la regola all'inizio della catena o alla posizione indicata.
-L, --list
Visulizza l'elenco delle regole inserite
-F, --flush
Svuota le catene predefinite
-Z, --zero
Azzera i contatori di ogni catena
-N, --new-chain
Crea una nuova catena custom
-X, --delete-chain
Cancella una catena (creata dall'utente)
-P, --policy
Setta la policy di default per una catena
PARAMETRI
-p ,--protocol [protocol]
Specifica su quale protocollo deve matchare la regola
-s, --source address[/mask], -src
Specifica l'IP sorgente.
-d, --destination address[/mask], -dst
Specifica l'IP destinazione
-j, --jump
Specifica il target a con cui gestire il pacchetto matchato: può essere una catena custom o un target esistente (drop,accept etc..)
-i, --interface
Specifica da quale interfaccia è in entrata un pacchetto. Opzione valida solo per INPUT, FORWARD e PREROUTING.
-o, --out-interface
Specifica l'interfaccia d'uscita di un pacchetti. Opzione valida per FORWARD, OUTPUT e POSTROUTING.
TARGET
DROP
I pacchetti che "matchano" la regola vengono droppati.
ACCEPT
I paccheti che "matchano" la regola vengono fatti passare.
RETURN
Il pacchetto smette di attraversare la catena e passa a quella successiva o segue il comportamente di default
QUEUE
Se il kernel lo supporta il pacchetto passa a livello user-space dove può essere manipolato da programmi vari.
REJECT
Il pacchetto viene rifiutato con un messaggio di notifica al mittente (es: icmp destination unreachable)
LOG
Il pacchetto viene loggato via syslog.
MARK
Il pacchetto viene marcato per essere gestito da programmi in user space.
MASQUERADE
L'IP del pacchetto viene mascherato.
MIRROR
Viene rimandato al mittente un pacchetto speculare a quello ricevuto
REDIRECT
Il pacchetto viene redirezionato ad una porta locale
ALTRE OPZIONI
-v --verbose
Abilita il verbose mode
-n
Abilita la visualizzazione numerica, senza DNS reverse lookup
--linenumbers
Quando viene eseguito il list delle regole viene aggiunto un numero ad ogni regola che corrisponde la posizione della regola nella sua catena.
!
Inverte il significato dell'opzione che lo segue
Comando su Linux che permette di configurare in run-time e visualizzare alcuni parametri del kernel.
Particolarmente utile per il tuning del sistema, in particolare:
- Tuning dei Parametri della Network
- Tuning dei Parametri della memoria virtuale
- Tuning dei Parametri del filesystem
Per verificare le opzioni:
sysctl [-n] [-e] variable ...
sysctl [-A]
Per modificare le opzioni:
sysctl [-n] [-e] -w variable=values
Per rileggere il file di condfigurazione:
sysctl [-n] [-e] -p [file di configurazione]
-A
Printa in stdout tutti i valori attualmente disponibili
-n
Disabilita il print in stdout del nome della variabile
-e
Ignora eventuali errori nel nome della variabile
-w
Opzione per modificare il settaggio di sysctl
-p
Carica le opzioni di sysctl da un file. Default /etc/sysctl.conf
File di configurazione contenente le opzioni del kernel modificabili in run-time.
Di seguito verra' riportato un esempio di questo file con alcune opzioni abilitate di default da RedHat.
E' fondamentale abilitare net.ipv4.ip_forward (forwarding dei pacchetti IP) se il proprio Linux deve fare da firewall/router.
Di fatto vengono modificati i parametri contenuti nel /proc filesystem.
Abilitando (1) ,disabilitando (0), o il Tuning di alcuni parametri del kernel:
Precisamente si possono modificare i valori del kernel in run-time per i seguenti campi
- Virtual memory
- File System
- Network
Ecco il cat del file in configurazione RedHat Standard:
[neo@dido neo]$ cat /etc/sysctl.conf
# Disables packet forwarding
net.ipv4.ip_forward = 0
# Enables source route verification
net.ipv4.conf.default.rp_filter = 1
# Disables the magic-sysrq key
kernel.sysrq = 0
A causa di un bug di alcuni router, inoltre, se l'ECN (Explicit Congestation Notification) è abilitato, ciò che sta dietro a tali router NON sarà raggiungibile.
Il tutto si risolve disabilitando l'ECN nel kernel, intervenendo in /etc/sysctl.conf con una riga tipo:
net.ipv4.tcp_ecn= 0
Il port knocking è un modo molto interessante di abilitare l'accesso a vari servizi (classico sshd ad esempio) senza dover tenere sempre aperta la porta sul firewall. Una misura di sicurezza aggiuntiva molto efficace con un basso costo di gestione e praticamente nessuna contro indicazione.
Partiamo dal presupposto di avere sul nostro server un firewall basato su IPTABLES con tutte le porte chiuse, e abbiamo la necessità di accedere da remoto tramite ssh. La strada che vogliamo evitare è quella di utilizzare il port forwarding aprendo la porta sul firewall e inoltrandola al server o di aprire la porta del servizio sshd (è solo un esempio, potrei voler abilitare altri servizi) direttamente.
Qui entra in gioco il PORT KNOCKING. Vige il principio client/server, ove il server prevede un file di configurazione non troppo complicato e il client è facilmente impostabile tramite parametri.
Il meccanismo è questo: il client esegue una sequenza di richieste di accesso (lancia dei SYN) a porte di servizio arbitrarie entro un tempo stabilito, questa sequenza viene riconosciuta ed abilita l'apertura di una determinata porta corrispondente ad un preciso servizio.
IPTABLES dinamicamente quindi, cambia le sue RULES, in virtù di una sequenza stabilita e riconosciuta (questi sono i parametri da impostare nel file di configurazione del client e del server).
Ad esempio: entro 10 secondi devo interrogare 3 porte e per ultima quella relativa al servizio utile (esempio sshd) , se la sequenza delle tre porte è giusta, sshd verrà abilitato e inizierà la regolare procedura di autenticazione su questo servizio.
Personalmente questo sistema di sicurezza mi ha entusiasmato, forse per la sua semplicità direttamente proporzionale alla sua efficacia.
Questa ... roba, questo testo, questa inezia, probabilmente non fa ridere nessuno.
Ma è stato scritto nel secolo scorso, e trovo adeguato riciclarlo qui.
Non serve? Non vale? Non è gradito? Non diverte?
Non importa.
In fondo è stato scritto nel 1998.
Roba del 900, appunto.
Se i giornalisti lo sapessero ci sarebbe di che divertirsi.
I più smaliziati li chiamerebbero pacchetti killer, altri la fine di Internet, molti vandalismi da hacker, su Gioia parlerebbero di programmi molesti.
Si moltiplicano le mutazioni sui pacchetti ammazza reti.
Dall'ormai vecchio teardrop, roba di fine '97, a gentili variazioni sul tema.
La procedura sembra assodata.
Qualcuno pubblica il sorgente che scrambla a dovere il buon pacchetto scelto per il sacrificio.
In 8 ore esce la patch per Linux, strillato abbondantemente sulla Home di Linux.org, in 5 giorni Microsoft, sempre concerned sulla sicurezza del suo robusto sistema operativo di rete, mette in linea la sua pezza.
Per trovarla uno deve rovistare accuratamente nell'enorme e informativo sito.
Il wannabe hacker del caso, sentendosi cool per aver letto la pagina underground giusta, compila qualche riga di .c e tira giù siti random.
Sembra stia diventando passatempo da weekend trovare nuovi modi per tirar giù host in rete.
Hai un server NT?
O patch o cadi.
Il macchinone ha le gambe aperte alla rete, e da lì ci mettono poco ad infilarci una raffica di byte contorti che ti fanno sclerare in un microsecondo il Netserver con doppia ventola, case allargato che luccica come una discoteca, e sistemi di sicurezza avanzati assortiti.
E non solo server NT, su sistemi Unix esce un bug al giorno.
O ti aggiorni o ti roottano.
Sembra una corsa folle all'ultimo aggiornamento, mentre venditori folli in giro parlano di commercio elettronico, firma digitale, soluzioni sicure e via blaterando.
Per non dire dei router, la cui unica sicrezza sta nei loro arcani e elitari sistemi operativi. Se i loro sorgenti fossero facilmente reperibile, mi sa, ci sarebbe di che sorprendersi.
E via verso la rete del nuovo millennio, dove ci faremo passare flussi finanziari e compavendite assortite, informazioni confidenziali e porno stream.
Fra intranet ed extranet ci sarà sempre una undernet che potrà gozzovigliare con l'illusoria sicurezza della supernet.
Segue un esempio di configurazione del file /etc/sysctl.conf (dove, in molte distribuzioni vengono impostati i parametri da passare al kernel durante la fase di boot) ottimizzato per essere utilizzato su un firewall.
* WORK IN PROGRESS *
net.ipv4.ip_forward = 1
net.ipv4.ip_dynaddr = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_sack = 0
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_window_scaling = 0
net.ipv4.tcp_syn_retries = 3
net.ipv4.tcp_synack_retries = 3
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.log_martians = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
kernel.printk = 1 4 1 7
##
net.ipv4.tcp_max_syn_backlog=1280
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.all.forwarding=0
net.ipv4.conf.all.mc_forwarding=0
net.ipv4.vs.timeout_timewait=60
Segue un esempio di configurazione di base di iptables da applicare direttamente su un server pubblico per proteggere la macchina stessa ed esporre solo le porte strettamente necessarie. Il file è nel classico formato di output del comando iptables-save
, le sue impostazioni possono quindi essere quindi importate con iptables-restore < nomefile.txt
.
Tipicamente, su distribuzioni come RedHat, queste impostazioni sono salvate in /etc/sysconfig/iptables
.
# Di default viene droppato il traffico in entrata e in forward. Si accetta invece il traffico in uscita, in linea con il principio, applicato in questo esempio, di mantenere delle impostazione di base essenziali, non eccessivamente stringenti e paranoiche (per evitare complicazioni in fase di implementazione) ma comunque efficaci.
# Le regole applicate, da adattare al proprio caso, permettono:
# - Accesso da Internet alle porte 80 (http), 443 (https), 25 (smtp), 110 (pop3)
# - Accesso via ftp (porta 21) solo da una rete specifica
# - Accesso via ssh (porta 22) solo da un host specifico
# - Regola per permettere l'ingresso in entrata di tutti i pacchetti correlati a connessioni precedentemente stabilite in uscita
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 110 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A INPUT -s 10.42.42.1 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -s 10.42.42.0/255.255.255.0 -p tcp -m tcp --dport 21 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# Segue, commentata, una riga che permette di abilitare il logging dei pacchetti droppati (è l'ultima prima del DROP di default della catena), viene specificata una stringa di prefisso e il livello di logging, in modo da poter isolare questi log tramite syslog: Aggiungere in /etc/syslog.conf una riga tipo "kern.debug /var/log/firewall.log"
# -A INPUT -i eth0 -m pkttype --pkt-type ! broadcast -j LOG --log-prefix "[INPUT DROP] : " --log-level 7 --log-tcp-options --log-ip-options
COMMIT
#Seguono le impostazioni di NAT di default, dove nessuna regola viene impostata
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
#Seguono le impostazioni di MANGLE di default, dove nessuna regola viene impostata
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
Suse 9's firewall management is in the hands of the SuSEfirewall2 package and (obviously) based on iptables. The package provides a main script /sbin/SuSEfirewall2
and various initialization and configuration scripts that present a user friendly logic that hides the raw syntax of the iptables command.
The configuration can be done with YaST2 graphical interface or editing directly the main configuration file /etc/sysconfig/SuSEfirewall2
.
The questions asked in YaST2 have their equivalent in the variables configured in this file, which define various (well commented) parameters function-oriented such as:
FW_QUICKMODE="no"
FW_DEV_EXT="eth1"
FW_DEV_INT="eth0"
FW_DEV_DMZ=""
FW_ROUTE="yes"
FW_MASQUERADE="yes"
FW_MASQ_DEV="$FW_DEV_EXT"
FW_MASQ_NETS="0/0"
FW_PROTECT_FROM_INTERNAL="no"
FW_AUTOPROTECT_SERVICES="no"
# FW_SERVICES_EXT_TCP="www"
# FW_SERVICES_DMZ_UDP="syslog"
FW_SERVICES_EXT_TCP="http ssh telnet"
FW_SERVICES_EXT_UDP=""
FW_SERVICES_EXT_IP=""
FW_SERVICES_DMZ_TCP=""
FW_SERVICES_DMZ_UDP=""
FW_SERVICES_DMZ_IP=""
FW_SERVICES_INT_TCP=""
FW_SERVICES_INT_UDP=""
FW_SERVICES_INT_IP=""
# FW_SERVICES_QUICK_TCP="ssh"
# FW_SERVICES_QUICK_UDP="isakmp"
# FW_SERVICES_QUICK_IP="50"
FW_SERVICES_QUICK_TCP=""
FW_SERVICES_QUICK_UDP=""
FW_SERVICES_QUICK_IP=""
FW_TRUSTED_NETS=""
FW_ALLOW_INCOMING_HIGHPORTS_TCP="no"
FW_ALLOW_INCOMING_HIGHPORTS_UDP="DNS"
FW_SERVICE_AUTODETECT="yes"
FW_SERVICE_DNS="no"
FW_SERVICE_DHCLIENT="no"
FW_SERVICE_DHCPD="no"
FW_SERVICE_SQUID="no"
FW_SERVICE_SAMBA="no"
FW_FORWARD=""
FW_FORWARD_MASQ=""
FW_REDIRECT=""
FW_LOG_DROP_CRIT="yes"
FW_LOG_DROP_ALL="yes"
FW_LOG_ACCEPT_CRIT="yes"
FW_LOG_ACCEPT_ALL="no"
FW_LOG="--log-level warning --log-tcp-options --log-ip-option --log-prefix SuSE-FW"
FW_KERNEL_SECURITY="yes"
FW_STOP_KEEP_ROUTING_STATE="no"
FW_ALLOW_PING_FW="yes"
FW_ALLOW_PING_DMZ="no"
FW_ALLOW_PING_EXT="no"
FW_ALLOW_FW_TRACEROUTE="yes"
FW_ALLOW_FW_SOURCEQUENCH="yes"
FW_ALLOW_FW_BROADCAST="no"
FW_IGNORE_FW_BROADCAST="yes"
FW_ALLOW_CLASS_ROUTING="no"
#FW_CUSTOMRULES="/etc/sysconfig/scripts/SuSEfirewall2-custom"
FW_CUSTOMRULES=""
FW_REJECT="no"
# FW_HTB_TUNE_DEV="ppp0,125"
# FW_HTB_TUNE_DEV="ppp0,250"
FW_HTB_TUNE_DEV=""
The init scripts are divided in three stages: /etc/init.d/SuSEfirewall2_init
, /etc/init.d/SuSEfirewall2_setup
and /etc/init.d/SuSEfirewall2_final
which are easily managed by the rcSuSEfirewall2
script.
Sample configurations and some docs can be found in /usr/share/doc/packages/
and, while it's still possible to use the iptables command in the interactive shell or in custom scripts, the easy and fast choice is surely to comform to the SuSEfirewall2 logic.
The SuSEfirewall2
command provides some nice options:
SuSEfirewall2 start|stop
Applies or removes the iptables.
SuSEfirewall2 status
Show the status of the iptables (provides the output of iptables -L -nv
).
SuSEfirewall2 test
Simulates the rules, logging all the packets that would be dropped.
SuSEfirewall2 debug
Prints to stdout the iptables commands that could be applied, without actually executing them.
Visualizza le regole inserite nella tabella NAT, più precisamente delle seguenti Chain:
- POSTROUTING
- PREROUTING
- OUTPUT
Indicando inoltre le statistiche delle singole rule.
[root@GIOVE root]# iptables -t nat -L -nv
Rule relative alla catena di Prerouting
Chain PREROUTING (policy ACCEPT 71106 packets, 8718K bytes)
pkts bytes target prot opt in out source destination
25 1236 DNAT tcp -- * * 0.0.0.0/0 10.0.0.1 tcp dpt:1111 to:10.0.0.170:1723
17 968 DNAT tcp -- eth1 * 0.0.0.0/0 10.0.0.2 to:10.0.0.170
Rule relative alla catena di Postrouting
Chain POSTROUTING (policy ACCEPT 77 packets, 4597 bytes)
pkts bytes target prot opt in out source destination
41015 3171K MASQUERADE all -- * eth1 10.0.0.0/24 0.0.0.0/0
Rule relative alla catena di Output
Chain OUTPUT (policy ACCEPT 35 packets, 2393 bytes)
pkts bytes target prot opt in out source destination
Segue un esempio dello stdout del comando iptables, quando si richiama la visualizzazione delle regole installate sul sitema con le relative statistiche.
In questo caso verranno visualizzate le rule e le relative statistiche delle catene di default ovvero INPUT,FORWARD ed OUTPUT
[root@ululo root]# iptables -L -x -v -n --line-numbers
INPUT CHAIN RULES
Chain INPUT (policy DROP 125 packets, 5564 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 DROP all -- eth1 * xx.xx.xx.xx 0.0.0.0/0
2 0 0 DROP all -- eth1 * 10.0.0.0/8 0.0.0.0/0
3 0 0 DROP all -- eth1 * 172.16.0.0/12 0.0.0.0/0
4 0 0 DROP all -- eth1 * 192.168.0.0/16 0.0.0.0/0
5 0 0 DROP all -- eth1 * 224.0.0.0/4 0.0.0.0/0
6 0 0 DROP all -- eth1 * 240.0.0.0/5 0.0.0.0/0
7 0 0 DROP all -- eth1 * 0.0.0.0/0 127.0.0.0/8
8 0 0 ACCEPT all -- * * 127.0.0.0/8 0.0.0.0/0
9 1817 139869 ACCEPT all -- eth1 * xx.xx.xx.xx/xx 0.0.0.0/0
10 0 0 ACCEPT all -- eth1 * xx.xx.xx.xx/xx 0.0.0.0/0
11 0 0 ACCEPT icmp -- * * xx.xx.xx.xx/xx 0.0.0.0/0
12 0 0 ACCEPT icmp -- * * xx.xx.xx.xx/xx 0.0.0.0/0
13 0 0 ACCEPT udp -- eth1 * xx.xx.xx.xx 0.0.0.0/0 udp spt:53
14 0 0 ACCEPT udp -- eth1 * xx.xx.xx.xx 0.0.0.0/0 udp spt:53
15 0 0 ACCEPT tcp -- * * xx.xx.xx.xx/xx 0.0.0.0/0 tcp dpt:22
16 0 0 ACCEPT tcp -- * * xx.xx.xx.xx/x 0.0.0.0/0 tcp dpt:22
17 72 4688 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state ESTABLISHED
18 0 0 ACCEPT udp -- eth1 * 0.0.0.0/0 0.0.0.0/0 state ESTABLISHED
19 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
20 0 0 ACCEPT tcp -- * * xx.xx.xx.xx/xx 0.0.0.0/0 tcp dpt:xx
21 0 0 ACCEPT tcp -- * * xx.xx.x.xx 0.0.0.0/0 tcp dpt:xx
22 1032 142364 ACCEPT all -- eth0 * 10.0.0.0/24 0.0.0.0/0
FORWARD CHAIN RULE
Chain FORWARD (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT tcp -- * * xx.xx.xx.xx/xx 0.0.0.0/0 tcp dpt:xx
2 56 4512 ACCEPT tcp -- * * xx.xx.xx.xx 0.0.0.0/0 tcp dpt:xx
3 18364 1982359 ACCEPT all -- * * 10.0.0.0/24 0.0.0.0/0
4 0 0 DROP tcp -- * * 0.0.0.0/0 10.0.0.0/24 tcp flags:0x16/0x02
5 20035 11377009 ACCEPT all -- * * 0.0.0.0/0 10.0.0.0/24
OUTPUT CHAIN RULE
Chain OUTPUT (policy DROP 35 packets, 45580 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- * * 0.0.0.0/0 127.0.0.0/8
2 0 0 ACCEPT udp -- * eth1 0.0.0.0/0 0.0.0.0/0 udp spts:32769:65535 dpts:33434:33523 state NEW
3 1118 231400 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW,ESTABLISHED
4 1 73 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW,ESTABLISHED
5 10 615 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW,RELATED,ESTABLISHED
6 0 0 ACCEPT all -- * eth0 0.0.0.0/0
Visualizzazione delle rule e relative statistiche della tabella nat
[root@ululo root]# iptables -L -x -v -n -t nat --line-numbers
PREROUTING CHAIN RULE
Chain PREROUTING (policy ACCEPT 2746 packets, 207204 bytes)
num pkts bytes target prot opt in out source destination
1 6 288 DNAT tcp -- * * 0.0.0.0/0 xx.xx.xx.xx tcp dpt:xx to:xx.xx.xx.xx:xx
2 3 194 DNAT 47 -- eth1 * 0.0.0.0/0 xx.xx.xx.xx to:xx.xx.xx.xx
POSTROUTING CHAIN RULE
Chain POSTROUTING (policy ACCEPT 11 packets, 628 bytes)
num pkts bytes target prot opt in out source destination
1 2147 116727 MASQUERADE all -- * eth1 10.0.0.0/24 0.0.0.0/0
OUTPUT CHAIN RULE
Chain OUTPUT (policy ACCEPT 205 packets, 14004 bytes)
num pkts bytes target prot opt in out source destination
Servknock e' un sistema di portknocking composto da client e server, chiamati con estrema fantasia knock e servknock, caratterizzato dalle seguenti features :
- Rilevamento delle sequenze tramite la libreria libPcap;
- Utilizzo di sequenze di knock crittate, comprendenti anche l'indirizzo IP del richiedente;
- Possibilita' di includere nella sequenza di knock sia pacchetti TCP, UDP che ICMP;
- Possibilita' di discriminare i pacchetti TCP della sequenza in base ai flag impostati.;
- Possibilita' di specificare diverse sequenze di knock per eventi differenti
- Elementi della sequenza di knock mischiati con un pattern casuale di traffico di rete.;
- Possibilita' di eseguire comandi shell arbitrari e non solamente manipolare le regole di filtraggio del firewall.
- Possibilita' di eseguire piu' di un comando al riconoscimento di una sequenza
- Possibilita' di eseguire due differenti serie di comandi, la prima al riconoscimento della sequenza , e la seconda trascorso un timeout specificato.
Installazione
Il sistema su cui si desidera installare servknock non necessita di particolari configurazioni.
E' infatti sufficiente avere netfilter correttamente configurato, ed i moduli necessari caricati (ad esempio iptable_nat, ipt_MASQUERADE, ip_conntrack in caso si abbia la necessita' di ricorrere alla Network Address Translation), a meno che essi non siano gia' stati inclusi direttamente nel kernel in fase di compilazione.
Come sistema di riferimento e' stata utilizzata debian GNU/Linux 3.1 con kernel della serie 2.6 .
I passi da seguire per l'installazione del programma sono i seguenti :
1. Installare le librerie Libpcap, LibMcrypt, LibMhash e LibNet 1.1 necessarie per compilare i sorgenti. :
apt-get install libpcap-dev
apt-get install libmcrypt-dev
apt-get install limhash-dev
apt-get install libnet1-dev
2. Scaricare e decomprimere il tarball di servknock dall'url http://stargazer.altervista.org/pk/servknock_1.12.tar.gz :
wget http://stargazer.altervista.org/pk/servknock_1.12.tar.gz
tar -zxvf servknock_1.12.tar.gz
3. Se si desidera compilare esclusivamente il portknocking server digitare il comando : make servknock
Il sistema comprende anche un client per la generazione delle sequenza di knock, che puo' essere compilato come segue: make knock
.
Per avviare invece la compilazione di entrambi i programmi e' sufficiente digitare: make all
Se il processo e' andato a buon fine, nella directory saranno presenti due nuovi eseguibili, chiamati knock e servknock.
4. Per non specificare l'intero percorso ad ogni esecuzione dei due programmi, copiarli all'interno di una directory compresa nella variabile d'ambiente $PATH, ad esempio /usr/sbin. E' inoltre necessario creare la directory /etc/servknock e copiare al suo interno il file servknock.conf. Tale procedura puo' essere effettuata in modo automatizzato direttamente con il comando : make install
Configurazione del server
La prima parte del file di configurazione del server (servknock.conf) e' costituita dalla successiva serie di coppie chiave=valore, che descrivono le opzioni di configurazione generali :
- iface : nome del'interfaccia sulla quale catturare il traffico, come ad esempio eth0, ppp0 ecc.
- cypher : l'algoritmo da utilizzare nelle operazioni di cifratura/decifratura delle sequenze di knock. Attualmente gli cifrari supportati sono gli algoritmi a chiave simmetrica blowfish, twofish, xtea, rijndael e serpent.
- password : la stringa necessaria per generare la chiave utilizzata nelle operazioni crittografiche. Ovviamente lavorando con algoritmi a chiave simmetrica, anche il richiedente deve utilizzare la medesima chiave per la costruzione delle sequenze di knock dirette al server.
- iv : stringa utilizzata per generare il vettore di inizializzazione. Come per la chiave, deve essere uguale sia lato server che client.
- span : gli intervalli di porte monitorati da servknock , per il riconoscimento delle sequenze. Perche' il programma possa essere correttamente avviato e' necessario che la somma di tutti i range di porte valga esattamente 255.
- logfile : il nome del file dove loggare le sequenze riconosciute ed i comandi eseguiti.
Nella seconda parte vengono invece definite le diverse sequenze di knock.
Ognuna di esse e' compresa entro i tag <:seq> e </seq>, ed include le seguenti opzioni :
- name : il nome della sequenza;
- sequence : i pacchetti di rete che la compongono, comprese le rispettive porte di destinazione, nel caso si dei pacchetti TCP ed UDP ;
- tcp_flags : i flag che devono essere settati nei pacchetti TCP ;
- seq_timeout : intervallo di tempo espresso in secondi entro il quale deve venire completata la sequenza;
- command : comando da eseguire al riconoscimento della sequenza. Nel caso alla sequenza fossero associati piu' comandi, devono essere presenti diverse linee con l'opzione command : una per ognuno di essi.
- cmd_timeout : intervallo di tempo a partire dal momento del riconoscimento della sequenza, trascorso il quale eseguire i comandi specificati dall'opzione stop_command.
- stop_command : comando da eseguire una volta trascorsi un numero di secondi secondi pari al valore specificato in cmd_timeout, a partire dal riconoscimento della sequenza di knock. Nel caso si desideri associare piu' comandi alla sequenza, e' sufficiente inserire diverse righe stop_command.
Per la manipolazione delle regole di filtraggio, e' qundi possibile seguire due approcci : avere sequenze diverse per l'inserimento e la rimozione della regola stessa, oppure una sequenza singola, utilizzando le opzioni cmd_timeout e stop_command. A titolo esemplificativo, viene riportato il seguente stralcio di file di configurazione:
###############################
# Portknocking server
###############################
iface=eth0
# blowfish |twofish | xtea | rijndael-128 | serpent
cypher=rijndael-128
password=metALm3lTd0wn
iv=Pa1nkilL3r
span=7000-7100,7500-7655
logfile=/var/log/servknock.log
<seq>
name=ssh_open
sequence=UDP:222,ICMP,TCP:56,UDP:22,TCP:99
seq_timeout=60
tcp_flags=ack,psh
command=iptables -A INPUT -s $IP -p tcp --dport 22 -j ACCEPT
</seq>
<:seq>
name=ssh_close
sequence=UDP:212,TCP:149,ICMP,UDP:42,TCP:199,TCP:180
seq_timeout=60
tcp_flags=syn,psh,fin
command=iptables -D INPUT -s $IP -p tcp --dport 22 -j ACCEPT
</seq>
<:seq>
name=apache
sequence=TCP:90,UDP:44,ICMP
tcp_flags=syn,ack,psh
seq_timeout=60
command=iptables -A INPUT -s $IP -p tcp --dport 80 -j ACCEPT
cmd_timeout=1000
stop_command=iptables -D INPUT -s $IP -p tcp --dport 80 -j ACCEPT
</seq>
Perche' il sistema funzioni correttamente e' infine necessario impostare le regole iniziali di filtraggio di netfilter, ricorrendo ad iptables. All'interno del tarball di ServkKnock e' compreso a titolo esemplificativo lo shellscript
fwall.sh, utilizzabile per i test. Naturalmente esso non e' indicato per l'utilizzo in un ambiente di produzione.
Esecuzione del server
ServKnock puo' essere semplicemente avviato con il comando servknock
. Un'altro metodo, utilizzabile nei sistemi con init System-V, e' quello di inserire uno shellscript per l'avvio di ServKnock (chiamandolo ad esempio
servknock.sh) nella directory /etc/init.d .In questo modo sara' possibile avviare e fermare il programma con i comandi /etc/init.d/servknock.sh start
ed /etc/init.d/servknock.sh stop
Infine se si desidera avviare il server in fase di boot, o comunque associarne l'esecuzione ad uno specifico runlevel e' necessario aggiungere una chiamata a servknock nella struttura di init del sistema con un link simbolico del tipo /etc/rc3.d/S90servknock.sh che punti a /etc/init.d/servknock.sh).
Per semplicita', negli esempi riportati ServKnock verra' sempre avviato direttamente da shell, dove la linea di comando da utilizzare e' cosi' strutturata : servknock [OPTION] [ -f <conf_file> ]
.
Le opzioni ammissibili sono le seguenti :
-d : daemon mode. Permette di fare girare il programma come un processo demone, eseguito in background.
-h : stampa a video una pagina di help
-D : debug mode . Se specificata, questa opzione consente di stampare sullo standard output diverse informazioni, relative ai parametri di configurazione, le operazioni svolte ed i pacchetti analizzati. Non e' consentito specificare contemporaneamente le opzioni -d e -D .
-f : permette di utilizzare un file di configurazione alternativo a quello di default ( /etc/ servknock.conf ). E' possibile specificare sia path relativi che assoluti.
-V : verbose mode. Consente di stampare sullo standard output alcune informazioni sintetiche sulle sequenze riconosciute ed i comandi eseguiti. Come per il debug mode, non e' permesso specificare contemporaneamente le opzioni -V e -d .
Esecuzione del client
Nel tarball di ServKnock e' presente anche un secondo programma chiamato knock, utilizzato per generare le sequenze di knock ed inviarle al PortKnocking server, dal quale possono essere riconosciute e di conseguenza portare all'esecuzione delle azioni previste in risposta.
Come per il PortKnocking server, anche per il client esiste un relativo file di configurazione, chiamato knockrc. La sua struttura e' del tutto simile a quella di servknock.conf, con la prima parte del file costituita da una serie di coppie chiave=valore, che descrivono le opzioni di configurazione generali, e la seconda in cui sono definite le diverse sequenze.
Il significato delle opzioni ammissibili in knockrc, sono del tutto identiche a quelle del file di configurazione di servknock. E' comunque necessario ricordare come alcune di esse siano specifiche di servknock.conf e quindi non utilizzabili. Non e' infatti prevista l'opzione logfile, mentre nella definizione di una sequenza di knock sono ammesse esclusivamente name, sequence, e tcp_flags.
Ovviamente perche' le sequenze possano essere riconosciute, le opzioni utilizzate debbono corrispondere con quelle definite nel file di configurazione del PortKnocking server, con name come unica possibile eccezione.
################################
# Knock Client conf file
###############################
# blowfish | twofish | xtea | rijndael-128 | serpent
cypher=rijndael-128
iv=Pa1nkilL3r
password=metALm3lTd0wn
span=7000-7100,7500-7655
#open port 22
<seq>
name=open_ssh
sequence=UDP:222,ICMP,TCP:56,UDP:22,TCP:99
tcp_flags=ack,psh
</seq>
#close port 22
<seq>
name=close_ssh
sequence=UDP:212,TCP:149,ICMP,UDP:42,TCP:199,TCP:180
tcp_flags=syn,psh,fin
</seq>
#open port 80
<seq>
name=apache
sequence=TCP:90,UDP:44,ICMP
tcp_flags=syn,ack,psh
</seq>
Il programma puo' venire invocato con la seguente linea di comando : knock -d <host> -i <interface> -s <sequence name> [-g <address>] [-f <conf file>]
.
Le opzioni ammissibili sono le seguenti :
-d : indica l'host al quale inviare la sequenza di knock. E' possibile specificare indifferentemente un nome oppure direttamente l'indirizzo IP di destinazione.
-f : permette di utilizzare un file di configurazione alternativo a quello di default (~/.knockrc).
-g : indica l'indirizzo IP dell'eventuale gateway utilizzato.
-h : stampa a video una pagina di help
-i : l'interfaccia da utilizzare per l'invio dei pacchetti, ad esempio eth0, eth1, ppp0 ecc.
-s : il nome della sequenza di knock da generare. Tale nome deve coincidere con l'opzione name di una delle sequenze definite nel file di configurazione. Se tutti i parametri necessari sono stati specificati correttamente, il programma e' in grado di creare i pacchetti della sequenza ed inviarli a destinazione, utilizzando il device indicato :
[TCP] 10359 Smoke packet
[TCP] 7559 Knock packet
[TCP] 5805 Smoke packet
[UDP] 8272 Smoke packet
[TCP] 2567 Smoke packet
[UDP] 7612 Knock packet
[TCP] 7656 Smoke packet
[TCP] 12807 Smoke packet
[ICMP] Knock packet
[TCP] 14457 Smoke packet
[TCP] 7582 Knock packet
[TCP] 8303 Smoke packet
[TCP] 7525 Knock packet
[UDP] 12872 Smoke packet
[TCP] 9951 Smoke packet
[TCP] 7569 Knock packet
[UDP] 4006 Smoke packet
[TCP] 7620 Knock packet
[TCP] 6497 Smoke packet
Come si puo' notare come gli elementi della sequenza di knock vengono inviati all'interno di una sequenza casuale di pacchetti TCP ed UDP.
E' possibile impostare alcuni parametri in fase di compilazione riguardanti la generazione degli smoke packets, modificando il valore delle seguenti costanti definite in knock.h :
/*max nr. of smoke elements between right packets*/
#define SMOKE_NR 3
/*prob. of a smoke packet to be included in the sequence*/
#define SMOKE_PERC 60
/*max port number in a smoke packet, max 65535*/
#define SMOKE_MAX_PORT 9000
/*min port number in a smoke packet, min 1024*/
#define SMOKE_MIN_PORT 4000
NOTA: Nel caso il server non riesca a rilevare correttamente le sequenze, e' necessario rallentare il ritmo di invio dei pacchetti, decomenntando la riga #define MODULE_KNOCK nel file knock.h e ricompilando il client. Se il tempo totale per l'invio della sequenza dovesse a questo punto superare il valore di seq_timout specificato nel file di configurazione del server e' sufficiente aumentare tale valore.
Esempio di utilizzo
1. Il client con indirizzo IP 192.168.0.4 invia una specifica sequenza di knock al server, con il comando knock -d stargazer.localdomain -i eth0 -s apache
:
[TCP] 9543 Smoke packet
[UDP] 4328 Smoke packet
[TCP] 7055 Knock packet
[TCP] 6293 Smoke packet
[TCP] 9625 Smoke packet
[UDP] 7005 Knock packet
[UDP] 8424 Smoke packet
[UDP] 11426 Smoke packet
[ICMP] Knock packet
[TCP] 14587 Smoke packet
[TCP] 7014 Knock packet
[TCP] 7554 Knock packet
[UDP] 6726 Smoke packet
[TCP] 8073 Smoke packet
[TCP] 13369 Smoke packet
[UDP] 4020 Smoke packet
[TCP] 7618 Knock packet
[UDP] 8396 Smoke packet
[UDP] 13206 Smoke packet
[UDP] 9848 Smoke packet
[TCP] 7526 Knock packet
[UDP] 13656 Smoke packet
[TCP] 11985 Smoke packet
2. Il server riconosce tra i pacchetti ricevuti la sequenza TCP:90,UDP:44,ICMP ed esegue i comandi ad essa associati :
[apache] Knock sequence completed
[apache] Command iptables -A INPUT -s $IP -p tcp --dport 80 -j ACCEPT [OK]
3. Il client puo' connettersi all'applicazione protetta, in esecuzione sul webserver.
4. Allo scadere del timeout specificato nel file di configurazione il server
esegue i comandi di "chiusura" associati alla sequenza riconosciuta in
precedenza :
[apache] Command iptables -D INPUT -s $IP -p tcp --dport 80 -j ACCEPT [OK]