Ochrana SSH proti útokům

obranaJednou z možných ochran proti SSH útokům, kdy se útočník pomocí automatizovaných skriptů snaží periodicky lámat účty uživatelů s jednoduchými hesly (třeba uživatel user a heslo user), je použití iptables a programu sshdfilter.

Jak to funguje?

SSH démon zapisuje do logu neúspěšné pokusy o zalogování – typicky vypadají nějak takto:

Did not receive identification string from x.x.x.x
Illegal user x from x.x.x.x
Failed password for illegal user x from x.x.x.x port x ssh2
Failed password for x from x.x.x.x port x ssh2

sshdfilter je jednoduchý skript napsaný v Perlu, který tyto neúspěšné pokusy sleduje a v případě, že počet neúspěšných pokusů z jedné IP adresy překročí určitý počet (tento počet lze nastavit), tak vytvoří pravidlo do firewallu (skript využívá vlastní řetězec, takže nehrozí riziko přepsání), které bude blokovat traffic z dané IP adresy na port 22. Lze nastavit i dobu po jakou bude tento traffic z dané IP adresy blokován. Tímto způsobem lze jednoduše odfiltrovat poměrně velký počet útoků.

Instalace

Instalace v distribuci CentOS 4.3 se provede následovně:

wget http://www.csc.liv.ac.uk/~greg/sshdfilter-1.4.4.tar.gz

su -
cp /home/user/sshdfilter-1.4.4.tar.gz /usr/src
cd /usr/src
tar zxvf sshdfilter-1.4.4.tar.gz
cd sshdfilter-1.4.4

perl install.pl

Ještě je potřeba ručně upravit pravidla firewallu – tedy soubor /etc/sysconfig/iptables, do kterého přidáme na vhodná místa následující řádky:

:SSHD - [0:0]
...
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 22 -j SSHD

Pak už stačí restartovat patřičné služby:

/etc/init.d/iptables restart 
/etc/init.d/sshd restart

Konfigurace

Konfigurační soubor se nachází v /etc/sshdfilterrc.

—————–

Ochrana SSH démona proti útokům (2)

Další možností jak předejít útokům (úvod do této problematiky a jedno z možných řešení lze nalézt zde) je úplné vypnutí autentizace na základě jména a hesla a používání pouze autentizace na základě klíčů.

Jak to funguje?

Vygenerujeme si na daném klientském počítači (ze kterého se na server/další počítač budeme přihlašovat) pár klíčů (soukromý a veřejný) a veřejný klíč si pomocí bezpečného kanálu (tedy opět přes SSH) zkopírujeme na server. Poté co ověříme funkčnost tohoto způsobu přihlašování, tak na serveru zakážeme přihlášení pomocí jména a hesla. Pro názornost budu klientskou stanici nazývat client a server budu nazývat server. Uživatel bude na obou stanicích stejný (může se samozřejmě lišit, to není podmínkou) – bude se jmenovat ondra.

Nastavení

ondra@client:~$ ssh-keygen -t dsa

Tímto jsme si vytvořili veřejný a soukromý klíč na klientské stanici. Pokud se chcete přihlašovat pod nějakým heslem (pro přesnost – není to klasické heslo, ale passphrase), tak jej zadejte, pokud ne, tak jej zadejte prázdné. Pokud jsme nezměnili adresář pro uložení klíčů, tak je nalezneme v adresáři /home/ondra/.ssh/, kde id_dsa je soubor se soukromým klíčem a id_dsa.pub je soubor s veřejným klíčem. Veřejný klíč následně zkopírujeme na server a přejmenujeme tímto příkazem (záměrně nepoužívám příkaz scp pro kopírování, protože by mohlo dojít k přepsání stávajícího souboru s klíčema):

ondra@client:~$ cat ~/.ssh/id_dsa.pub | ssh ondra@server "cat >> .ssh/authorized_keys"

Tento příkaz nebude fungovat pokud na serveru nemáte vytvořený adresář .ssh. Ještě je víc než vhodné změnit práva souboru authorized_keys (SSH odmítne spojení v případě, že práva na tomto souboru budou příliš benevolentní). Lze to provést zase vzdáleně za pomoci ssh a to takto:

ondra@client:~$ ssh ondra@server chmod 600 .ssh/authorized_keys

Teď už zbývá jen vyzkoušet komunikaci, tzn. připojit se k serveru pomocí příkazu ssh ondra@server. Pokud jste nastavili passphrase, tak po vás bude požadováno její zadání.

