Przede wszystkim skoncentruję się na obsłudze sieci w sensie obsługi połączeń protokołu TCP/IP, ponieważ głównie on jest wykorzystywany w dużych sieciach - m.in. w samym Internecie. Powiem też o protokole UDP, który w tej chwili jest już wykorzystywany coraz rzadziej. Nie będę opowiadał szczegółowo o samych protokołach, przypomnę jedynie najważniejsze rzeczy.
Po pierwsze: w jaki sposób komputery są rozpoznawane w sieci? Czym jeden różni się od drugiego? Aby rozróżnić poszczególne hosty protokół IP korzysta z tzw. numerów IP - czterobajtowych numerycznych identyfikatorów. Kiedy informacje są wysyłane z jednego komputera, dołączany do nich jest numer komputera dla którego informacje są przeznaczone.
Tu już pojawia się pierwsze zagrożenie - dane na ogół nie są przesyłane do konkretnego komputera, najczęściej idą one do wszystkich komputerów w danym segmencie sieci, a te dla których pakiet z danymi nie jest przeznaczony po prostu go ignoują. Ale nic nie stoi na przeszkodzie, żeby któryś komputer wyłapywał dane które nie były przesyłane wprost do niego. Czyli w praktyce oznacza to możliwość "podsłuchiwania" transmisji - dlatego niebezpieczne są wszystkie rodzaje połączeń, które przesyłają ważne dane (np. hasło) otwartym tekstem (tzn. nie zaszyfrowane). Jak sobie radzić ze sniffingiem (bo tak nazywa się taka metoda przechwytywania danch) opowiem potem.
Transmisja między dwoma komputerami nie odbywa się w sieci w sposób ciągły. Dane są dzielone na mniejsze fragmenty (pakiety), i dopiero tak wysyłane. Pozwala to uniknąć konieczności wysyłania całości jeszcze raz od początku, jeśli okaże się że np. po drodze jeden bajt był przekłamany. W internecie spotykamy praktycznie dwa rodzaje pakietów: pakiety TCP (Transmission Control Protocol) i pakiety UDP (User Datagram Protocol). Zasadnicza różnica pomiędzy nimi polega na tym, że protokół TCP ma możliwość sprawdzania poprawności transmisji: jeśli jakikolwiek pakiet po drodze zostanie przekłamany lub zniknie, to automatycznie jest wysyłany jeszcze raz. Protokół UDP daje jedynie możliwość wysyłania pakietów, natomiast nie gwarantuje, że wszystkie dane dotarły niezmienione na miejsce (kontrolę poprawności trzeba wtedy wykonywać oddzielnie).
Wszystkie rodzaje protokołów, którymi mogą się posługiwać komputery połączone w sieć TCP/IP można znaleźć w pliku /etc/protocols wraz z ich identyfikatorami (np. protokół TCP ma numer 6, a UDP 22). Bez tych numerów system nie jest w stanie rozpoznać rodzaju przychodzących pakietów.
Każdy z komputerów w sieci może serwować określone usługi: np. FTP, WWW, IRC itp. Żeby odróżnić jakoś dane przesyłane do różnych rodzajów programów-serwerów każdy pakiet oprócz adresu docelowego ma też określony rodzaj usługi której dotyczy jego zawartość. Usługi są, podobnie jak protokoły, określane za pomocą przypisanych im liczb (z zakresu 1-65535) - określanych mianem portów. I tak np. FTP ma przypisany standardowo numer portu 21, WWW(HTTP) - 80, itd. Te numery można znaleźć w pliku /etc/services. Nazwy usług, z których zamierzamy w systemie korzystać powinny być tam wpisane razem z odpowiednimi numerami.
Jeśli na naszym komputerze ma być dostępna dana usługa, potrzebny jest odpowiedni serwer (daemon), który będzie nasłuchiwał, czy przypadkiem ktoś nie próbuje się połączyć z naszą maszyną na danym porcie (tzn. jeden port może być przypisany tylko do jednego programu, ale jeden program może nasłuchiwać naraz na kilku portach).
Porty o numerach od 1 do 1023 są zastrzeżone - w tym sensie, że jedynie root ma prawo uruchamiać programy, które na tych portach będą nasłuchiwać. Zwykli użytkownicy mogą wykorzystywać do tego celu porty od 1024 w górę.
Najprostszą sytuacją jest taka, kiedy program który ma za zadanie obsłużyć przychodzące wywołania na danym porcie siedzi cały czas w pamięci i czeka aż będzie potrzebny - tak najczęściej działa na przykład demon httpd - serwer WWW. Jednak często wywołania jakiegoś programu są na tyle rzadkie, że większą efektywność osiągniemy jeśli ten serwer będzie uruchamiany tylko wtedy, kiedy będzie potrzebny. Czasem też pewien program musi być wywołany dla każdego połączenia z osobna (np. telnet). Dlatego jest coś, co zajmuje się właśnie tylko i wyłącznie nasłuchiwaniem na określonych portach, i w razie potrzeby uruchamia potrzebne demony. To coś to właśnie demon inetd. Są różne wersje tego demona (np. rlinetd), ale ponieważ to jest tekst dla początkujących administratorów, więc skupię się przede wszystkim na standardowej wersji inetd dostępnej chyba we wszystkich dystrybucjach.
Demon inetd siedzi sobie cały czas w pamięci, i nasłuchuje na podanych przez nas portach. Kiedy wykryje próbę połączenia z jednym z nich, sprawdza w pliku konfiguracyjnym jaką akcję ma wykonać dla takiego rodzaju połączenia (istotne rzeczy to protokół (TCP/UDP), oraz numer portu). Plik konfiguracyjny to /etc/inetd.conf, a wpisy w nim wyglądają podobnie do tego:
telnet stream tcp nowait root telnetd
Co po kolei za co odpowiada:
nntp stream tcp nowait news in.nntpd
Uruchamiany program to nntpd (wywoływany przez link o nazwie in.nntpd), uruchamiany z prawami użytkownika "news".
Wrapper to program, którego zadaniem jest uruchamianie innych programów. Po co w takim razie w ogóle takie coś jest potrzebne, przecież wystarczy uruchomić sam program? Teoretycznie tak. Ale użycie wrappera pozwala na wprowadzenie dodatkowych możliwości: np. taki programik zanim wywoła inną aplikację może sprawdzić jakiś warunek, i w zależności od tego czy jest spełniony może kontynuować pracę lub przerwać bez uruchamiania naszej aplikacji.
Typowym przykładem wrappera jest tcpd, program który służy do odpalania aplikacji sieciowych. Przed uruchomieniem zadanej aplikacji tcpd sprawdza w swoich plikach konfiguracyjnych, czy powinien zezwolić na zestawienie tego konkretnego połączenia. Dzięki temu możemy np. zezwolić na łączenie się tylko z konkretnego adresu, lub wręcz przeciwnie, nie zezwolić na łączenie się z jakiejś domeny. O tym co ma być dokładnie zrobione decydują pliki /etc/hosts.allow oraz /etc/hosts.deny (czasem zamiast /etc jest /etc/tcpd, jak na przykład w PLD). Wpis do takiego pliku hosts.deny może mieć postać:
in.telnetd : ALL EXCEPT LOCAL zaprzyjazniona.domena.com.pl
Co znaczy taki wpis? Na jedną pozycję w konfiguracji składają się dwa lub więcej człony rozdzielone dwukropkami. Pierwszy z nich to nazwa programu, którego dotyczy wpis - w tym wypadku demona in.telnetd. Druga pozycja to informacja o tym, jakie adresy mają się "załapać" do naszej regułki - w tym wypadku są to wszystkie adresy oprócz adresów lokalnej sieci, oraz zaprzyjaznionej domeny.
Na jakiej zasadzie tcpd określa komu pozwolić wejść a komu nie? Po co są dwa różne pliki? Odpowiedź jest prosta: dla wygody. Tcpd działa tak: jeśli połączenie podpada pod jakąś regułkę w hosts.allow, to połączenie dochodzi do skutku (aczkolwiek czasem może to być połączenie obsługiwane przez inny program niż było planowane: o tym za chwilę). Potem próbuje dopasować domenę do regułek w hosts.deny - jeśli tam dopasuje, to połączenie jest odrzucane. Jeśli domeny nie ma opisanej w żadnym z tych plików - tcpd przyjmuje połączenie. Dwa pliki są dla wygody administratora: można np. do pliku hosts.deny wpisać:
ALL:ALL
co zablokuje wszystkie programy (uruchamiane przez tcpd) dla wszystkich, a w hosts.allow odblokować konkretne usługi dla konkretnych domen.
Dobrym pomysłem jest wpisać na "dzień dobry" właśnie "ALL:ALL" do hosts.deny, a w hosts.allow odblokować sobie odpowiednie usługi dla domen localhost, moja.domena, ew. LOCAL. Pozwala to ograniczyć "otwartość" naszego serwera do naszego własnego komputera - nikt spoza niego nie będzie mógł uruchomić żadnego programu przez tcpd. Niestety w większości dystrybucji standardowy plik inetd.conf jest baardzo "dziurawy" - jest w nim aktywnych dużo usług, które są potencjalnymi lukami w bezpieczeństwie, takich jak rlogin, rexec...
Najczęściej wykorzystuje się wrappery przy wywołaniach z inetd-a: linijka z inetd.conf wzbogacona o użycie tcpd wyglądać może tak:
telnet stream tcp nowait root tcpd in.telnetd
Aha, zapomniałem o ważnej rzeczy. Jak sprawdzić, jakie porty są czynne na jakimś komputerze? Do sprawdzenia na naszym własnym serwerze służy polecenie netstat: np. z opcją "-a" pokaże nam wszystkie otwarte porty na naszym komputerze. Netstat ma bardzo dużo pożytecznych opcji, dlatego warto zajrzeć do manuala netstat(8).
Natomiast aktywne porty na innych komputerach można sprawdzić używając tzw. skanera portów: np. nmap-a. Ale uwaga - próby skanowania obcych serwerów często są uznawane przez administratorów tamtych maszyn za wstęp do większych kłopotów: dlatego nie należy się dziwić, jeżeli po takim skanowaniu dostaniemy maila z tematem "Heavy port-scanner attack from ...", a czasem taki mail trafia też do roota domeny, w której mamy IP, albo do abuse@tpnet.pl (jeśli korzystamy z 0202122)... z tego na ogół wynikają same kłopoty.
Wracając do wrappera: co jeszcze można z nim zrobić? Jak już napisałem, można nakazać mu uruchomić w poszczególnych przypadkach inny program niż standardowo. Załóżmy, że np. chcemy pozwolić na połączenie, ale najpierw wyświetlić jakiś napis (np. mówiący o tym, że ta usługa będzie od jutra niedostępna). Jak to zapisać? W pliku hosts.allow:
in.telnetd : ALL : twist echo "Ta usługa od jutra będzie niedostępna" ; sleep 2 ; in.telnetd
(piszę z pamięci, więc niewykluczone że trzeba to zapisać w trochę inny sposób, ale zasada jest taka sama). Polecenie "twist" dodane na końcu, razem z innym poleceniem powoduje zastąpienie wywoływanego programu (w tym wypadku in.telnetd), przez inny program (w tym wypadku przez połączenie kilku poleceń: echo, sleep, in.telnetd). Taki program wywołany w zastępstwie ma swoje standardowe wejście i wyjście podczepione do nawiązanego połączenia: czyli uruchomione polecenie "echo" wypisze coś na ekranie osoby, która się telnetuje na nasz komputer, a to co ta osoba wpisze pójdzie do nas.
Do jednej regułki może być dopisane tylko jedno wywołanie programu przez "twist", i musi to być ostatnie wywołanie w linii.
Inna rzecz to uruchamianie dodatkowych programów, bez podpinania ich wejścia/wyjścia do połączenia. Po co chcieć coś takiego robić? Np. załóżmy, że jeśli ktoś się telnetuje do nas z domeny aaaa, to chcemy dostać maila z informacją o tym. W pliku hosts.allow dopisujemy:
in.telnetd : zla.domena.com : spawn echo "Telnet ze zlej domeny!" | mail root
i już. Połączenie zostanie przyjęte (bo jest wpisane w pliku hosts.allow), ale root dostaje powiadomienie o tym mailem.
A, mówiłem wcześniej o tym, że jest jeszcze jeden powód, dla którego warto kopiować uruchamiane programy (lub linkować) jako in.cośtam. No i tu jest ten powód: jeśli chcemy na dwóch różnych portach udostępnić telneta, i na obu założyć różne regułki w hosts.allow lub hosts.deny, to wystarczy podlinkować telnetd jako in.telnetd1 i in.telnetd2, i potem w plikach użyć odpowiednio jednego na jednym porcie, a drugiego na drugim.
Ostatnia rzecz dotycząca tpcd to możliwość używania w tych wywołaniach sekwencji specjalnych ze znaczkiem % - tcpd automatycznie potrafi rozwinąć je do odpowiednio: adresu z którego jest dokonywane połączenie, nazwy tamtej domeny, nazwy użytkownika który stamtąd się łączy (o ile ma taką informację) itp. Więcej można poczytać na stronach manuala hosts_options(5) i hosts_access(5).
Na koniec przykład z życia wzięty: często jacyś dowcipnisie próbują atakować mój komputer za pomocą tzw. netbusa: jest to koń trojański, dość popularny w Windows. Jeśli na moim komputerze (gdyby pracował pod Windowsem :P ) miałbym uruchomionego (bez mojej wiedzy) takiego netbusa, to każdy kto odpowiednim programem połączy się z moim komputerem na porcie 12345 i 12346 może go w pełni kontrolować: ściągać pliki, robić zrzuty ekranu, zmieniać pozycję myszki, wysuwać i chować szufladę CD-ROMu itp. Wprawdzie kiedy mam Linuxa to takie coś nie jest dla mnie groźne, ale nie lubię jak ktoś ma takie głupie zabawy...
Ja poradziłem sobie tak: po pierwsze do pliku /etc/services dopisałem linijki:
netbus 12345/tcp
netbus-data 12346/tcp
potem do pliku inetd.conf dopisałem:
netbus stream tcp nowait root /usr/sbin/tcpd in.netbusd
netbus-data stream tcp nowait root /usr/sbin/tcpd in.netbusd
w katalogu /usr/sbin utworzyłem dowiązanie symboliczne o nazwie in.netbusd do pliku /bin/true (tak, żeby jego uruchomienie momentalnie się kończyło bez specjalnych efektów). Na koniec dopisałem regułkę w pliku /etc/tcpd/hosts.deny:
in.netbusd: ALL : spawn /usr/bin/winnuke %a
%a jest wyrażeniem rozwijanym do adresu komputera z którego ktoś się łączy. W ten sposób każde połączenie na porty 12345 lub 12346 automatycznie wywołuje w odpowiedzi ataki WinNukiem na host, z którego było wykonywane połączenie.
Program WinNuke oraz inne programy do "sprawdzania odporności Windows na ataki" ;) można znaleźć w dystrybucji PLD, a w szczególności też tutaj (jako źródła) lub tutaj (jako pakiet .src.rpm od PLD)
Tutaj omówię pokrótce najczęściej spotykane usługi, problemy z ich stosowaniem związane z bezpieczeństwem, oraz metody rozwiązywania tych problemów.
Jedna z najczęściej spotykanych usług, powszechnie używana, niestety... Główna wada telneta: wszystkie dane są przesyłane gołym tekstem. W efekcie jeśli ktokolwiek podsłucha naszą transmisję, dostanie nie tylko nasz login i hasło, ale też zapis całej naszej sesji na zdalnym koncie - wszystko to, co wpisywaliśmy na klawiaturze i wszystko to, co serwer nam pokazywał.
Tutaj rozwiązanie problemu jest jedno - nie używać telneta, zamiast tego wszędzie gdzie się da używać ssh (Secure SHell) - to jest taki telnet z dodatkowym szyfrowaniem i kompresją transmisji, powiem o tym parę słów za chwilę...
Problem jak wyżej: transmisja jest niekodowana. Dodatkowo jeszcze dochodzi problem z plikami .rhosts i /etc/hosts.equiv: w tych plikach można umieszczać nazwy komputerów, z których osoby logujące się bez hasła! Jeśli jakiś komputer podszyje się pod adres IP maszyny, którą my mamy wpisaną gdzieś w tych plikach, to nie będzie od niego wymagana żadna autoryzacja! To jest oczywiście poważna dziura. Wyjście jak w wypadku telneta: nie używać. Warto w ogóle zablokować tę usługę (w inetd.conf), w większości standardowych konfiguracji jest ona jednak aktywna (początkujący administrator może w ogóle nawet sobie z tego nie zdawać sprawy)
Tutaj problem polegający na przesyłaniu danych gołym tekstem znika. Jedyna rzecz na którą warto zwrócić uwagę to wyłączyć w demonie SSH możliwość logowania się bez hasła bazując na podstawie plików /etc/hosts.equiv, .rhosts i .shosts, które działają tak jak w RSH. Wprawdzie w dalszym ciągu jest możliwość zalogowania się bez hasła - ale do tego jest wymagane wtedy posiadanie prywatnego klucza autoryzującego dla danego konta, a to jest równie niebezpieczne jak metoda logowania przez hasło - tzn. nie jest łatwo uzyskać taki klucz...
SSH pomaga też rozwiązać problemy z niektórymi innymi usługami, które przekazują dane gołym tekstem, np. FTP, POP3, przez stawianie tzw. tuneli. Cała filozofia polega na tym:
ssh -L 8888:komputer.docelowy.com.pl:110 komputer.do.ssh
Po czymś takim ssh zaloguje nas na "komputer.do.ssh", jednocześnie ustawiając tunel pomiędzy portem 8888 na naszym hoście a portem 110 na komputerze.docelowym.com.pl. Jeśli chcemy mieć tunel do maszyny na którą się logujemu, to robmy to np. tak:
ssh -L 8888:moj.komputer.zdalny:110 moj.komputer.zdalny
Jeśli nie chcemy się logować, a jedynie postawić sam tunel to powinno się podać opcje "-n" i "-f" dla ssh, oraz jakąś komendę do wykonania na drugim komputerze. Dopóki komenda nie zakończy swojego działania, dopóty możemy łączyć się przez tunel. Kiedy polecenie się skończy, można korzystać tylko z już aktywnych połączeń. Typowy przykład:
ssh -f -n -L 8888:moj.komputer:110 moj.komputer sleep 600
co daje nam 10 minut (600 sekund) na otwarcie tunelu.
Taki sam tunel można stawiać w drugą stronę: tzn. z tamtego serwera do nas. Analogicznie:
ssh -f -n -R 8888:moja.lokalna.maszyna:110 moj.komputer sleep 600
pozwoli ustanowić tunel między portem 8888 na zdalnym serwerze a 110 na naszej lokalnej maszynie.
Przy stawianiu tunelów dla FTP warto pamiętać o tym, że dane dla FTP kursują na dwóch portach: 20 i 21, więc trzeba tunelować oba...
Standardowa usługa. Niekodowana - wszystkie pliki oraz username i hasło można łatwo przechwycić. Nie stanowi to dużego problemu przy połączeniach typu anonymous, gdzie nazwa użytkownika jest powszechnie znana. Jednak dla indywidualnych zastosowań (tzn. przy przesyłaniu plików do/ze swojego konta) lepiej użyć np. scp - programu wchodzącego w skład pakietu "ssh" i umożliwiającego zaszyfrowanie całej transmisji. Przykładowe użycie:
scp plik/na/lokalnym/dysku username@serwer:/katalog/na/serwerze
lub
scp user@serwer:~/plik/w/katalogu/na/serwerze .
Tam gdzie nie ma możliwości użycia ssh można czasem wykorzystać tzw. SSL
(Secure Socket Layer) - inny rodzaj transmisji kodowanej. Wymaga to
odpowiedniego wsparcia zarówno po stronie klienta (program do FTP
korzystający z SSL), jak i serwera (serwer FTP z SSLem lub wrapper do
SSLa - czyli coś co pozwala korzystać z kodowanego połączenia nawet programom
które normalnie tego nie potrafią).
Można jeszcze tunelować ftp po ssh, jednak wymaga to trybu passive, oraz
tunelowania połączeń na port 21 (lokalnie) i 20 (zdalnie). Jednak prostszym
wyjściem w takiej sytuacji jest użyć scp.
Niektóre serwery są uważane przez wiele osób za "dziurawe" - warto ich
unikać (np. wu-ftpd), ponieważ błędy w nich są znajdowane dość często.
Serwery FTP na ogół muszą chodzić z prawami roota, więc błąd klasy
"security" w takim programie zwykle pozwala przejąć prawa administratora.
Proftpd wydaje się być w miarę dobrym rozwiązaniem, aczkolwiek w
nim też zdarzały się bugi. W tej chwili w PLD tworzony jest nowy serwer
ftp i on prawdopodobnie będzie jednym z najbezpieczniejszych serwerów.
Również usługa niebezpieczna, po pierwsze ze względu na możliwość
przechwycenia, po drugie ze względu na możliwość uruchamiania programów na
serwerze przy oglądaniu strony (CGI,SSI).
CGI i SSI to opcje serwera http umożliwiające wykorzystanie dodatkowych
programów przy przesyłaniu strony z serwera do przeglądarki. Jest to
potencjalna dziura w bezpieczeństwie, zwłaszcza jeśli serwer pracuje jako
użytkownik root. Możliwych wyjść jest kilka: można wyłączyć
możliwość korzystania z CGI i SSI w konfiguracji serwera. Można ograniczyć
korzystanie z tych opcji tylko do kilku konkretnych programów
wyspecyfikowanych przez administratora (np. licznik odwiedzin). Jeśli
serwer WWW chodzi z prawami użytkownika nobody/httpd/coś_podobnego, to nie
ma problemu i prawdopodobnie używanie CGI i SSI nie stanowi zagrożenia - o
ile nie ma możliwości ustawienia bitu SUID na uruchamianych programach
(dotyczy to też czegoś takiego jak Perl-SUID).
Jeśli serwer chodzi z prawami roota, należy to jak najszybciej! zmienić - na ogół nie jest to potrzebne.
W sytuacji gdy potrzebne jest kodowanie ze względu na ochronę przesyłanych danych można użyć protokołu shttp (secure http) - czyli http realizowanego przy użyciu SSLa. Większość dostępnych w tej chwili przeglądarek (lynx wymaga specjalnej łatki) ma możliwość korzystania z shttp.
W tym przypadku również transmisja jest niekodowana. Możliwe rozwiązania:
Przede wszystkim, jeśli nie potrzebujemy, warto zmienić domyślnego
sendmaila na coś innego - qmaila, exima, postfixa, zmailera... możliwości
jest dużo. W sendmailu do tej pory znaleziono już bardzo dużo błędów, i
prawdopodobnie znajdą się jeszcze inne... Po drugie dobrze by było
wyłączyć open-relaying, czyli
możliwość wysyłania listów z naszego serwera przez dowolnego użytkownika i
do dowolnego użytkownika - w ten sposób ktoś może podrzucać nam swoją
pocztę do wysyłania jednocześnie obciążając nam łącze. Na ogół wystarczy
ustawić możliwość wysyłania tylko z sieci wewnętrznej do wszystkich
adresów i z adresów zewnętrznych tylko do wewnątrz, natomiast wyłączyć
możliwość przekazywania listów z zewnątrz gdzieś do innej sieci.
Po drugie można wyłączyć opcję VRFY (jeśli taka jest) - za jej pomocą
dowolna osoba jest w stanie sprawdzić, czy jest na serwerze konto o
podanej nazwie.
Jak w poprzednim wypadku: można sprawdzić czy dana osoba ma konto na serwerze, co nie jest dobrą rzeczą... Po drugie za pomocą fingera można sprawdzić na ogół kto jest w danej chwili zalogowany - to może tylko ułatwić włamywaczowi wejście na serwer. Najlepiej w ogóle wyłączyć, lub zablokować dostęp z zewnątrz. Ew. można użyć demona fingera który nie pozwala na oglądanie listy zalogowanych użytkowników.
Na ogół po postawieniu samby dostęp do niej ma każdy - także osoby z sieci
zewnętrznej. Przede wszystkim należy pamiętać o używaniu haseł - nawet w
sieci wewnętrznej, o ile tylko istnieje możliwość połączenia się z
którymkolwiek jej komputerem z zewnątrz. Można też ustawić możliwość
łączenia się jedynie z konkretnego numeru IP/klasy numerów.
Jeśli jest taka możliwość można korzystać z szyfrowanych haseł.
Jeśli z naszego komputera korzysta ktokolwiek inny oprócz nas, warto
ustawić odpowiednie prawa dostępu na katalogi zamontowane przez sambę,
lub w ogóle umożliwić korzystanie z tych katalogów tylko pewnej grupie
użytkowników.