Paketfilter, eine Einführung
Inhaltsverzeichnis
- Syntax der verschiedenen Paketfilterloesungen
- Access Control Lists fuer Ciscos
- Access Control Lists fuer Linux mit ipchains
- Access Control Lists fuer Linux mit ipfwadm
- Access Control Lists fuer Ascends
- Grundsaetzliche Probleme
- Fragmente
- FTP
- DNS
- ICMP (Internet Control Message Protocol)(
- RPC-Dienste
- Designprinzip
- Praktisches Beispiel
- Anforderungen
- die ACL
- Einbindung ins System
- Fazit
Eine kleine Einfuehrung in Paketfilter.
Sinn dieses Textes ist ungefaehr zu zeigen wie man es macht und worauf
es ankommt. In den Beispielen wird die Syntax der Linux-ipchains verwendet,
aber die Regeln lassen sich ohne weiteres auf andere Paketfiltersysteme
uebertragen.
Ganz wichtig: Dieser Text ist nicht fehlerfrei. Und damit meine
ich keine Rechtschreibfehler. Ich uebernehme keine Gewaehr.
Syntax der verschiedenen Paketfilterloesungen
Access Control Lists für Ciscos:
Beim cisco löscht man eine ACL mit "no ip access-list NNN",
wobei NNN die Nummer der ACL ist. Ansonsten gibt es nur noch
ein Kommando zum Anhängen.
Wichtig: NNN bestimmt den Typ der ACL - ich verwende hier "extended
ACLs", die bessere Steuerung als die standard ACLs ermoeglichen, die
fuer heutige Zwecke nicht mehr ausreichen.
NNN bewegt sich bei Extended ACLs im Bereich 101..199.
Wichtig ist: jede neue Kommando wird hinten an die ACL angehängt.
im Zweifelsfalls heißt also die Lösung "wegwerfen und neu machen",
oder rcp nehmen. Wobei Wegwerfen, wenn man die Änderung remote macht,
riskant ist (hint: nicht vorhandene ACLs, die irgendwo noch angesprochen
werden, wirken wie "DENY alles"). rcp funktioniert ganz gut.
Im Zweifelsfall legt man eine neue ACL an, trägt die anstelle der
Alten in den Interfaces ein, und löscht dann die alte ACL.
Die Syntax ist:
access-list [permit|deny] NNN PROTOCOL SOURCE [PORTSPEC] \
DEST [PORTSPEC] [established] [log|log-input]
Darin bedeutet:
- permit:
- paket darf durch
- deny:
- paket wird verworfen
- PROTOCOL:
- Art des Protokolls:
- ip für alles (keine PORTSPEC erlaubt)
- icmp
- udp
- tcp
- diverse andere Protokolle.
- SOURCE:
- erlaubte Sourcen
- any alle moeglichen
- host XXX nur maschine XXX (XXX==IP-Adresse)
- XXX YYY alles, was auf IP-Adresse XXX
und Netzmaske YYY paßt.
- PORTSPEC:
- Source/Zielportangabe. Sourceport direkt nach Sourceadresse,
Zielport direkt nach Zieladresse,
- eq XXX port = XXX
- lt XXX port kleiner XXX
- gt XXX port kleiner XXX
- neq XXX port != XXX
- range XXX YYY Port zwischen XXX und YYY einschliesslich
für einige XXX und YYY koennen Namen verwendet werden,
für viele nicht.
- DEST:
- siehe SOURCE
- established:
- Nur für TCP gültig, matcht auf alle Pakete ohne SYN-Flag
(SYN ist Verbindungseröffnung).
- log:
- syslog-Meldung für matchende Pakete erzeugen
- log-input:
- syslog-Meldung für matchende Pakete erzeugen,
mit Angabe des Interfaces (erst ab 11.2).
ACLs muessen, damit sie wirksam sind, noch einem Interface
zugeordnet werden. Beispiel:
interface bri0
ip access-group NNN in|out
(in oder out aus Sicht des Ciscos).
Access Control Lists für Linux mit ipchains
ipchains ist der ACL-Mechanismus, der ab Linux-2.1.10x zur Verfügung
steht. Mir gefällt es aber deutlich besser als die alte Lösung,
und die funktioniert sowieso nicht mehr, weil ich 2.1.102 verwende, also ...
ipchains ist ein Kommando zur Verwaltung der ACLs im Kernel. Im
Normalfall hängt es eine Zeile an, oder löscht eine Zeile oder
fügt eine Zeile ein. Anders gesagt - an dieser Stelle ist es
flexibler als cisco-IOS. Ich benutze das aber so nicht, da ich es
vorziehe immer mit ganzen Listen zu hantieren und nicht einzelne
Kommandos auszuprobieren (aber das ist nur meine Arbeitsweise,
nicht prinzipiell besser).
Es gibt drei globale ACL - input, output und forward.
I/o dürfte klar sein, forward bestimmt das Weiterleiten von
Paketen (I+O zusammen leisten nicht das was F leistet, und
F leistet nichts von dem was I oder O leisten).
In diese globalen ACLs kann man noch weitere Einhängen.
Die Defaultpolicy stellt man mit "ipchains -P" ein, für
jede ACL extra. Beispiel siehe unten.
Außer ACCEPT (paket ist OK) gibt es noch DENY (laß es
verschwinden) und REJECT (sende Host unreachable). DENY ist ein guter
Default für input Rules.
Bei meiner Vorgehensweise - Configdatei verändern und dann ACL
aktivieren, gibt es ein Problem - wenn ich die ACL zwischen-
zeitlich löschen würde um sie neu aufzubauen hätte ich einen
Moment lang keine. Deshalb habe ich ein Script um die eigentliche
ACL gemacht, es setzt die Defaults, legt eine temporäre ACL an,
macht sie zur aktiven ACL, loescht die Alte, legt die Alte wieder
an, macht sie aktiv, löscht die Temporäre wieder.
Vorteil bei diese Vorgehensweise: der Name ist die allermeiste Zeit
identisch - das hilft bei Scripten die die ACL auswerten, ungemein.
Syntax:
- ipchains -A NAME REGEL
- eine Regel an die ACL NAME anhängen
- ipchains -D NAME REGEL
- eine Regel löschen. Exakter Name bitte
- ipchains -D NAME NUMMER
- Regel Nummer NUMMER löschen
- ipchains -C NAME REGEL
- "was wäre wenn". See man page.
- ipchains -R MAME NUMMER REGEL
- eine Regel ersetzen
- ipchains -I NAME NUMMER REGEL
- an Position NUMMER einfügen. Der alte Eintrag und alle
folgenden rutschen nach hinten.
- ipchains -P NAME POLICY
- Defaultpolicy der ACL NAME setzen.
Legende:
- NAME
- Name einer ACL/Chain (bis 8 Zeichen)
- NUMMER
- 1..n.
- POLICY
-
- REJECT läßt ein host unreachable
zurücksenden
- ACCEPT paket erlauben
- DENY paket verschwinden lassen
- REGEL
- der Inhalt der Regel, der Code der bestimmt welche Pakete auf diese
Regel passen und was mit ihnen geschieht.
Regeln werden mit Optionen des Kommandos ipchains angelegt. Das
ist eindeutig nicht so schön wie beim Cisco.
Einige Bedingungen lassen sich negieren, dazu stellt man ein
Ausrufezeichen voran.
- -p [!]PROTOCOL
- Angabe des Protokolls, auf das die Regel paßt. Moeglich
sind
- icmp
- udp
- tcp
- all (Aequivalent zu ip beim Cisco)
- die Nummer eines IP-Protokolls
- -s [!]ADDRESS [![PORTSPEC]]
- Angabe der Absenderadresse
- ADDRESS ist entweder IP-Adresse/netmask oder
IP-Adresse/bits oder IP-Adresse.
- PORTSPEC ist die Angabe des des Sourceports des Pakets.
Hier ist die Angabe einer Portnummer, des Namens eines Dienstes
in /etc/services, und die Angabe eines Bereiches AAA:BBB
moeglich. Bei Bereichsangaben sind Namen oder Nummern moeglich,
die beiden Endpunkte sind eingeschlossen.
AAA hat 0 als Default und ist der Startport.
BBB hat 65535 als Default und ist der Endport.
- -d [!]]ADDRESS [![PORTSPEC]]
- Angabe der Zieladresse. Siehe Sourceadresse.
- [!] -y
- SYN-Flag gesetzt (! -y: SYN-Flag nicht gesetzt == "established")
- -l
- logging (syslog) einschalten
- -i XXX
- Regel gilt für Interface XXX.
- -j NAME
- jump to ACL NAME.
Fuer NAME erlaubt sind die Namen anderer ACLs (Rekursion
sollte hier vermieden werden - nur um das mal gesagt zu haben),
oder die Namen der Policies (DENY,ACCEPT,REJECT).
- [!] -f
- passt auf das 2. bis letzte Teil eines fragmentierten Paketes.
Bei ICMP-Paketen ist der Sourceport der ICMP-Typ, und der
Destination-Port die genauere Spezifizierung ("unreachable" +
"host unreachable").
Access Control Lists für Linux mit ipfwadm
ipfwadm ist die "alte" Paketfilterlösung für Linux. Sie kann
Fragmente nicht vernünftig handhaben (was allerdings auch auf
den cisco-Code zutrifft) und kann nicht atomar die Regeln Updaten.
Nichtsdestotrotz ist 2.0.33 natürlich um etliches stabiler als 2.1.102.
Die Syntax ist recht ähnlich der des ipchains-Kommandos, nur
ein paar Optionen heissen anders, und accept,deny,reject wollen
kleingeschrieben werden.
Es wird grundsätzlich an die Liste angehängt (von denen es auch
hier drei gibt, allerdings ohne die Möglichkeit auf andere ACLs
zu verweisen.
Ich spare mir hier die detaillierte Auffuehrung der Optionen. Die
Syntax ist hinreichend aehnlich der der ipchains, allerdings muss
man auf gross/kleinschreibung achten. Ein Beispiel:
ipfwadm -I -a accept -b -P udp -S 0.0.0.0/0 53 \
-D 194.245.80.2/32 53
Access Control Lists für Ascends:
Besprochen wird nur die Konfiguration von Filterlisten über Radius. Die
Onlinekonfiguration ist einfach zu häßlich und unübersichtlich.
Die Syntax ist:
Ascend-Data-Filter="ip [in|out] [forward|drop] \
[dstip DESTIP/MASKBITS] [srcip SRCIP/MASKBITS] \
[PROTO [dstport CMP DESTPORT] \
[srcport CMP SRCPORT] [EST]]"
Kurze Legende:
- ip:
- Schlüsselwort. Muß einfach sein.
- in:
- Eingehende Pakete filtern (Gegenseite sendet zum Ascend).
- out:
- Ausgehende Pakete filtern (Ascend sendet zur Gegenseite).
- forward:
- Auf die Regel passende Pakete weiterleiten.
- drop:
- Auf die Regel passende Pakete verwerfen.
- destip:
- Schlüsselwort
- DESTIP/MASKBITS
- Ziel-IP-Adresse: Netzmaske und Maskenbits (194.245.80.0/28).
- srcip:
- Schlüsselwort
- SRCIP/MASKBITS
- Quell-IP-Adresse: Netzmaske und Maskenbits (194.245.80.0/28).
- PROTO:
- Protokoll.
- 1 oder icmp
- 6 oder tcp
- 17 oder udp
- 89 oder ospf
- 0 für alle Protokolle (analog zu ip beim Cisco).
Aus der Dokumentation - so man die so nennen kann - geht nicht hervor
ob man auch andere Protokolle anhand ihrer Nummern angeben kann. Ich
vermute mal es geht.
- dstport:
- Schlüsselwort. Dieses und die folgenden Parameter koennen nur fuer
TCP und UDP Pakete genutzt werden.
- CMP:
- <,>, = oder !=. Dient zum Vergleich
der Portnummern.
- DESTPORT:
- Spezifiziert den Zielport. Hier koennen Nummern oder auch einige
Namen (ftp-data,ftp,telnet,smtp,domain,finger,www,nntp,ntp und
noch ein paar mehr - wobei es bezeichnen ist daß der Ascend Radius
Server www versteht und den offiziellen Namen http
nicht). Im Zweifelsfall sollte man Portnummern verwenden.
Wenn mal jemand Lust hat sollte er dem Radiusserver
getservicebyname beibringen. Es ist mir unklar warum die
Ports darin hardcoded sind (na gut, das ist echter Ascend-Code).
- srcport:
- Schlüsselwort. Dieses und die folgenden Parameter koennen nur fuer
TCP und UDP Pakete genutzt werden.
- SRCPORT:
- Spezifiziert den Quellport. Siehe oben.
- est:
- Wirkung wie established beim Cisco. Es kann für
TCP-Verbindungen und laut Ascend-Doku auch für UDP-Verbindungen
genutzt werden (wobei letzteres recht unwahrscheinlich ist, es ergibt
einfach keinen Sinn).
Die Reihenfolge der Schlüsselwörter ist ziemlich variabel, etwa so
flexibel wie man es erwarten würde.
Neben diesen Data Filtern gibt es noch sog. Call Filter.
Die Syntax ist identisch, nur statt Ascend-Data-Filter ist
Ascend-Call-Filter zu benutzen. Sie bestimmen ob der Ascend
wegen eines Paket eine Verbindung aufbaut und setzen gegebenenfalls
den Timeoutzähler zurück, beeinflussen aber nicht den Transfer der
Pakete über schon bestehende Verbindungen.
Wenn kein Eintrag der Filterliste paßt verwirft der Ascend das
Paket bei Data Filtern, und ignoriert es bei Call Filtern.
Will man ICMP oder andere Protokolle filtern, die keine Ports
kennen, wird es umstaendlicher - dann muß man zu sog. generischen
Filtern greifen, die schwieriger zu konfigurieren sind und mit denen
man einzelne Bits im IP-Paket untersuchen kann.
Plus und Minus
- - es gibt keine Loggingmöglichkeiten. (unverzeihlich)
- - es gibt keine Statistiken, der Ascend führt keinen
Zähler mit wie oft eine Regel einer ACL zutraf (das ist allerdings
verzeihlich - die Listen sind aus Sicht des Ascends dynamisch).
- - ICMP Pakete zu filtern ist schwierig
- + über die generischen Filter lassen sich alle möglichen
Paketarten filtern. Hier ist der Ascend deutlich flexibler als
der Cisco oder Linux.
Grundsätzliche Probleme
Fragmente
Manchmal sind IP-Pakete zu groß für das
Übertragungsmedium. Sie werden dann (und manchmal auch aus anderen
Gründen) gesplittet.
Die Steuerinformation - welche Hosts, welche Ports - kommt dabei
nur im ersten Paket (oder über X Pakete verteilt, wenn man die
Pakete klein genug splittet. Das ist beinahe immer nur bei Attacken
zu beobachten).
Wie geht man beim Paketfiltern damit geschickt um? Antwort: Gar nicht.
Es gibt nichts was ein einfacher Paketfilter machen kann - er kann
nicht erkennen ob das Fragment nicht doch ungefährlich und notwendig
ist.
Der Linuxkernel bietet aber die Moeglichkeit, alle Pakete, auch die die
nur durchgereicht werden, vor dem Verarbeiten zusammenzusetzen. Dazu
muss man
- CONFIG_IP_ALWAYS_DEFRAG=y in /usr/src/linux/.config eintragen,
- make oldconfig && make install modules modules_install
aufrufen (oder wie auch immer macht es sonst macht. lilo nicht
vergessen!).
Nachteile:
- things take time - das kann Massendatenübertragungen
etwas verlangsamen.
- das frisst etwas Speicher.
- das funktioniert definitiv nur wenn die Linuxkiste der
einzige Übergang ins Internet ist.
Was tun wenn man nur einen Cisco hat? You lose, dafuer ist der Router
ungeeignet.
FTP
FTP überträgt die Daten und Directory Listings auf einer anderen
Verbindung als die Kommandos. Und da gibt es zwei Versionen:
- active mode
- der Server öffnet eine FTP-Verbindung zum client.
Typischerweise will "man" (der client) das aber nicht - schliesslich
ist schwer unterscheidbar ob der Connect von Port 20 (ftp-data)
auf Port 2049 (ahem - Network Failure System) nicht doch eine Attacke
ist.
- passive mode
- der Client öffnet den zweiten Kanal selbst, auf einen Port,
den der Server vorher mitgeteilt hat (aus Sicht des Paketfilters auf
irgendeinen Port von irgendeinem Port!).
Klingt gut? Wär's auch, wenn nicht:
- der Client das unterstützen müßte.
Viele Programme tun's zwar, aber etliche nicht, und manche nicht
defaultmäßig, sondern erst nach Umkonfiguration.
- der Server selbst hinter einem Firewall stehen könnte ...
dann nämlich mag der nicht Verbindungen von Remote Port XXX auf
Remote Port YYY erlauben.
Wie entkommt man diesem Dilemma, wenn man selbst FTP-Server sein will
und selbst FTP nutzen koennen will?
# ftp
ipchains -A $i -p tcp -y \
-d 194.245.80.2 21 -j ACCEPT
# ftp-data -> NFS
ipchains -A $i -p tcp -y -s 0/0 20 \
-d 194.245.80.2 2049 -j REJECT
# ftp-data -> X
ipchains -A $i -p tcp -y -s 0/0 20 \
-d 194.245.80.2 6000:6010 -j REJECT
# ftp-data -> andere Port >1024: OK.
ipchains -A $i -p tcp -y -s 0/0 20 \
-d 194.245.80.2 1024: -j ACCEPT
Man erlaubt also den Zugriff auf gewisse Ports von port 20 aus - das
kann zwar ein FTP-Server sitzen, _aber_ das muss nicht. Das kann auch
der böse Einbrecher sein. In jedem Fall sollte man andere kritische
Ports auch sperren - siehe unten unter RPC.
Prinzipiell ist das nicht wesentlich sicherer als diese Zeile, die nebenbei
auch incoming passive mode ftp erlaubt:
ipchains -A $i -p tcp -y -s 0/0 1024: \
-d 194.245.80.2 1024: -j ACCEPT
Sie macht es nur einfacher zu sehen dass da noch andere Sachen sind ...
Fazit: ftp ist ein Problem, daß sich mit den Mitteln eines
Paketfilters nicht lösen läßt. man müßte hier
schon mehr Möglichkeiten haben - aber das setzt Überwachung
der FTP-Control-Connection voraus und ähnelt damit mehr einem
richtigen Firewall.
Bei manchen FTP-Servern kann man die Fähigkeit zum passive
mode abschalten, die mir bekannten Clients gehen dann automatisch zum
active mode über (falls der Firewall auf der Seite des Clients das
zuläßt. Katze, Schwanz, Biß).
In jedem Fall sollte man tunlichst darauf achten daß man, wenn man
den Zugriff von Port 20 auf Port X (X>1023) oder von überall auf
Port X freigibt, alle Port noch absichert die oberhalb von 1023 liegen
und in Benutzung sind, z.B. X, NFS, Datenbankapplikationen. Leider ist
das nicht einfach, siehe unten unter RPC (dasselbe kann aber auch
fuer ganz andere Dienste gelten, nicht nur fuer RPC).
DNS
auch bei DNS lauert eine Überraschung. Und zwar koennen ueberlange
DNS-Antworten TCP verlangen. Wenn eine Antwort zu lang ist für das
UDP-Paket (aus Gründen die ich nicht kenne sind UDP-DNS-Pakete auf
5xx Bytes limitiert) muß der Anfragende den Rest per TCP abholen.
Das heißt: wenn man DNS-Server ist muß man auch beliebige
TCP-Verbindungen von aussen auf port 53 erlauben _oder_ dafür Sorge
tragen daß der Fall nicht auftreten kann (keine überlangen
TXT-Pakete).
ICMP (Internet Control Message Protocol)
ICMP beinhaltet ping, ping reply, host unreachable, source quench (hey Absender,
Du sendest zu schnell, halt mal ein), etc usw.
Man sieht also problemlos daß dies zu filtern üble Konsequenzen
haben kann.
Andererseits sind icmps beliebte Träger für Attacken (jolt).
Was also tun? Hat man eine Linuxmachine zur Verfuegung kann man diese
alle Pakete defragmentieren lassen. Ansonsten kann man versuchen nur
die wichtigsten ICMPs durchzulassen - dazu zaehlt insbesondere Typ 3,
die "unreachables".
RPC-Dienste
Meine Meinung über nfs (Network Failure System), portmap und
Co duerfte ja hinreichend bekannt sein. Block them.
Andere RPC-Dienste bind()en sich beim Start auf einen festen Port, sagen
wir mal 1024++ (oder, wenn man sie später stoppt und neu starten, auch
auf einen ganz anderen). Und da nehmen sie fleissig Verbindungen an.
Dabei helfen keine TCP-Wrapper, es gibt keine hilfreichen Syslogeintraege.
Normalerweise funktioniert RPC so, daß man den Portmapper fragt
"hey du, auf welchem Port ist lockd?". Wenn Portmapper geblockt ist
kommt halt keine Antwort, aber das macht nichts, mit strobe oder nmap
findet man den Port ja trotzdem - man weiß zwar nicht _was_ das
ist, aber offen ist er dennoch - was mir nicht schmeckt, da SUNs RPC-Code
eine eher unsichere Angelegenheit ist.
Eine Moeglichkeit waere, diesen Muell nicht zu starten. Dummerweise
gibt es Systeme die RPC-Dienste von sich aus starten wenn andere
Dienste gestartet werden (so startet der Linux-knfsd auch lockd und
rpciod).
Die Andere ist, das Zeug absolut gar nicht zu starten. Also auch nfsd
nicht. Das ist natuerlich manchmal unpraktisch.
Die Letzte und Beste ist, Verbindungen von aussen nur auf bestimmte Ports
zu erlauben - was allerdings der Tod fuer passive-mode-FTP-Zugriff auf
den FTP-Server hinter dem Firewall ist. Im Zweifelsfall ist das die
sinnvollste Alternative.
Designprinzip
Sicherheit, die nachhaltig anhaelt, erreicht man nur wenn man explizit
erlaubt was erlaubt sein soll. Man erreicht sie nicht wenn man nur
verbietet was bekannt gefaehrlich ist.
Gruende dafuer:
- siehe oben unter RPC. Man kann nicht wissen was das System hinter
dem eigenen Ruecken tut.
- Konfigurationsfehler, z.B. ein irrtuemlich geloeschtes # in
der inetd.cnf, haben weniger schlimme bis keine Folgen.
- Ohne grossen Aufwand bleibt niemand up-to-date bei den Problemen
die die diversen eingesetzten Systeme haben.
Praktisches Beispiel
Für die folgenden Anforderungen soll ein Firewall designed werden:
Anforderungen
- kleines 16'er Subnetz. Nutzung:
- hurd aka 194.245.80.1 (GNU Hurd)
- soll gegen aussen abgeschottet werden
- tirka aka 194.245.80.2 (LINUX)
- Ist Firewall, Router, Proxy, Mailserver, etc, muss daher
weitgehend unbeschraenkt bleiben, und bieten folgende Dienste:
- ftp
- ssh
- smtp
- http
- auth (ident, rfc931)
- nntp (für zwei Maschinen)
Die Maschine ist auch der DNS-Server für das lokale Netz,
muß also DNS-Antworten erhalten können. Ausserdem sollte
nslookup/dig von da nach aussen moeglich sein. Der DNS-Server
soll aber von aussen nicht benutzt werden, also brauchen keine
eingehende TCP-DNS-Verbindungen erlaubt werden.
Ausserdem soll diese Maschine auch auf Pings antworten.
- fjoras aka 194.245.80.3 (BeOS)
- darf 'raus. Bietet nach aussen keine Dienste an. darf 'raus
heisst: TCP-Pakete ohne gesetztes SYN-Bit duerfen zu dieser Maschine.
- serak aka 194.245.80.4 (DenialOfService95)
- darf nichts.
- apollo aka 194.245.80.5 (HPUX)
- darf 'raus
- peter aka 194.245.80.6
- darf nichts.
- du3 aka 194.245.80.7
- bietet ein paar Dienste: whois,telnet,ftp. Alles andere ist zu
blockieren
- Spoofing-Filter notwendig.
- Das Gateway ist Proxy und DNS-Cache (und Cache für alles
Andere auch).
- Auf traceroute sollen Antworten erfolgen, _aber_ die Pakete
duerfen nicht durchgereicht werden. Sprich der Router soll eine sauberes
"der ist nicht erreichbar von sich geben"
(diese Anforderung ist mit dem cisco nicht erfüllbar)
- Ausgehende Pakete werden ignoriert.
Idealerweise wuerde man noch verhindern dass irgendwelcher Muell nach
aussen geht, aber ich hab' keine Notwendigkeit dafuer.
Die ACL:
$i ist der Name der ACL.
# ACL erst mal löschen
if grep -w $i /proc/net/ip_fwnames >/dev/null ; then
ipchains -L -vn |head
ipchains -F $i
ipchains -X $i
fi
neue ACL anlegen.
ipchains -N $i
# IP-Spoofing? Aber nicht doch!
ipchains -A $i -s 194.245.80.2/28 -l -j DENY
# remote redirects? Hm?
# das ist zwar etwas, mit dem der Kernel fertigwerden _sollte_,
# aber gleichzeitig sind remote redirects _so_ gefaehrlich
# daß sich der Mehraufwand rechtfertigen läßt.
ipchains -A $i -p icmp -s 0/0 redirect -l -j DENY
# und icmp-Typen über 12 sind nicht allzu wichtig.
ipchains -A $i -p icmp -s 0/0 12: -l -j DENY
# traceroute bis zum Gateway erlauben
# "erlauben" ist relativ ... hier heißt es "unreachable zuruecksenden".
# Über das "-l" läßt sich streiten.
ipchains -A $i -p udp -s 0/0 \
-d 194.245.80.0/28 30000: -l -j REJECT
# soweit die globalen Sachen. Jetzt die einzelnen Kisten:
# hurd. Nach außen unsichtbar.
ipchains -A $i -d 194.245.80.1 -l -j DENY
# tirka. der Router. Loggt, aber akzeptiert pings. Akzeptiert alle anderen
# icmps.
#
# echo-request
ipchains -A $i -p icmp -s 0/0 8 \
-d 194.245.80.2 -l -j ACCEPT
# andere ICMPs
ipchains -A $i -p icmp -s 0/0 \
-d 194.245.80.2 -j ACCEPT
# nfs, X sperren
ipchains -A $i -p tcp -y \
-d 194.245.80.2 2049 -l -j DENY
ipchains -A $i -p tcp -y \
-d 194.245.80.2 6000:6010 -l -j DENY
# ftp-data (actice mode FTP, bei dem der Client auf dieser Maschine sitzt)
ipchains -A $i -p tcp -y -s 0/0 20 \
-d 194.245.80.2 1024: -j ACCEPT
# zugriffe auf lokalen FTP-Server
ipchains -A $i -p tcp -y \
-d 194.245.80.2 21 -j ACCEPT
# ssh
ipchains -A $i -p tcp -y \
-d 194.245.80.2 22 -j ACCEPT
# smtp
ipchains -A $i -p tcp -y \
-d 194.245.80.2 25 -j ACCEPT
# http
ipchains -A $i -p tcp -y \
-d 194.245.80.2 80 -j ACCEPT
# auth
ipchains -A $i -p tcp -y \
-d 194.245.80.2 113 -j ACCEPT
# nntp fuer zwei Maschinen
ipchains -A $i -p tcp -y -s 194.245.99.18 \
-d 194.245.80.2 119 -j ACCEPT
ipchains -A $i -p tcp -y -s 194.245.103.2 \
-d 194.245.80.2 119 -j ACCEPT
# alle anderen SYN-Pakete wegwerfen
ipchains -A $i -p tcp -y \
-d 194.245.80.2 -l -j DENY
# alle TCP-Pakete ohne SYN sind OK.
ipchains -A $i -p tcp ! -y \
-d 194.245.80.2 -j ACCEPT
# DNS-Austausch zwischen den Servern
# das kann man auch einschraenken wenn der DNS-Server nur forwarder benutzt,
# was meiner aber, wenn mich der Spieltrieb befaellt, nicht tut.
ipchains -A $i -p udp -s 0/0 53 \
-d 194.245.80.2 53 -j ACCEPT
# DNS-Lookups von dieser Kiste aus erlauben (bzw. die Antworten darauf)
ipchains -A $i -p udp -s 0/0 53 \
-d 194.245.80.2 1024: -j ACCEPT
# für jemanden talk/ntalk freigeben.
# nicht für jedermann, dazu ist talk viel zu nervig.
ipchains -A $i -p udp -s 193.141.108.34 \
-d 194.245.80.2 517:518 -j ACCEPT
ipchains -A $i -p udp -s 193.141.108.34 517:518 \
-d 194.245.80.2 -j ACCEPT
# Rest entsorgen
ipchains -A $i \
-d 194.245.80.2 -l -j DENY
#
# fjoras, BeOS. Outgoing OK, incoming nicht. Kein UDP.
# braucht keine ping-Echos.
ipchains -A $i -p tcp ! -y \
-d 194.245.80.3 -j ACCEPT
ipchains -A $i -p tcp \
-d 194.245.80.3 -l -j DENY
# unreachables
ipchains -A $i -p icmp -s 0/0 3 \
-d 194.245.80.3 -j ACCEPT
ipchains -A $i \
-d 194.245.80.3 -l -j DENY
# serak, DOSe. Nach aussen unsichtbar
ipchains -A $i \
-d 194.245.80.4 -l -j DENY
# apollo, HPUX. Outgoing OK, incoming nicht.
# der tcp/ip-Stack hat eine extrem aggressive path mtu discovery, scheint
# mir. Deshalb auch source-quench durchlassen.
# Anderseits ist die Kiste so steinalt daß sie garantiert Löcher hat.
# "comp.sys.hpux: how many root holes do you want to see today"?
ipchains -A $i -p tcp ! -y \
-d 194.245.80.5 -j ACCEPT
# unreachables
ipchains -A $i -p icmp -s 0/0 3 \
-d 194.245.80.5 -j ACCEPT
# source-quech
ipchains -A $i -p icmp -s 0/0 4 \
-d 194.245.80.5 -j ACCEPT
ipchains -A $i \
-d 194.245.80.5 -l -j DENY
# peter. DOS. Nach aussen unsichtbar.
ipchains -A $i \
-d 194.245.80.6 -l -j DENY
# DU3 bietet ftp,telnet,whois
# wenn auf der Kiste sonst nichts liefe hätte man es sehr einfach,
# man koennte einfach den Zugriff auf alle Ports >1023 freigeben und
# hätte dann überhaupt keine Probleme mehr. Da die Praemisse
# "hier laeuft nur das und das" auf meinen Spielzeugrechnern nicht
# besonders lange stimmt bin ich hier paranoider:
ipchains -A $i -p tcp -y \
-d 194.245.80.7 21 -j ACCEPT
ipchains -A $i -p tcp -y \
-d 194.245.80.7 23 -j ACCEPT
ipchains -A $i -p tcp -y \
-d 194.245.80.7 43 -j ACCEPT
ipchains -A $i -p tcp ! -y \
-d 194.245.80.7 -j ACCEPT
# unreachables
ipchains -A $i -p icmp -s 0/0 3 \
-d 194.245.80.7 -j ACCEPT
# source-quench
ipchains -A $i -p icmp -s 0/0 4 \
-d 194.245.80.7 -j ACCEPT
# time exceeded (von der Kiste aus sind traceroutes manchmal sinnvoll)
ipchains -A $i -p icmp -s 0/0 11 \
-d 194.245.80.7 -j ACCEPT
ipchains -A $i \
-d 194.245.80.7 -l -j REJECT
# und die letzte Regel: _bye_.
ipchains -A $i -l -j DENY
Vielleicht noch ein Hinweis: ich hab' noch ein paar Regeln mehr drin,
einige FTP-Server duerfen DATA-Verbindungen zur tirka oeffnen (das sind
zwei Server die passive mode nicht zulassen).
Einbindung ins System
Sinnvollerweise integriert man das Einhaengen der ACL in das System wohl
am besten im ip-up Script. Hier kann man auch entscheiden
ah, das ist der Ascend von CSL, der bekommt ACL cslin - also
passend nach Gegenstelle die richtige ACL verwenden.
In die Bootscripte koennte etwa das kommen:
ipchains -P input DENY
ipchains -P forward ACCEPT
ipchains -P output ACCEPT
ipchains -N cslin
...oben genannter code... mit $i == cslin
ipchains -A input -i eth0 -j ACCEPT
ipchains -I input -i lo -j ACCEPT
ip-up koennte dann etwa dies tun:
ipchains -A input -i $1 -j cslin
und ip-down:
ipchains -D input -i $1 -j cslin
Fazit
- Sicherheit ist nicht trivial. Sie ist sogar noch komplizierter als
die obigen Regeln andeuten: Auch die Dienste, die man anbietet, und
die Programme, die man benutzt um auf andere Server zuzugreifen,
sind sicherheitsrelevant, und haeufig genug sind gerade die Clients
die uebelsten Sicherheitsloecher. Und dann ist da noch sendmail!
sendmail? Nein Danke!.
- Der Paketfiltercode der Ciscorouter ist nicht mehr, aber auch nicht
weniger als das (das firewall feature set kann aber deutlich
mehr, wird aber in diesem Artikel nicht betrachtet).
- Linux kann hier mitterweile mehr.
- Linux kann keine reflective access list.
- FTP ist immer irgendwie problematisch. Punkt.
Please send comments on these web pages and questions to
uwe@ohse.de.
Copyright (C) 1998 Uwe Ohse.
Verbatim copying and distribution is permitted
in any medium, provided this notice is preserved.