Pokud výše uvedené funguje, tak můžeme přistoupit k hlavnímu kroku a tím je zakázání autentizace pomocí hesla a tím zabránění útokům, kdy se útočník snaží periodicky hádat jednoduchá hesla. Autentizace zakážeme na serveru tak, že změníme následující direktivy (v souboru /etc/ssh/sshd_config) na hodnoty no.

PasswordAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin no

Změna volby ChallengeResponseAuthentication na hodnotu no je velice důležitá, protože pokud by byla ponechána zapnutá a systém by využíval pro přihlášení PAM (což u většiny distribucí využívá), tak by přihlášení uživatele, bez ohledu na hodnotu direktivy PasswordAuthentication, probíhalo klasickým způsobem – tedy na základě uživatelského jména a hesla.

Po tomto kompletním nastavení musíme restartovat/reloadnout démona sshd a to například následujícím způsobem:

/etc/init.d/sshd reload

Pokud se přihlásíte ze stanice ze které byl generován klíč, tak bude (po případném zadání passphrase) přihlášení úspěšné. Při přihlašování z jiné (nedůvěryhodné) stanice nám ssh démon odpoví následující hláškou:

Permission denied (publickey,gssapi-with-mic).

což znamená, že naše nastavení je správné.

——————–

Ochrana SSH démona proti útokům (3)

Kromě vypnutí autentizace na základě jména a hesla v konfiguraci ssh démona a povolení autentizace na základě klíčů (viz 2. díl) a kromě použití programu sshdfilter nebo podobného na blokování portu 22 (s využitím iptables) při detekci většího počtu neúspěšných pokusů o přihlášení (viz 1. díl) můžeme využít ještě další možnost jak ochánit ssh démona před útoky a přitom si nijak výrazně neomezit vzdálený přístup. Jedná se o ochranu pomocí tzv. port knockingu. Výhodou této metody je, že si vystačíme pouze se stavovým filtrem, tedy s iptables.

Jak to funguje?

Pomocí iptables a především modulu recent můžeme firewall nastavit tak, že se port 22 otevře (obvykle pouze na pár vteřin) na základě „zaťukání“ (port knockingu) na námi stanovené porty (například: 250 100 150 200). Není to sice nejpohodlnější metoda, ale když si napíšeme jednoduchý skript, který za nás například pomocí programu telnet nebo nmap dané porty kontaktuje a poté se přes otevřený ssh port připojí k ssh serveru, tak to zase nijak pracné nebude.

Nastavení

#!/bin/bash

# smazeme predchozi nastaveni pravidel a nami nadefinovanych retezcu
/sbin/iptables -F
/sbin/iptables -X

# nastavime defaultni politiky
/sbin/iptables -P INPUT DROP
/sbin/iptables -P FORWARD DROP
/sbin/iptables -P OUTPUT ACCEPT

/sbin/iptables -N MYKNOCK2
/sbin/iptables -A MYKNOCK2 -m recent --name KNOCK1 --remove
/sbin/iptables -A MYKNOCK2 -m recent --name KNOCK2 --set
/sbin/iptables -A MYKNOCK2 -j LOG --log-prefix "MYKNOCK2: "

/sbin/iptables -N MYKNOCK3
/sbin/iptables -A MYKNOCK3 -m recent --name KNOCK2 --remove
/sbin/iptables -A MYKNOCK3 -m recent --name KNOCK3 --set
/sbin/iptables -A MYKNOCK3 -j LOG --log-prefix "MYKNOCK3: "

/sbin/iptables -N MYKNOCK4
/sbin/iptables -A MYKNOCK4 -m recent --name KNOCK3 --remove
/sbin/iptables -A MYKNOCK4 -m recent --name KNOCK4 --set
/sbin/iptables -A MYKNOCK4 -j LOG --log-prefix "MYKNOCK4: "

/sbin/iptables -A INPUT -m recent --update --name KNOCK1

/sbin/iptables -A INPUT -m tcp -p tcp --dport 250 -m recent --set --name KNOCK1
/sbin/iptables -A INPUT -m tcp -p tcp --dport 100 -m recent --rcheck --name KNOCK1 -j MYKNOCK2
/sbin/iptables -A INPUT -m tcp -p tcp --dport 150 -m recent --rcheck --name KNOCK2 -j MYKNOCK3
/sbin/iptables -A INPUT -m tcp -p tcp --dport 200 -m recent --rcheck --name KNOCK3 -j MYKNOCK4

