88                             88
88                             88
88                             88
88,dPPYba,  ,adPPYba,  ,adPPYb,88
88P'    "8a I8[    "" a8"    `Y88
88       d8  `"Y8ba,  8b       88
88b,   ,a8" aa    ]8I "8a,   ,d88
8Y"Ybbd8"'  `"YbbdP"'  `"8bbdP"Y8

OpenBSD jako bramka sieciowa

OpenBSD jest wersją systemu BSD, w której nacisk położono na silniejsze zabezpiecznia przez co świetnie sprawdza się jako system dla programowalnych urządzeń sieciowych. Jednak zdarzają się tacy hakerzy, którzy stosują go do codziennej pracy jako system ogólnego zastosowania. W Internetach można znależć wiele skonfigurowanych przez ludzi pulpitów oraz stricte poradników aby ten system mógł chociaż spróbować stać się systemem codziennego użytku, poki co my przy odrobinie chęci możemy zrobić z niego porządną bramę sieciową, z której sam korzystam w kilku sieciach. Warto dodać że ten system ma niewielkie wymagania systemowe patrząc na współczesny sprzęt. Dla architektury 32-bitowej 32 MB pamięci RAM oraz 600 MB wolnej przestrzeni na dysku to naprawdę nie wiele. Dla prawdziwego hakera wystarczył by komputer ze śmietnika, lub terminal z popularnego serwisu aukcyjnego za 20 zł.

