Blokování kombinace ip adresy a portu na základě informací z logu
- Úvod, proč, jak
- Negativní důsledy blokování IP
- Jak to funguje na firewall-u (iptables)
- Řešení pomocí PHP scriptu
- Konfigurace k PHP scriptu
- Zdroje informací
Úvod, proč
Pokud nás zlobí scanování portu 22(ssh), nebo chceme zvýšit bezpečnost např. ftp, https serveru apod.Co se týká ssh, je jej možné chránit i pomocí certifikátů, přístupu jen z povolených adres, nastavení přístupu jen dannému uživatel (skupině) atd. Ale pokud například chcete mít přístup odkukoliv a nechcete se obtěžovat s certifikáty, tak máte jen možnost silného hesla a případné periodické změny hesla.
Pro zvýšení bezpečnosti je možné vyhodnotit chování druhé strany (v tomto případě chováni IP adresy) a pokud se nám chování nelíbí, tak jí odepřít vstup do systému (v tomto případě uzavřít pro ni firewall).
Pro zvýšení bezpečnosti například ftp serveru či http(s) přihlašování je velmi vhodné mít mechanismy již v serveru či aplikaci, ale zablokování IP adresy odlehčí serveru, který zpravidla musí provést složitější vyhodnocovací process.
Rozhodně bych doporučil blokování IP:PORT na základě chování clienta pro veřejné „domácí“ a „testovací“ servery – nebudete přece neustále kontrolovat bezpečnost a měnit hesla. Rovněž lze se řešení doporučit do vnitřní sítě jako prvek zvýšení zabezpečení. Zde odpadá většinou problém z blokováním skupiny uživatelů, ale zas by měla přibýt automatická notifikace blokování.
Negativní důsledy blokování IP
Blokováním IP uzavřeme k vůli chování jednoho uživatel (případně napadeného počítače) přístup více uživatelům jsoucí přes jednu veřejnou IP adresu (např. celé firmě).Nespatřuji v tom nic špatného, za rozesílání spamu se dostanete velice rychle na seznamy spamerů (blacklisty) a také jste blokováni a zodpovědnost nese ten kdo zodpovídá za příčinu.
Je naprosto jasné, že tím Vám kdokoliv skrývající se za stejnou adresou odepře přístup na danou službu - co se dá dělat :(.
Pokud blokujeme na základě periodického vyhodnocování logu a děláme to jednoduše, jako níže uvedený skript, tak se nám může stát, že se chceme opakovaně přihlásit a opakovaně zadíme třeba špatné heslo, ale na konec se přihlásíme a po 10sec jsem odříznuti, ikdyž jsme se již příhlásily.
Je to proto, že nastal interval vyhodnocení logů a naše neuspěšné předchozí přihlášení naplnily podmínku k blokaci.
Jak to funguje na firewall-u (iptables)
Pokud používáme standardní firewall „iptables“, tak to můžeme udělat takto:Příprava
- Připravíme si řetěz
iptables -N mujRetez
- Vložíme do řetězu konečné návratové pravidlo
iptables -A mujRetez -j RETURN"
- Vložíme tento řetěz pravidel jako 1. pravidlo
-I INPUT -p tcp -j mujRetez
Pozn: iptables funguje tak, že první vyhovující pravidlo se uplatní a konce, takže pokud by jsme to dali na konec a někde před tím je vloženo například „ssh povoleno“, tak by nám naše pravidla byly n NIC.
Blokování
- Blokovat s odpovědí „zamítnuto“ ip:port (protocol tcp)
iptables -I mujRetez 1 -s %ip% -p tcp --dport %port% -j REJECT
- Nebo blokovat se zahozením „bez odpovědi“ ip:port (protocol tcp)
iptables -I mujRetez 1 -s %ip% -p tcp --dport %port% -j DROP
REJECT – má výšší režii – musí odpovědět.
DROP – je neslušné, ale nezatěžuje systém.
Níže uvedený script je nastaven tak, že při prvním blokaci použije REJECT a při opakované DROP, což je již slušné a náš server neni internetový nezdvořák :)
Pozn: Pravidla nejsou nikde trvale uložena a při restartování firewallu nám zmízí, proto je nutné kontrolovat při blokaci existenci našeho řetězce. Lze to zkontrolovat například příkazem:
iptables -n -L INPUT | grep -q mujRetezpokud chceme vidět výstup (ne jen kontrolovat návratový kód) odstraníme '-q'.
Odblokování
Musíme provést stejnou defincí jako blokování, tudíž musíme rozlišit:- Odblokování REJECT:
iptables -D mujRetez -s %ip% -p tcp --dport %port% -j REJECT"
- Odblokování DROP:
iptables -D mujRetez -s %ip% -p tcp --dport %port% -j DROP"
Úklid
- Odstranění vstupního bodu pravidel
iptables -D INPUT -p $imblk_protocol -j mujRetez
- Vymazání všech pravidel v řetězci
iptables -F mujRetez
- Odstranění řetězce
iptables -X mujRetez
Řešení pomocí PHP scriptu
Uváděný skript je hóóódně zjednodušené „něco“ jako fail2ban.Požadavky … ?
- php5
- Trpělivost při nastavení a otestování regular expresion – pokud nevyhovují ukázkové
Instalace … ?
Ke stažení je zde zip soubor s aktuální verzí.Případně starší verze zde tar.gz soubor (nedoporučuji).
- Rozbalit a vložit (na rota, či přes sudo) např. do /usr/local/bin/
- Ukázkový konfigurační soubor zkopírovat do místa
cp /imegabin/imegaipblock/imegaipblock.conf.php.example /etc/imegaipblock/imegaipblock.conf.php
- Změnit oprávnění na spouštěcích scriptech
chmod 744 /usr/local/bin/imegaipblock /usr/local/bin/imegaipblockwatchdog
- Případně změnit oprávnění na konfigurační soubor
chmod 640 /etc/imegaipblock/imegaipblock.conf
- Nastavit konfigurační soubor
Nastavení k PHP scriptu
Nastavení je plně v souboru /etc/imegaipblock/imegaipblock.conf.php.Základní nastavení:
- $imblk_conf['secureIp'] = Array(); IP adresy které nebudou blokovány, doporučuji vložit minimálně ip serveru a localhost
- $imblk_conf['logAllCmdCommands'] = false; Všechny provedené příkazy se vypisují do logu, doporučuji ve fázi tetování nastavit na .true'.
- $imblk_conf['logEveryStartClear'] = true; Nastavení na 'true' při každám startu promaže log (znovuotevře).
- $imblk_conf['timeToDropAllBlock'] = 93312000; Za jak dlouho se mají vyprázdnit všechna pravidla v sekundách, jedná se o takový vnitřní reload.
- $imblk_conf['frequence'] = 30; Jak často vyhodnocovat logy, v sekundách.
- $imblk_conf['maxBlockItems'] = 10000; Maximální počet blokací.
- $imblk_conf['maxHistoryItems'] = 6000; Maximální počet položek uchovaných v historii.
- $imblk_conf['maxCandidateItems'] = 10000; Maximální počet kandidátů pro blokaci
- $imblk_conf['historyTime'] = 129600; Jak dlouho uchovávat záznamy v historii, v sekundách.
- $imblk_conf['maxBlockTime'] = 86400; Maximální doba blokace, v sekundách.
- $imblk_conf['blockTime'] = 600; Doba blokování po prvním 'útoku'.
- $imblk_conf['repeatBlockTime'] = 600; Připočtená doba blokování po dalším 'útoku'.
- $imblk_conf['repeatBlockHistoryCoef'] = 1.2;Koeficient pro navyšování času uložení ůdaje v historii (optimální 1.2 -1.5 )
- $imblk_conf['repeatBlockTimeCoef'] = 1.2;Koeficient progresivního navyšování doby blokace (optimální 1.1 -2.5 )
- $imblk_conf['foundToBlock'] = 7; Minimální počet záznamů za čas $imblk_conf['foundTime'] způsobí blokaci.
- $imblk_conf['foundTime'] = 600; Čas k předchozímu $imblk_conf['foundToBlock'].
Jak to funguje:
Záznamy z adres 'secureIp' jsou zahozeny.1x za 'frequence' sekund jsou vyhodnoceny záznamy přibyvší do logů (kterých ? viz níže)
Pokud existuje záznam vyhodnocený jako „k blokaci“ je IP:PORT uložen do pole „kandidátů“
Pokud v poli „kandidátů“ přesáhne počet nalezených záznamů 'foundToBlock', je kombinace IP:PORT zablokována na dobu 'blockTime' a záznam je odstraněn z pole „kandidátů“. Záznamy v poli „kandidátů“ jsou uchovávány jen po dobu 'foundTime'.
Po vypršení času blokace je IP:PORT odblokován a současně zařazen do pole „historie“ na dobu 'historyTime'. Pokud již v poli „historie“ záznam existoval je čas 'historyTime' přičten, tudíž záznam v historii figuruje delší dobu.
Při opětovné blokaci (záznam byl nalezen v poli „historie“), je čas zbývající po vyřazení z pole „historie“ podělen „historyTime“ a tento koeficiont násoben 'repeatBlockTime'. Prakticky to znamená, že když si útočník nedá pokoj a furt to zkouší tak je dle výše uvedeného nastavení zablokován na 10min pak na 31min pak na 52min atd. Při první blokaci je vracena odpověď „nechci to, už mi to sem nedávejte“, při dalších již nedopovídáme (hloupý útočník si myslí, že provedl úspěšně DOS útok).
Každých 'timeToDropAllBlock' sekund je vše vyčištěno na straně iptables a všechny blokace uvolněny, historie zústává.
Nastavení vyhodnocování:
Zde je nastavení složitější:- Jedná se o zahnízděné php pole
- Regular expresion je možná nutné naladit
Zde je ukázkové nastavení obsažene ve staženém souboru:
$imblk_prefix = '^.*sshd\[(?<pid>\d+)\]:.*'; $imblk_host = '(?:::f{4,6}:)?(?<host>\S+)'; $imblk_conf['rules'][] = Array('logFile' => '/var/log/auth', 'params' => Array( Array('port' => 22, 'regexp' => Array( '/' . $imblk_prefix . '(?:error: PAM: )?Authentication failure for .* from ' . $imblk_host . '\s*$/', '/' . $imblk_prefix . 'Failed [-\/\w]+ for .* from ' . $imblk_host . '(?: port \d*)?(?: ssh\d*)?$/', '/' . $imblk_prefix . 'ROOT LOGIN REFUSED.* FROM ' . $imblk_host . '\s*$/', '/' . $imblk_prefix . '[iI](?:llegal|nvalid) user .* from ' . $imblk_host . '\s*$/', '/' . $imblk_prefix . 'User \S+ from ' . $imblk_host . ' not allowed because not listed in AllowUsers$/', '/' . $imblk_prefix . 'authentication failure; logname=\S* uid=\S* euid=\S* tty=\S* ruser=\S* rhost=' . $imblk_host . '(?:\s+user=.*)?\s*$/', '/' . $imblk_prefix . 'refused connect from \S+ \(' . $imblk_host . '\)\s*$/', '/' . $imblk_prefix . 'Address ' . $imblk_host . ' .* POSSIBLE BREAK-IN ATTEMPT\s*$/' ) ) /*pureftpd on port 21*/ ,Array('port' => 21,//ftp 'regexp' => Array( '/^.*pure-ftpd: \(\?\@'.$imblk_host.'\).* \[WARNING\] Authentication failed for user.*$/' ) ) /*https cutom messages on 443 port*/ ,Array('port' => 443,//https 'regexp' => Array( '/^.*pureftpdadmin: Failed login to webserver, port:.*from-ip: \['.$imblk_host.'\], user:.*$/' ) ) ) ); $imblk_conf['rules'][] = Array('logFile' => '/var/log/apache2/error_log',//filename 'params' => Array( Array('port' => 443,//https 'regexp' => Array( '/^\[.*] \[error\] \[client '.$imblk_host.'\] user .*: Password Mismatch$/', '/^\[.*] \[error\] \[client '.$imblk_host.'\] Access denied: .*$/', '/^\[.*] \[error\] \[client '.$imblk_host.'\] user .* not found: .*$/' ) ) ) );Ukázkové nastavení předpokládá záznamy z ssh, pureftpd, a uživatelské zprávy z https (z upraveného pureftpdadmin) do souboru /var/log/auth. Dále se zpracovává soubor /var/log/apache2/error_log kde jsou hlášení od SVN přes https.
Hlášení do logu z php aplikace lze poslat například takto:
exec('logger -p auth.warning -t mojeaplikace "Failed login to webserver, port: [443], from-ip: [xxx.xxx.xxx.xxx], user: [name]"');
Nastavení na vyhdnocování jen na SSH ze souboru /var/log/messages, by vypadalo jen takto:
$imblk_conf['rules'][] = Array('logFile' => '/var/log/messages', 'params' => Array(Array('port' => 22, 'regexp' => Array('/' . $imblk_prefix . '(?:error: PAM: )?Authentication failure for .* from ' . $imblk_host . '\s*$/', '/' . $imblk_prefix . 'Failed [-\/\w]+ for .* from ' . $imblk_host . '(?: port \d*)?(?: ssh\d*)?$/', '/' . $imblk_prefix . 'ROOT LOGIN REFUSED.* FROM ' . $imblk_host . '\s*$/', '/' . $imblk_prefix . '[iI](?:llegal|nvalid) user .* from ' . $imblk_host . '\s*$/', '/' . $imblk_prefix . 'User \S+ from ' . $imblk_host . ' not allowed because not listed in AllowUsers$/', '/' . $imblk_prefix . 'authentication failure; logname=\S* uid=\S* euid=\S* tty=\S* ruser=\S* rhost=' . $imblk_host . '(?:\s+user=.*)?\s*$/', '/' . $imblk_prefix . 'refused connect from \S+ \(' . $imblk_host . '\)\s*$/', '/' . $imblk_prefix . 'Address ' . $imblk_host . ' .* POSSIBLE BREAK-IN ATTEMPT\s*$/' ) ) ) );$imblk_prefix a $imblk_host jsou přednastavené v souboru výše.
Další '$imblk_conf['rules'][] = ' by již nebylo třeba
Z výše uvedeného je patrna konfigurace:
Soubor 'logfile' vyhodnocuj na pravidla 'params', definováno polem, např pro port 22.
Pravidlo se skládá z čísla portu 'port' a pole perl regular expresion 'regexp'. Zde jejich vidět několik. Platí zásada udělat přesné vyhodnocovací regular expresion, aby nám někdo, například místo uživatelského jména, nevložil falsifikovaný záznam, který by vedl k blokaci jiné adresy metoda zvaná „log injection“.
Co po nastavení ?
- Všechna pravidla je nutné odzkoušet.
- Také je třeba nasimulovat utok z jiné IP adresy a zkontrolovat zda sytém adresu zablokuje. Při standardním nastavení je vyhodocování po 30 sekundách, tzn. že je možné provést, někdy výrazně více pokusů o přístup než je nasteveno ve 'foundToBlock' - je třeba čekat na 30 sekundový interval.
Další možnosti
- Spusti lze blokování pomocí příkazu
/usr/local/bin/imegaipblockstart
- Skript NEpříjmá signály, tudíž vypnutí lze provést pomocí příkazu 'ps -ef | grep imeg[a]ipblock.php' a následně 'kill -9 xxxx' :)
- Příkazem,
/usr/local/bin/imegaipblockwatchdog
vložený do crontab (crontab -e) např.40 * * * * /imegabin/imegaipblock/imegaipblockwatchdog > /dev/null
(1× za hodinu), lze hlidat případné spadnutí skriptu (proč by padal ?, – no když ho zestřelíš, tak se aspoň sám nahodí :) ) - Příkazem:
/usr/bin/php /imegabin/imegaipblock/imegaipblock.php -m start clean
lze vyčistit pravidla 'iptables', za předpokladu, že skript již neběží (v modu start). Tím se firewal uvede do původního stavu - Log se nachází v '/var/log/imegaipblock'
a případný zápisWARNING check command return no zero value. CMD: /usr/sbin/iptables -n -L INPUT | grep -q IMegaIpBlock
znamená jen to, že byl například firewal restartován, nebo byla přenačtena pravidla, pokud nic takového neděláme, neměl by se zápis objevit. Teoreticky se může zápis objevit před první blokací, to pak znamená jen to, že není úplně správné pořadí spouštění jednotlivých procesů a načítaní pravidel iptables. Nicméně ničemu to nevadí „nehas co Tě nepálí“. - Hlášeni po staru o neexistenci IMegaIpBlock také není na závadu…
Zdroje informací:
- man php
- man grep
- man iptables
- man crontab
- man logger
- fail2ban
- php.net
- Wikipedia Cron
- Wikipedia vi editor - česky
- Bash manual