/sbin/iptables -A INPUT -p tcp --dport 22 -m recent --rcheck --seconds 5 --name KNOCK4 -j ACCEPT

/sbin/iptables -A INPUT -i lo -j ACCEPT
/sbin/iptables -A INPUT -m icmp -p icmp --icmp-type any -j ACCEPT
/sbin/iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
/sbin/iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited

Případný výstup z programu iptables-save bude vypadat následovně:

# Generated by iptables-save v1.3.5 on Thu Oct 19 16:26:20 2006
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:MYKNOCK2 - [0:0]
:MYKNOCK3 - [0:0]
:MYKNOCK4 - [0:0]
-A INPUT -m recent --update --name KNOCK1 --rsource
-A INPUT -p tcp -m tcp --dport 250 -m recent --set --name KNOCK1 --rsource
-A INPUT -p tcp -m tcp --dport 100 -m recent --rcheck --name KNOCK1 --rsource -j MYKNOCK2
-A INPUT -p tcp -m tcp --dport 150 -m recent --rcheck --name KNOCK2 --rsource -j MYKNOCK3
-A INPUT -p tcp -m tcp --dport 200 -m recent --rcheck --name KNOCK3 --rsource -j MYKNOCK4
-A INPUT -p tcp -m tcp --dport 22 -m recent --rcheck --seconds 5 --name KNOCK4 --rsource -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A MYKNOCK2 -m recent --remove --name KNOCK1 --rsource
-A MYKNOCK2 -m recent --set --name KNOCK2 --rsource
-A MYKNOCK2 -j LOG --log-prefix "MYKNOCK2: "
-A MYKNOCK3 -m recent --remove --name KNOCK2 --rsource
-A MYKNOCK3 -m recent --set --name KNOCK3 --rsource
-A MYKNOCK3 -j LOG --log-prefix "MYKNOCK3: "
-A MYKNOCK4 -m recent --remove --name KNOCK3 --rsource
-A MYKNOCK4 -m recent --set --name KNOCK4 --rsource
-A MYKNOCK4 -j LOG --log-prefix "MYKNOCK4: "
COMMIT
# Completed on Thu Oct 19 16:26:20 2006

Skript pro port knocking pomocí telnetu a následné připojení pomocí ssh klienta na danou IP adresu. Tento skript je jen jako názorný příklad, samozřejmě by se dal podstatně vylepšit a parametrizovat.

#!/bin/bash

for port in 250 100 150 200
do
telnet 192.168.2.100 $port > /dev/null 2>&1;
done

ssh ondra@192.168.2.100

Druhý skript se stejnou funkčností, ale využívající místo telnetu program nmap.

for port in 250 100 150 200
do
nmap -P0 -sT -p $port --host_timeout 250 192.168.2.100 > /dev/null 2>&1;
done

ssh ondra@192.168.2.100

—————-

Ochrana SSH démona proti útokům (4)

Způsobů jak ochránit SSH démona proti útokům je mnoho. Jednou z dalších možností jak zabránit „brute force“ útokům je využití modulů PAM (Pluggable Authentication Modules), konkrétně pak „auto blacklist“ modulu pam_abl.

Jak to funguje?

Jednoduše řečeno – PAM je systém knihoven, které jednotlivé programy (např. login, su, …) volají v případě, když je potřeba autentizovat (ověřit totožnost) uživatele. Jak už napovídá název, PAM (Pluggable Authentication Modules) je vytvořen tak, že jej lze snadno konfigurovat, takže je na správci jak si jej přizpůsobí k obrazu svému.

My tedy do procesu autentizace jednoduše vložíme ještě výše zmíněný modul pam_abl, který poskytuje možnost automaticky přidat do black listu ty počítače (IP adresy nebo jejich názvy) a uživatele, kteří se opakovaně neúspěšně pokusili o přihlášení (jinak řečeno překročili limit neúspěšných přihlášení uvedený v konfiguračním souboru) do systému přes SSH protokol.

Tento způsob funguje trochu jinak než blokování s využitím iptables (např. pomocí sshdfilteru). Uživateli nezamezíme přístup k ssh démonu, ale veškeré jeho další pokusy o přihlášení do systému přes SSH protokol budou neúspěšné i kdyby zadal správné uživatelské jméno a heslo. Toto někomu nemusí vyhovovat, každopádně je to stejně účinná ochrana jako blokování přístupu s využítím IP filtru iptables. Můžeme nastavit i dobu po jejímž uplynutí bude záznam z black list databáze automaticky odstraněn, stejně jako tomu je i u sshdfilteru.