UWAGA! Wszystkie przedstawiowne tutaj polecenia są uruchamiane z poziomu użytkownika root.

  1. Instalacja systemu.

    Instalacja systemu OpenBSD została przedstawiona tutaj. Jedyne co w tym wypadku możemy zmienić to ustawić intefejs podłączony do Internetu (w zależności od konfiguracji naszego ISP, warto pamiętać w jaki sposób został przydzielony nam adres IP. Będzie nam to potem potrzebne w regułach zapory dotyczących NAT-u) oraz interfejs sieci LAN, ze stałym adresem IP, będącym pierwszym adresem z puli (tak się przyjęło, chociaż ludzi na kursach CISCO uczono inaczej, że adresem bramy w sieci LAN pownien być ostatni adres z puli). W przypadku interfejsu podłączonego do Internetu ze stałym adresem, o adresy bramy, domenę oraz adresy DNS zostaniemy zapytani dopiero po zdefiniowaniu interfejsów sieci LAN. Co pokazano poniżej.

    #Interfejs WAN (podłączony do internetu)
    IPv4 address for em0 ? (or 'dhcp' or 'none') [dhcp] 157.190.112.10
    Netmask for em0 [255.255.255.0]
    
    #Interfejs LAN
    IPv4 address for em1 ? (or 'dhcp' or 'none') [none] 192.168.0.1
    Netmask for em0 [255.255.255.0]
    
    Default IPv4 route ? (IPv4 address or none) [none] 157.190.112.1
    DNS domain name (e.g. 'example.com') [my.domain] morketsmerke.net
    DNS nameservers? (IP address list or none) 157.190.112.1
    

    Definiując interfejs WAN należy wpisać dane, które umożliwią nam połączenie z Internetem. Musimy mieć połączenie na naszej maszynie, aby zainstalować pakiet dnsmasq, który będzie niezbędny do obsługi DNS. Chyba że zrobimy z telefonu router i podłączymy go kablem USB, w OpenBSD działa to bez zarzutów.

  2. Instalacja dnsmasq.

    Do osiągnięcia naszego celu, musimy zainstalować jeden program ponieważ reszta znajduje się już w systemie. Aby pobrać oprogramowanie z oficjalnego repozytorium wydajmy następujące polecenie:

    # pkg_add -a dnsmasq
    

    Po zainstalowaniu daemona warto ustawić jego uruchamianie podczas startu systemu.

    # rcctl enable dnsmasq
    
  3. Konfiguracja DHCP

    W OpenBSD daemon DHCP jest preinstalowany a jego plik jest umieszczony bezpośrednio w katalogu /etc. Dla małej sieci nie potrzebujemy zbyt wielu opcji. Wystarczą te najbardziej podstawowe. Poniżej przedstawiono najprostszą do prawidłowego funkcjonowania sieci konfigurację DHCP. Otwieramy plik /etc/dhcpd.conf.

    subnet 192.168.0.0 netmask 255.255.255.0 {
    	range 192.168.0.100 192.168.0.200;
    	option routers 192.168.0.1;
    	option domain-name "morketsmerke.net";
    	option domain-name-servers 192.168.0.1;
    }
    

    Jeśli nasza brama obsługuje więcej niż jedną sieć LAN, to powtarzamy deklaracje dla kolejnych podsieci.

  4. Ustawienia interfejsów dla dhcpd

    Do poprawnej pracy naszego serwera DHCP pozostaje jeszcze wskazać odpowiedenie interfejsy dla wpisanych w pliku konfiguracyjnym podsieci. Interfejsy wpisuje się w opcjach uruchomieniowych daemona w pliku /etc/rc.conf.local, te opcje odczytywane są podczas uruchamiania usług zaraz przed umożliwieniem użytkownikowi zalogowania do systemu. Wpis dla dhcpd ma następujący wzór:

    dhcpd_flags="interfejs1 interfejs2 ... interfejsN"
    

    Warto dodać że przekaznie opcji uruchomieniowych (flag) do daemona jest równoznaczne z jego uruchomienie podczas startu, więc nie trzeba wydawać polecenia rcctl enable dhcpd.

  5. Ustawienie interfejsu dla dnsmasq

    Jeśli ktoś ustawiał już dnsmasq na GNU/Linux to robi się to tutaj w ten sam sposób. W pliku konfiguracyjnym /etc/dnsmasq.conf, odnajdujemy opcję #interface=, usuwamy znajdujący się na początku znak komentarza i po znaku równości (=) podajemy nasz interfejs sieciowy, tak samo jak w przypadku wielu sieci LAN, kopiujemy opcje wraz z ustawionym kolejnym interfejsem.

    Teraz możemy użyć polecenia netstat -ln | grep -e '^tcp' -e '^udp' aby wyświetlić wszystkie otwarte porty TCP i UDP. Z wyników tego polecenia dowiemy się że dnsmasq nasłuchuje na wszystkich interfejsach a nie tylko na wskazanym, zostało to utworzone dla wygody w przypadku zmiany interfejsów lub ich adresów (w zależności od konfiguracji) nie trzeba zmieniać ustawień w pliku, a daemon nie odpowie na żądania, na które nie powinien. Jeśli jednak chcemy wymusić wyłączenie wyżej wspomnianej właściwości i respektowanie opcji interface to należy odblokować opecję bind-interfaces.

  6. Ewnetualne wpisy w /etc/hosts*

    Za pomocą pliku /etc/hosts, możemy umieszczać nazwy domenowe na bramie dzięki temu uzyskamy odzworowanie nazw w naszej sieci lokalnej bez konfigurowania skomplikowanych systemów DNS takich jak BIND9. Oczywiście nie było by to możliwe bez dnsmasq. Wzór wpisu do plku /etc/hosts znajduje się poniżej.

    <IP>	<FQDN>	<HOSTNAME>
    

    Dla przykładu wstawię tutaj jeden ze wpisów.

    192.168.0.2	serwer.morketsmerke.net	serwer
    
  7. Firewall oraz NAT

    Do prawidłowego funkcjonowania naszej bramy potrzebny jest system NAT (Network Address Translation). Funkcje NAT-u w UNIX-ach przeważnie są realizowane przez oprogramowanie Firewall-a. Zapory sieciowe (firewall-e) są konfigurowane za pomocą reguł, a do działania NAT-u, czy to w przypadku systemów *BSD, gdzie zapora realizowana jest za pomocą pakietu PF (Packet Filter) czy za pomocą pakietu iptables używanego na systemach GNU/Linux wystarczy jedna reguła.

    pass out on <interfejs podłączony do Internetu> from <interfejs LAN z sufiksem :network> to any nat-to
    (<publiczny adres IP / intefejs podłaczony do Internetu>)
    

    Taka konfiguracja jest wystarczająca, jednak warto pamiętać o tym że prawdopodobnie mamy włączone SSH, które nasłuchuje na wszystkich portach, więc aby nie dać możliwości ataków odgadywania hasła przez boty, warto albo ustawić adres, na którym ma nasłuchiwać w konfiguracji SSH lub użyć polityki zarządzania ruchem sieciowym polegającej na odcięciu całego ruchu sieciowego od firewalla a następnie dopuszczenia tylko tego najważniejszego dla zastosowań biurowo-domowych wystarczy odciąć cały ruch i jawnie go zadeklarować za pomocą odpowienich reguł. Tutaj warto opisać jak działa PF. PF jak każdy inny daemon czyta swoją konfiguracje z pliku /etc/pf.conf, to właśnie w nim są przechowane reguły. Dostosowuje je do swojego wewnętrznego formatu, aby optymalnie przypasowywać pakiety do istniejących reguł na tej zasadzie właśnie działają zapory sieciowe, a cechą charkterystyczną PF jest zasada "ostatni wygrywa", czyli jeśli pakiet pasuje do wielu reguł to akcja (pass lub block) ostatniej pasującej do pakietu reguły zostanie na nim zastosowana. Wracając do naszego pliku, otwieramy go do edycji, najlepiej usunąć to co tam jest poza jakimiś początkowymi komentarzami jeśli istnieją oczywiście. Na samym początku zdefiniujemy sobie kilka zmiennych, tak w regułach PF można definiować zmienne.

    red="Interfejs podłączony do internetu";
    green="Interfejs sieci LAN";
    greennet="Interfejs sieci LAN:network";
    

    Skąd te nazwy zmiennych, otóż kiedyś korzystała z nich dystrybucja IPCop - GNU/Linuxowa dystrybucja przeznaczona właśnie na bramki. Kolory oznaczały interfejsy przypisane do konkretnych rodzajów sieci:

    • czerwony - sieć Internet/sieć rozległa WAN - brak zaufania dla danych pochodzących z tej sieci
    • zielony - sieć LAN - sieć niefiltrowana przez ten firewall (komputery z tej sieci miały dostęp do wyszystkich pozostałych sieci), sieć największego zaufania.
    • niebieski - sieć mniejszego zaufania niż w sieci LAN, sieć niebieska nie mogła się komunikować z siecią zieloną, stosowana dla wydzielenia odrębnej sieci LAN dla sieci bezprzewodowej
    • pomarańczowy - sieć ograniczonego zaufania - DMZ, komputery z tej sieci nie mogły łączyć się z żadną z powyższych sieci poza czerwoną, ale sieci niebieska oraz zielona bez przeszkód mogły łączyć się hostami sieci pomarańczowej.

    Jest to dla mnie dość zrozumiała wizja konfiguracji sieci, dlatego też korzystam z niej po dziś dzień. W skrócie red oznacza Internet, green sieć LAN, greennet służy głównie wygodniejszemu zapisowi interfejsu LAN z przyrostkiem (sufiksem) :network (em1:network). Pod naszymi zmiennymi zapisujemy pierwszą regułę.

    block all
    

    To prosta a zarazem bardzo skuteczna reguła, powoduje blokadę wszystkich pakietów, odcina bramkę od jakiejkolwiek sieci nawet LAN. I teraz możemy zatrzymać się na chwilę i pomyśleć, czyli co? Teraz będę musiał dla każdego połączenia definiować oddzielną regułę oraz regułę zezwalającą na otrzymanie odpowiedzi od odległego serwera? Otóż nie, tu jest właśnie duża różnica pomiędzy PF a iptables. Przy użyciu tych samych polityk w PF nie trzeba dopuszczać oddzielną regułą odpowiedzi z serwera, wystarczy reguła, która pozwoli hostom z sieci LAN na rozpoczęcie polączenia. W PF jest realizowane automatycznie po przypasowaniu pakietu rozpoczynającego połączenie. Tworzony jest tak jakby tunel, który pozwoli na swobodny przepływ odpowiedzi na przypasowane pakiety wychodzące. Poniżej znajdują się reguły, które spowodują już dopuszczenie ruchu do i z bramki.

    pass in on $green from $greennet to any
    

    Ta reguła powoduje dopuszczenie ruchu wejściowego na intefejsie sieci LAN do dowolnego hosta, między innymi również do bramki.

    pass out on $red from $red to any
    

    Z racji tego że wszystko było odcięte przez block all daliśmy możliwość komunikacja bramki z siecią LAN, chcąc niechcąc adres interfejsu sieci LAN również znajduje się wewnątrz tej sieci. Aby bramka mogła połączyć się z Internetem musimy wypuścić ruch wychodzący z interfejsu WAN do dowolnego hosta. Teraz pozostało nam dopisać ostatnią odpowiedzialną za NAT regułę.

    pass out on $red from $greennet to any nat-to ($red)
    

    Ta reguła mówi nam aby wypuścić ruch na interfejsie red z sieci lokalnej (greennet) gdziekolwiek z ustawieniem NAT-u do adresu interfejsu podłączonego do Internetu. Ujęcie w nawias zmiennej red, mówi PF, aby stale monitorował interfejs pod kątem zmian adresu, aby nie trzeba było wczytywać ponownie reguł PF, przy każdej jego zmianie .

    Do wczytania reguł PF służy polecenie pfctl, które wydajemy z opcją -f, po którym wskazujemy plik z regułami. Jednak przed wczytaniem reguł warto wydać polecenie pfctl wraz z przełącznikami -nf spowoduje to sprawdzenie pliku reguł pod kątem błędów bez wczytywania go. Warto o tym pamiętać kiedy dokonujemy zmian w pliku reguł, a jeden błąd uziemia PF i firewall w ogóle się nie uruchamia i nagle w firmie zaczyna brakować dostepu do Internetu...

  8. Przekazywanie pakietów

    Na UNIX-ach aby była możliwość przesłania pakietów z jednego łącza (interfejsu) na drugie należy umożliwić to z poziomu jądra systemu po przez zmianę jednej z jego opcji. Przekazywanie pakietów jest uruchamiane za pomocą polecenia sysctl, wraz z opcją net.inet.ip.forwarding ustawioną na 1.

    # sysctl net.inet.ip.forwarding=1
    

    Opcje zmieniane za pomocą polecenia sysctl w trakcie działania systemu działają tak długo jak system jest uruchomiony, oznacza to że po ponownym uruchomieniu opcja powróci do swojej pierwotnej wartości. Więc teraz musimy coś zrobić aby nie trzeba było logować sie do bramki i uruchamiać z "ręki" przekazywania pakietów. Rozwiązanie tego problemu jest bardzo proste, wystarczy dopisać opcje net.inet.ip_forwarding z wartością 1 do pliku /etc/sysctl.conf.

    # echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf
    

Jak pokazano wyżej za pomocą kilku prostych poleceń, wyedytowaniu kilku plików można przerobić ten jakże obcy dla wielu system, na naprawdę coś użytecznego. Warto dodać że ja najpierw nauczyłem się tworzyć bramki na OpenBSD, a dopiero później na GNU/Linux. Jeśli posiadamy naprawdę dużą wiedzę na temat systemu GNU/Linux to niestety przyda się ona w kilku/kilkunastu przypadkach. Systemom rodziny BSD, bliżej do macOS X i dziedzictwa UNIX-a niż do GNU/Linux. Nie są one skomplikowane, wręcz przeciwnie, ale brak elementarnej wiedzy powoduje że ten system może być dla nas abstrakcją. Tutaj jedną z niezrozumiałych rzeczy może być PF, zapraszam do dokumentacji PF na stronie projektu OpenBSD, która jest dostępna w postaci podręcznika https://www.openbsd.org/faq/pf/index.html. Może również pojawi się i tutaj w mojej streszczonej sprawdzonej wersji polskiej. Zabawy z PF.

~xf0r3m