15.03.2017 | 07:00

krystian

Zabezpieczanie serwera w wariancie dla umiarkowanych paranoików

Aby zabezpieczyć serwer przed większością ataków wystarczy wdrożyć kilka prostych rozwiązań. Co jednak, jeśli ktoś się na naszą maszynę uweźmie i będzie dysponował dużą ilością czasu i pomysłów? Można mu bardziej utrudnić zadanie.

We współpracy z firmą ArubaCloud pokazaliśmy Wam, jak postawić swój serwer backupów, jak skonfigurować własny serwer VPN i podłączyć do niego komputer, telefony komórkowe oraz domowy ruter a także jak schować się przed cenzurą sieci i jak zacząć serwer zabezpieczać, jak postawić swój własny zdalny pulpit i swój serwer WWW oraz jak monitorować dowolnie wybrane pliki lub katalogi. Dzisiaj pokażemy pewną rzadziej spotykaną metodę zabezpieczenia serwera przed wyjątkowo natrętnymi atakującymi.

Po co mi to

Kilka miesięcy temu pokazaliśmy Wam, jak serwer zabezpieczyć – logować się po SSH za pomocą klucza, skonfigurować proste banowanie natrętnych intruzów i aktywować automatyczne aktualizacje. Wiemy jednak, że sporo z Was lubi podnosić poziom swoich zabezpieczeń dużo powyżej przeciętnego, dlatego dzisiaj pokażemy, jak serwer zabezpieczyć tak, by praktycznie nikt nie mógł się do niego połączyć. Nikt – oprócz Was.

Konfigurację pokażemy na przykładzie serwera w Aruba Cloud, sponsora naszych poradników. Jeśli nie macie jeszcze swojej własnej maszyny, to jest to dobra okazja by się w taką wyposażyć. Aruba oferuje dwa miesiące korzystania ze swojego podstawowego serwera gratis – a po zakończeniu promocji będzie on Was kosztował zaledwie 4 złote miesięcznie. Instrukcję jak krok po kroku skorzystać z promocji i uruchomić swój serwer znajdziecie w tym artykule. Jeśli macie już swój serwer – to zapraszamy do lektury kolejnych akapitów.

Pokażemy Wam dzisiaj, jak serwer skonfigurować tak, by nie odpowiadał na połączenia na żadnym porcie – ale byście mogli się do niego połączyć gdy tego zechcecie. Oczywiście można to zrealizować za pomocą reguł firewalla, ograniczających zakres źródłowych adresów IP. Kiedy jednak nie wiecie, z jakiego IP będzie się łączyć, z pomocą przychodzi tzw. port knocking, czyli pukanie do portów. Serwer będzie miał zamknięty port SSH dopóki nie wykonacie określonej w konfiguracji sekwencji połączeń. Gdy Wasz komputer połączy się z odpowiednimi portami we właściwej kolejności za pomocą odpowiednich pakietów, serwer otworzy dla Was SSH. Gdy skończycie pracę, będziecie mogli ten port w podobny sposób zamknąć. Jak takie cudo skonfigurować?

Konfigurujemy serwer

Zainstalujemy usługę knockd która będzie odpowiedzialna za otwieranie portu ssh (tcp/22) po uzyskaniu odpowiedniej sekwencji.

Na początku instalujemy wymagane pakiety do skompilowania usługi knockd ze źródeł:

$ sudo yum install git libpcap-devel.x86_64 autoconf automake

Następnie musimy pozyskać źródło usługi knockd. Usługa ta jest dostępna w serwisie GitHub pod tym adresem. Pozyskujemy źródła knockd za pomocą polecenia git:

git clone https://github.com/jvinet/knock

oraz kompilujemy w następujący sposób:

$ cd knock
$ autoreconf -fi
$ ./configure --prefix=/usr/local/
$ make
$ sudo make install

Po wydaniu polecenia make install plik binarny knockd został skopiowany do katalogu /usr/local/sbin/knockd, natomiast przykładowy plik konfiguracyjny knockd.conf został skopiowany do katalogu /usr/local/etc/.

Edytujemy plik /usr/local/etc/knockd.conf według naszych potrzeb:

[options]
        logfile = /var/log/knockd.log