Modul pam_abl lze použít pro jakýkoliv program využívající pro autentizaci uživatele PAM, tzn. kromě SSH démona jej můžeme využít např. pro FTP démona vsftpd, pro blokování lokálně přihlašovaných uživatelů a podobně.

Nastavení

Dag Wieers nám opět ušetřil práci, takže instalace modulu pam_abl bude velice jednoduchá a pokud máte nastaven jeho repozitář RPMForge, tak vám pro instalaci bude stačit následující příkaz:

yum install pam_abl

Nejprve přidáme modul pam_abl do konfiguračního souboru, který využívá SSH démon pro PAM autentizaci. Tento soubor se v CentOSu nazývá /etc/pam.d/sshd. Po jednoduché úpravě spočívající v přidání druhého řádku týkajícího se modulu pam_abl bude tento soubor vypadat následovně:

#%PAM-1.0
auth required pam_abl.so config=/etc/security/pam_abl.conf
auth include system-auth
account required pam_nologin.so
account include system-auth
password include system-auth
session optional pam_keyinit.so force revoke
session include system-auth
session required pam_loginuid.so

Konfigurační soubor modulu pam_abl, který leží v souboru /etc/security/pam_abl.conf je součástí RPM balíčku a jeho obsah vypadá následovně:

# /etc/security/pam_abl.conf
# debug
host_db=/var/lib/abl/hosts.db
host_purge=2d
host_rule=*:10/1h,30/1d
user_db=/var/lib/abl/users.db
user_purge=2d
user_rule=!ondra:10/1h,30/1d

Direktiva host_db a user_db udává cestu k Berkeley DB se seznamem blokovaných počítačů a uživatelů. Direktivou host_purge a user_purge se nastavuje doba po kterou se daný počítač nebo uživatel bude blokovat. V tomto případě je blokování nastaveno na dva dny. Direktivou host_rule a user_rule se nastavují pravidla, kdy se začně počítač nebo uživatel blokovat.

host_rule=*:10/1h,30/1d

Výše uvedené pravidlo začne blokovat přihlášení z počítače ze kterého bude 10 neúspěšných pokusů o přihlášení v průběhu jedné hodiny nebo 30 neúspěšných pokusů v průběhu jednoho dne.

user_rule=!ondra:10/1h,30/1d

Výše uvedené pravidlo začne blokovat přihlášení jakéhokoliv uživatele (kromě uživatele ondra) na něhož bude 10 neúspěšných pokusů o přihlášení v průběhu jedné hodiny nebo 30 neúspěšných pokusů v průběhu jednoho dne.

Podrobnější popis pravidel, jejich syntaxi a další příklady pravidel naleznete v dokumentaci k modulu pam_abl.

Pokud máte vše správně nastavené, tak by se vám při překročení zadaného počtu neúspěšných pokusů o přihlášení přes SSH protokol za danou časovou jednotku měl v logu /var/log/secure objevit záznam podobný níže uvedenému:

Dec 15 18:23:54 tachecn pam_abl[8892]: Blocking access from www.tachec.org to service sshd, user ondra

Součástí RPM balíčku pam_abl je i stejnojmenný nástroj, který slouží k výpisu blokovaných počítačů z databáze a případně ke smazání počítačů či užavatelů (tedy ke zrušení blokování) z této databáze.

pam_abl -v

Reading config from /etc/security/pam_abl.conf
Failed users:
ondra (1)
Sat Dec 15 19:13:10 2007
Failed hosts:
www.tachec.org (1)
Sat Dec 15 19:13:10 2007

Vypíše seznam neúspěšných přihlášení včetne data a času, kdy k neúspěšnému přihlášení došlo.

Pokud bych chtěl zrušit blokování například pro celou doménu tachec.org, tak to s pomocí příkazu pam_abl provedu následovně:

pam_abl -v --okhost=*.tachec.org

Reading config from /etc/security/pam_abl.conf
Deleted 1 item

Zdroje:
http://www.tachec.org/tipsandtricks/securing_ssh/
http://www.tachec.org/tipsandtricks/securing_ssh2/
http://www.tachec.org/tipsandtricks/securing_ssh3/
http://www.tachec.org/tipsandtricks/securing_ssh4/