Sziasztok,
Én magam is boldog tulajdonosa vagyok egy Asus WL-500g típusú routernek (amin természetesen Oleg firmware fut), és sokszor menedzselem távolról ssh-n keresztül. Sajnos a routerre nagy számban próbálkoznak betörni ssh-n keresztül (tudom, tudom a portáthelyezés sok mindent megoldana de én már csak ilyen mazochista vagyok) és szerettem volna ezeket betörési kísérletek jobban megfigyelni, elemezni. Eme apropóból született egy kis scriptgyűjtemény, ami képes elvégezni ezt a feladatot, igazodva a router által biztosított szerény körülményekhez. Mindezen scripteket csak hobbiból írtam, kezdetben csak saját magam számára és később jutott eszembe, hogy megosztom másokkal is, hátha hasznosnak bizonyul. Ebből következőleg ez nem egy professzionális alkalmazás, így lehetnek benne hibák, és a tesztelése is csak egy szűk platformon történt meg. A scriptek szabadon módosíthatóak és mindenki saját igénye (és rendszere) szerint átalakíthatja őket, mindehhez nem szükséges más mint némi python ismeret és elszántság.
Egy kis ismertető
Némi gondolkozás után úgy döntöttem, hogy a scripteket Python-ban írom meg, mivel ez szinte minden ilyen típusú firmwaren elérhető (OpenWRT, Oleg stb.), így nem kell vesződni fordítással és egyéb nyalánkságokkal.
Fontos tudnivaló, hogy a scriptek használnak olyan eszközöket, melyeknek a megértése némi utánjárást igényel (például iptables) és az egyéb szükséges szoftverek használata sem feltétlen triviális mezei halandó számára. Így hát a használatát inkább csak a barkácsolást szerető és a linuxhoz valamennyi értő emberkéknek javasolt (bár ha valaki már nem a gyári firmwaret használja a routerén, akkor valószínűleg kedveli az efféle elfoglaltságokat).
Na de lássuk is inkább, hogy mire képes ez a scriptgyűjtemény (ha már ilyen hangzatos nevet adtam neki
):
- Elemzi az ssh daemon logjait, amit stílszerűen syslog-ng naplóz (hogy miért pont syslog-ng kicsit később)
- Kiszűri a hibás bejelentkezési próbálkozásokat, amiket egy sqlite adatbázisba gyűjt (későbbi elemzés céljából)
- Kiegészítő pluginek révén képes automatikusan kitiltani a behatolók ip címeit (iptables segítségével)
- HTML oldalt generálni az adatbázisból
A script használatához szükséges néhány kiegészítő szoftvert is feltenni a routerünkre:
- OpenSSH (ez fontos, mert a script az OpenSSH szerver által generált logüzenetekre ugrik, a gyári Dropbear ssh szerverrel nem teszteltem, bár az iss.py-ban átírhatók az illeszkedés feltételei)
- Python (>=2.5)
- syslog-ng (ez egy igen hasznos és sokat tudó naplózó program, ami több olyan funkcióval is rendelkezik, amit én aktívan használok és a logok elemzését az általa naplózott logokon teszteltem. Ami fontos, hogy a script a logokban az összetartozó OpenSSH logüzeneteket az “sshd[PID]” forma alapján keresi, tehát ha nem syslog-ng-vel hanem a gyári sysloggal naplózunk akkor ilyen formában kell naplóznia ezeket az üzeneteket.)
Illetve néhány opcionális program (ezek nem kötelezőek, de a script futásához jól jöhetnek és jó eséllyel már más miatt feltettük a routerünkre):
Ezen programok többsége viszonylag könnyedén feltehető a routerünkre így (lásd még a fenti tutoriálokat illetve a következő fejezetet):
ipkg install openssh python2.6 syslog-ng cron sqlite3
ISS telepítése
Ezután töltsük le a tar.gz fájlt ami tartalmazza a scripteket.
Hozzunk létre egy tetszőleges könyvtárat a routeren és csomagoljuk ki ide:
mkdir /opt/usr/local
tar xvzf intrusion-scanner-system-1.0.tar.gz -C /opt/usr/local
Ezután a scriptek a /opt/usr/local/intrusion-scanner-system könyvtárban találhatóak meg. Ami nagyon fontos, hogy a kicsomagolt python scriptekben írjuk át a python bináris elérési útvonalát ha ez szükséges (itt a #!/opt/bin/python2.6 típusú kezdősorokra gondolok, ha más a bináris neve vagy máshol van az elérési útvonala).
Ha nem találjuk a binárist, azt a következőképp tudjuk megkeresni: “find / -name python” (vagy a which parancs segítségével ha az telepítve van a routerre, akkor “which python“)
A run.sh fájlban szintén írjuk át az elérési útvonalakat ha ez szükséges. Ezek után már csak egy apróság szükséges (de ez nem kötelező), állítsuk be a syslog-ng-nek hogy a létrehozott logfájlok dátumpecsételve legyenek (így megspóroljuk a cron-os logmozgatást). Erre azért van szükség, mert az elemző script mindig a teljes logfájlra fut le, így nem árt ha naponként rotáljuk a logfájlokat és mindig a legaktuálisabbra futtatjuk le (elkerülve így a duplikált működést, és a túl sok erőforrás lekötését a túl nagy logfájl elemzésére). Ehhez a következő konfigurációs változás szükséges a syslog-ng.conf fájlban (ami nálam a /opt/etc/syslog-ng/syslog-ng.conf-ban található):
# a source sor általában alapból is szerepel benne
source src { pipe(”/proc/kmsg”);unix-stream(”/dev/log”); internal(); };
#a /opt/var/log alá dátumpecsételt logok keletkeznek
destination messages { file(”/opt/var/log/${YEAR}-${MONTH}-${DAY}-messages”); };
log { source(src); destination(messages); };
A scriptekhez mellékeltem még egy run.sh nevü shell scriptet is, ami gyakorlatilag csak annyit csinál, hogy sorrendben lefuttatja az egyes scripteket. Ennek futását célszerű cronnal időzíteni (ezért kell a cron nekünk, de ez szintén nem szükséges), amihez a következő kiegészítést kell tenni a crontab fájlban (vagy a cron.d könyvtárban egy tetszőleges nevü fájlban):
15 0 * * * root /opt/usr/local/intrusion-scanner-system/run.sh >> /opt/var/log/iss-message 2>&1
Ez szimplán csak annyit csinál, hogy minden nap 00:15-kor lefuttatja a run.sh-t, a kimenetét pedig beleirányítja a megadott fájlba (ez akkor jön jól ha valamiért hiba történik a futása során).
Az ISS használata
Mindegyik python scripthez tartozik súgó, ami a –help opcióval csalogatható elő. A mellékelt README fájlban pedig részletesen ki van fejtve hogy melyik script mit csinál pontosan.

Help megtekintése
Én most csak egy gyakorlati példán keresztül szeretném bemutatni a használatát. Tételezzük fel, hogy már van néhány próbálkozási kísérlet a log fájlban. Ekkor a teendőnk:
./iss.py -d test.db -m all 2009-03-10-messages
Ebben az esetben annyi fog történni, hogy a script feldolgozza a megadott messages fájl tartalmát, kigyűjti mind a próbálkozók ip címét, mind a próbált login neveket, és az adatokat a test.db nevű sqlite3 adatbázisba írja. Az adatbázis tartalma könnyen megtekinthető:
[pzolee@WL-001FC68CFF43 intrusion-scanner-system]$ sqlite3 test.db
SQLite version 3.6.11
Enter “.help” for instructions
Enter SQL statements terminated with a “;”
sqlite> select * from addresses;
1|2009-03-11|189.19.206.13|50
2|2009-03-11|62.68.63.14|15
3|2009-03-11|140.136.150.114|6
sqlite>
sqlite> select * from names;
1|2009-03-11|root|61
2|2009-03-11|oracle|4
3|2009-03-11|postgres|2
4|2009-03-11|test|1
5|2009-03-11|nobody|1
6|2009-03-11|patrick|2
Két tábla fog létrejönni (ezt a .tables paranccsal tudjuk lekérdezni, illetve a .schema mondja meg a táblák oszlopait), az egyik az ip címeket tartalmazza, a másik a neveket. Az első oszlop egy azonosító, a második mindig a feldolgozás dátumát tartalmazza (ez fontos, nem a logba kerülés időpontját, hanem a script lefutásának idejét, ezért sem árt naponta futtatni), a harmadik oszlop az ip címet vagy login nevet, és végül a negyedik oszlop az előfordulások számát. SQL-t ismerők számára így tetszőleges lekérdezések összeállíthatók, sőt az adatbázis könnyedén átmásolható másik gépre is (lévén csak 1 db fájl) és ott is elemezhető. SQL-hez kevésbé értőknek néhány példa:
select sum(db) from addresses; #megmondja az összes próbálkozási kísérletek számát
select count(*) from names; #megszámolja az összes bejegyzést (bár ez az id-ból is kitalálható)
select * from addresses order by db asc; # növekvő sorrendbe teszi előfordulási gyakoriság szerint
Ha szeretnénk HTML formában is feldolgozni, akkor futtasuk le az iss-genhtml.py plugint. Ez az adatbázisból egyszerű HTML táblázatos formában készíti el a fenti listát:
./iss-genhtml.py -d test.db addresses.html names.html
Fontos tudni, hogy mindig az első HTML fájlba fognak kerülni az ip címek és a másodikba a login nevek (nem véletlenül neveztem el őket így).

IP címek HTML formában

Felhasználói nevek HTML formában
És végezetül, a második plugin, ami felolvassa az adatbázist, és a meghatározott paraméter alapján (minimális előfordulás szám) iptables segítségével kitiltja a megadott ip-ket. Csak hozzáértőknek javasolt használni:
./iss-iptables.py -d test.db -m gen -l 10
a “-m gen” opció azt mondja meg hogy le szeretnénk generálni az iptables szabályokat (-m clean pedig törli a meglévőket, de csak a script által létrehozottakat), a “-l 10″ hogy csak azokra az ip címekre hozzon tiltó szabályt, amiknek az előfordulása meghaladja a 10-et (egy feldolgozásra vonatkoztatva).
A lefutása után pl. ilyen iptables szabályokat kaphatunk:
[pzolee@WL-001FC68CFF43 intrusion-scanner-system]$ ./iss-iptables.py -d test.db -m gen -l 1
[pzolee@WL-001FC68CFF43 intrusion-scanner-system]$ iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP tcp – 140.136.150.114 anywhere tcp dpt:ssh
DROP tcp – 62.68.63.14 anywhere tcp dpt:ssh
DROP tcp – mail.amboretto.com.br anywhere tcp dpt:ssh
A “-m clean”-re pedig kitörli ezeket a DROP sorokat (de csak ezeket).
Vigyázzunk arra, hogy sok IP cím esetén nagyon sok szabály keletkezhet, így ilyenkor egyszerűbb az iptables alapértelmezett szabályát DROP-ra állítani és inkább csak a nekünk szükséges címeket engedélyezni és kihagyni a plugin használatát (illetve az én saját tapasztalataim alapján ritkán próbálkoznák ugyanarról az IP cimről több alkalommal, inkább csak egy alkalommal de akkor sokat).
SSH logüzenetekről részletesebben
Utolsó fejezetként már csak egy kis ismertetőt tartanék az OpenSSH által generált logokról, amik hibás bejelentkezés során keletkeznek. Ezen logok általában így néznek ki:
Feb 12 08:29:10 src@WL-001FC68CFF43 /opt/sbin/sshd[514]: Invalid user test from 79.173.101.136
Feb 12 08:29:10 src@WL-001FC68CFF43 /opt/sbin/sshd[514]: input_userauth_request: invalid user test
Feb 12 08:29:10 src@WL-001FC68CFF43 /opt/sbin/sshd[514]: Failed password for invalid user test from 79.173.101.136 port 58880 ssh2
Feb 12 08:29:10 src@WL-001FC68CFF43 /opt/sbin/sshd[514]: Received disconnect from 79.173.101.136: 11: Bye Bye
Ez a 4 sor összetartozik, mivel a PID (514) megegyezik, tehát ugyanahhoz a sessionhoz tartoznak. Az ssh szerver sorban ellenőrzi az egyes authentikációs metódusokat, mint az ebben az esetben is látható. A fenti példában egy nem létező felhasználói névvel jött a próbálkozás, amihez értelemszerűen a jelszó sem érvényes. A logok elemzése abból a szempontból problémás, hogy ez a 4 sornyi üzenet egy próbálkozást jelentett és nem négyet. Természetesen ez lehet ennél bonyolultabb is, mivel az ssh általában támogatja a kulcsos és jelszavas authentikációt is, így ezek bármelyike lehet hibás, miközben egy későbbi metódus pedig sikeresen és persze ezek minden kombinációja.
Feb 13 12:53:51 src@WL-001FC68CFF43 /opt/sbin/sshd[731]: Failed keyboard-interactive for test from 192.168.20.1 port 53334 ssh2
Feb 13 12:53:59 src@WL-001FC68CFF43 /opt/sbin/sshd[731]: Accepted password for test from 192.168.20.1 port 53334 ssh2
Ez a példa pedig azt mutatja hogy túloldalnak nem sikerült az első authentikáció, de végül a jelszavas igen.
Nos, remélem sikerült érthetően bemutatnom a scriptgyűjtemény használatát és hasznos eszköz lesz mindenki számára aki használja. Természetesen az adatbázis használatára tetszőleges kiegészítő készíthető, például php modul dinamikusan generált html oldalhoz vagy esetleg muninhoz kiegészítő. A felhasználó barátság sajnos nem igazán lett még jól megvalósítva, mivel elég kevés időm volt rá, és nem is igazán szerettem volna belemélyedni a html és php rejtelmeibe.
PZolee
Read original blog post