[openSSH]
        sequence = 4444,8989,6500
        seq_timeout = 5
        tcpflags = syn
        Start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

[closeSSH]
        sequence = 4445,8990,6501
        seq_timeout = 5
        tcpflags = syn
        command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT 

W powyższej konfiguracji w sekcji [options] ustawiamy plik logowania – /var/log/knockd.log – w tym pliku będą zapisane wszelkie informacje o zdarzeniach. Następnie w sekcji [openSSH] ustawiamy sekwencję na portach 4444,8989, 6500. Seq_timeout określa maksymalny czas na uzyskanie pełnej sekwencji połączeń do wskazanych przez nas portów – w naszym przykładzie jest to 5 sekund. Tcpflags określa które pakiety mają być uwzględniane – w naszym przypadku są to pakiety tcp z ustawioną flagą SYN.

Jeśli sekwencja będzie poprawna nastąpi uruchomienie polecenia zdefiniowanego w start_command. W opisywanym przykładzie wykonujemy polecenie iptables które dodaje regułę zezwalającą na nawiązanie połączenia z adresu ip, który wykonał poprawną sekwencję do naszego serwera na port 22 (ssh).

Bardzo podobną regułę zastosowano w dyrektywie [closeSSH] w której określono połączenia na porty 4445, 8990, 6501. Wysłanie pakietów tcp z flagą SYN w czasie nie dłuższym niż 5 sekund spowoduje wywołanie komendy iptables w której zdefiniowano zablokowanie dostępu do portu 22 dla adresu ip, który wykonał poprawną sekwencje połączeń.

Plik startowy

Tworzymy i edytujemy plik /etc/systemd/system/knockd.service:

[Unit]
Description=knockd service
After=network.target

[Service]
ExecStart=/usr/local/sbin/knockd -d -c /usr/local/etc/knockd.conf
Type=forking
PIDFile=/var/run/knockd.pid

[Install]
WantedBy=multi-user.target

Aby zastosować zmiany w systemie wydajemy polecenie:

sudo systemctl daemon-reload

i uruchamiamy usługę knockd:

sudo service knockd start

Jeśli chcemy aby usługa była uruchamiana podczas rozruchu systemu, wydajemy polecenie:

sudo systemctl enable knockd

Wysyłamy sekwencję

Serwer otworzy nam port 22/tcp jeśli wykonamy sekwencję prób połączeń na porty określone w konfiguracji: 4444, 8989, 6500.

Sekwencję możemy wykonać za pomocą:

nmap -p 4444,8989,6500 adres-ip-naszego-serwera

lub za pomocą klienta, który został utworzony podczas kompilowania usługi knockd:

knock adres-ip-naszego-serwera 4444:tcp 8989:tcp 6500:tcp

Po wykonaniu powyższych sekwencji usługa knockd powinna otworzyć port 22/tcp, a w logu (/var/log/knockd.log) powinno pojawić się następujące zdarzenie:

[2017-03-07 11:00] nasz-ip: openSSH: Stage 1
[2017-03-07 11:00] nasz-ip: openSSH: Stage 2
[2017-03-07 11:00] nasz-ip: openSSH: Stage 3
[2017-03-07 11:00] nasz-ip: openSSH: OPEN SESAME
[2017-03-07 11:00] openSSH: running command: /sbin/iptables -I INPUT -s nasz-ip -p tcp --dport 22 -j ACCEPT

Przedstawiliśmy przykładową konfigurację która umożliwia otwarcie portu 22/tcp dla usługi ssh po wykonaniu sekwencji połączeń do naszego serwera. Usługę można dostosować do swoich potrzeb jak chociażby ustawienie jakie pakiety tcp powinny być uwzględniane do wykrycia sekwencji – do wyboru mamy pakiety z flagą fin, syn, rst, psh,ack,urg.

Gdy już jesteśmy pewni, że wszystko działa jak należy, możemy zablokować dostęp do ssh wydając polecenie:

iptables -A INPUT -p tcp --dport 22 -j DROP

Dostęp do 22/tcp (ssh) będzie otwierany adresom IP, które wykonały poprawną sekwencję połączeń. Poniżej znajdziecie powyższą instrukcję w wersji wideo:

Wady i zalety

Zalety port knockingu:

  • zabezpiecza przed atakami brute force w ramach protokołu np. SSH,
  • zabezpiecza przed atakami na sam protokół,
  • nawet prosta sekwencja (jak opisana powyżej) wymaga dużego nakładu sił do przełamania,
  • może być jedną z warstw obrony (oprócz uwierzytelnienia loginem, hasłem czy kluczem),
  • otwiera port tylko dla konkretnego adresu IP, który może być zmienny (lub dla wielu, jeśli jest wielu użytkowników znających sekwencję).

Wady port knockingu:

  • w razie awarii demona nasłuchującego połączeń może odciąć od serwera (wtedy przydaje się procedura awaryjna opisana w tym artykule),
  • jeśli ktoś uzyska w inny sposób dostęp do serwera (np. przez dostęp fizyczny), to może w logach zaobserwować prawidłową sekwencję,
  • sekwencja może zostać podsłuchana w ataku MiTM.

Jak w przypadku każdego mechanizmu obronnego to do Was należy decyzja czy warto go zastosować.

Dla pełnej przejrzystości – za przygotowanie oraz opublikowanie powyższego artykułu otrzymujemy wynagrodzenie.

Powrót

Komentarze

  • 2017.03.15 07:29 W4R10CK

    Mam pytanie, czy da się ustawić, aby serwer jeśli po odblokowaniu portu nie wykryje ruchu na porcie, to po jakimś czasie go blokował? Gdybym przypadkiem zapomniał zablokować port po połączeniu? Pozdrawiam

    Odpowiedz
    • 2017.03.15 09:10 Az

      Musiało by to być kilka sekund. Ruch na porcie 22 jest co chwila, bez przerwy różnego typu ataki jak sprawdzenie najczęstszych (często domyślnych) danych logowania

      Odpowiedz
      • 2017.03.15 13:33 Wojtek

        Zmiana portu na jakiś inny + fail2ban z długim czasem banowania adresów ip i po kłopocie.

        Oczywiście przy założeniu, że możemy się logować przez hasła, bo jak damy ssh tylko po kluczach to bruteforce nam raczej nie grozi.

        Odpowiedz
        • 2017.03.15 23:12 Norbert S. Klanu

          + klucze (tylko ed25519) + PSAD

          Odpowiedz
    • 2017.03.15 11:15 Wojtek

      W konfigu knockd mozna ustawic czas po, którym odpalana jest automatycznie druga komenda np. zamykajaca dostep do portu ssh na fw po pierwszej komendzie.
      Dodatkowo jesli ktos nie loguje sie z miejsc o bardzo zmiennym ip mozna napisac skrypt, ktory bedzie otwieral port ssh dla adresu ip, z ktorego byla wyslana poprawna sekwencja knockd.
      Mozna tez ustawic na iptables aby utrzymywal nawiazane polaczenia i zamykac port do ssh po jakims czasie domyslnie.

      Knockd znam od lat, jest swietny.

      Odpowiedz
    • 2017.03.15 12:58 M.

      Bardzo prosto, przesyłam przykładowy config z knockd.conf:

      [SSHD]
      sequence = x,x,x,x
      seq_timeout = 6
      tcpflags = x,x,x
      start_command = /sbin/iptables -I INPUT xxxxxx -m state –state NEW -j ACCEPT
      cmd_timeout = 60
      stop_command = /sbin/iptables -D INPUT xxxxxx -m state –state NEW -j ACCEPT

      po 60 sekundach od chwili otwarcia portu SSH port się zamyka na nowe połączenia. Stare połączenia nadal działają, bo jest iptables -A INPUT xxxxx -m state –state ESTABLISHED,RELATED -j ACCEPT

      Odpowiedz
      • 2017.03.15 13:36 Wojtek

        Można zrobić skrypt który skanuje log knockda i wyławia ostatnią udaną sekwencję zwracają adres ip z jakiej pochodzi sekwencja.

        Potem wystarczy zmodyfikować komendę ip tables aby otwierała port tylko na dany ip.

        Wtedy uzyskujemy:

        – otwarcie portu na 60 s
        – dla danego ip
        – automatycznie zamykamy
        – utrzymujemy połączenie, które nawiązało się wcześniej

        Odpowiedz
      • 2017.03.15 15:17 Ferex

        Mógłbyś podać jakiś pełny przykład z małym wyjaśnieniem ? :)

        Odpowiedz
        • 2017.03.15 22:09 Wojtek

          Jutro coś naskrobię więcej na temat :D

          Odpowiedz
  • 2017.03.15 08:48 Popo

    Spoko, z wyjątkiem instalowania softu przez „make install”, co powoduje, ze pliki nie są objęte systemem pakietów.

    Odpowiedz
    • 2017.03.15 12:04 Borys

      Tutaj masz, trzeba tylko paczkę instalacyjną stworzyć: http://www.invoca.ch/pub/packages/knock/RPMS/ils-7/SRPMS/

      Odpowiedz
    • 2017.03.15 18:44 K

      Dostępne są nieoficjalne pakiety knockd na różnych, nieoficjalnych repozytoriach. Instalację nieoficjalnych pakietów w systemie pozostawiam do własnego rozważenia.

      Odpowiedz
      • 2017.03.15 20:01 Borys

        Poco masz instalować z nie oficjalnych jak można z oficjalnych, które podałem wyżej!

        Odpowiedz
  • 2017.03.15 10:08 Example

    Fajną opcją są tokeny od google połączone z ssh (tak wiem, google jest złe, ale te pliki są udostępnione gdzieś na gicie).

    Odpowiedz
    • 2017.03.15 11:48 yatsaman

      Właśnie takie coś mi chodzi od dłuższego czasu po głowie, ale w zestawieniu z port-knockingiem.

      Token od Google’a to 6 cyfr. Myślę że spokojnie dałoby się chociażby przez zwykłe przypisanie określonego portu do każdej cyfry uzyskać knock-pattern zmienny w czasie i bardzo odporny na ataki MitM

      Może przesada ale jak mawiają: „to że mam klinicznie stwierdzoną paranoję jeszcze nie oznacza że nikt mnie nie śledzi” :)

      Odpowiedz
  • 2017.03.15 11:56 Paweł

    Ja używam prostego skryptu nasłuchującego na porcie 8888/UDP:

    #!/usr/bin/env python
    import socket
    import sys
    import os

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind((„”,8888))

    while True:
    d,a = s.recvfrom(1024)
    if d[:11] == „haslo_otworz_port”:
    os.system(„iptables -R ssh 1 -p tcp –dport 22 ! -s”+ \
    str(a[0])+” -j DROP”)
    s.sendto(„ssh port open\n”, a)

    elif d[:13] == „haslo_zamknij_port”:
    os.system(„iptables -R ssh 1 -p tcp –dport 22 -j DROP”)
    s.sendto(„ssh port closed\n”, a)

    #end_file

    Wystarczy że wyśle hasło za pomocą netcata:
    echo „haslo_otworz_port” | nc -u 8888

    Mam jeszcze dodane w iptables filtrowanie pakietów ICMP/port_unreachable żeby nie można było namierzyć otwartego portu UDP.

    Niedawo mój domowy ISP zmnienił zewnętrzne IP (jestem za NAT-em) więc mogłem się połączyć z ssh dopiero jak ponownie wysłałem hasło na port 8888.

    Odpowiedz
    • 2017.03.15 13:38 Wojtek

      No tak ale tutaj wystarczy podsłuchać jeden pakiet aby zrobić replay z innego miejsca.

      Dodatkowo knockd ma log aby sprawdzić czy wszystko jest ok a tu :D ?

      Odpowiedz
      • 2017.03.16 01:29 Paweł

        Masz racje hasło jest jawne ale wysyłane jest raz na ruski rok i nie służy do autoryzacji tylko do otwacia portu.
        Z drugiej strony gdzie jest większe ryzyko istnienia potencjanych dziur czy w 10 linijkowym pythonowym skrypcie czy w prawie 2000 lini kodu C ?
        To jest pytanie retoryczne ;)

        Odpowiedz
  • 2017.03.15 12:20 wiesio

    Ostrożnie! Sama koncepcja knockd jest fajna, ale czyż nie okaże się, że nie będziemy się mogli połączyć z naszym serwerem gdy będziemy to robić z sieci, która wycina ruch na egzotyczne porty? Trzeba szukać serwera na zewnątrz sieci w której jesteśmy i z niego dopiero odpukać sekwencję. Odradzam również dodawania do sekwencji standardowych portów często używanych usług, bo są one skanowane tak często, że istnieje niezerowa szansa, że przypadkiem ktoś nam będzie port SSH włączać i wyłączać.

    Odpowiedz
  • 2017.03.15 18:08 TerazReset

    Skoro vps w aruba to tylko 4zł i ma stałe IP, to jakimś rozwiązaniem może być logowanie się po ssh, tylko z tego serwera.

    Odpowiedz
    • 2017.03.16 09:05 mwojtow

      tylko jak sie zalogowac do tego vps? przez kosole www? to jeszcze bardziej upierdliwe niz pukanie

      Odpowiedz
  • 2017.03.15 19:41 Filip

    Fajne dajecie te art, nie ma co:) Własnie myslalem, co tu zrobic, zeby zabezpieczyc serwer :)

    IMHO co sekwencji portów, mozna by to zrobic w funkcji czasu/daty, i wtedy na podstawie znanej zmiennej (czas z NTP) wyliczac sekwencje portów.

    Odpowiedz
  • 2017.03.15 23:32 TWAt2

    A jak z pod Windy automatycznie pukać gdy łączymy się putty ?

    Odpowiedz
  • 2017.03.16 09:02 mwojtow

    A po co uzywac knockd? To samo mozna uzyskac w czystym iptables (wlacznie z czasami blokowania)

    Odpowiedz
    • 2017.03.16 14:05 M.

      Podasz przykład?

      Odpowiedz
  • 2017.03.16 14:07 M.

    A takie pytanie do przemyślenia – czy jest możliwe ustalenie przybliżonych zakresów IP, które częściej są wykorzystywane do malware / ransomware i zablokować ruch do nich?

    Odpowiedz
  • 2017.03.16 14:12 M.

    Po części sam sobie odpowiadam – https://ransomwaretracker.abuse.ch/blocklist/

    Odpowiedz
  • 2017.03.16 17:06 M.

    I jeszcze jeden przykład ciekawego zabezpieczenia:

    Automatically Ban Hosts That Attempt to Access Invalid Services

    ipset also provides a „target extension” to iptables that provides a mechanism for dynamically adding and removing set entries based on any iptables rule. Instead of having to add entries manually with the ipset command, you can have iptables add them for you on the fly.

    For example, if a remote host tries to connect to port 25, but you aren’t running an SMTP server, it probably is up to no good. To deny that host the opportunity to try anything else proactively, use the following rules:

    ipset -N banned_hosts iphash
    iptables -A INPUT \
    -p tcp –dport 25 \
    -j SET –add-set banned_hosts src
    iptables -A INPUT \
    -m set –set banned_hosts src \
    -j DROP

    If a packet arrives on port 25, say with source address 1.1.1.1, it instantly is added to banned_hosts, just as if this command were run:

    ipset -A banned_hosts 1.1.1.1

    All traffic from 1.1.1.1 is blocked from that moment forward because of the DROP rule.

    Note that this also will ban hosts that try to run a port scan unless they somehow know to avoid port 25.

    za: http://www.linuxjournal.com/content/advanced-firewall-configurations-ipset?page=0,2

    Odpowiedz
  • 2017.03.23 15:01 dfdfdffdfggggg

    Ja mam tak zabezpieczone
    https://www.cyberciti.biz/tips/linux-unix-bsd-openssh-server-best-practices.html#comment-629576

    Pozmieniałem tylko lekko czasy, bo 5 sekund to czasami za mało.
    Zapomniałem co to boty w ssh.

    Odpowiedz
  • 2017.04.01 21:11 czytelnik

    Wydaje mi się, że nmap nie zadziała, bo skanuje porty losowo.
    Można użyć przełącznika -r, aby skanował po kolei, ale wtedy leci numerami portów od najniższego, a więc zamiast 4444,8989,6500 będzie 4444,8989,6500.
    Ew. próbować z losową kolejnością do skutku

    Odpowiedz

Zostaw odpowiedź do mwojtow

Jeśli chcesz zwrócić uwagę na literówkę lub inny błąd techniczny, zapraszamy do formularza kontaktowego. Reagujemy równie szybko.

Zabezpieczanie serwera w wariancie dla umiarkowanych paranoików

Komentarze