Janoszen

Low level debugolás, 2. rész: hálózati eszközök

Low level debugolás, 2. rész: hálózati eszközök

A sorozat első részében megnéztük, hogy hogyan lehet egy folyamat rendszerhívásait nyomon követni. Sokszor ez azonban körülményes, ha csak a hálózati forgalomra vagyunk kíváncsiak. Ilyenkor jól jön, ha néhány hasznos eszközt megismerünk.

Amiről szó lesz, nem újdonság. A „Hogyan működik az Internet?” sorozatunk első és második részében már volt szó hálózati monitorozó eszközökről, de ezúttal egy kicsit mélyebben megnézzük a témát.

tcpdump

A tcpdump eszköz ugyan fapados, de egyetlen Linux/UNIX fejlesztő eszköztárából sem hiányozhat. Nézzünk meg tehát – a teljesség igénye nélkül – néhány példát a használatára. A konzolos eszközökhöz híven részletes leírást a tcpdump manpage-en találsz, amit a man tcpdump paranccsal tekinthetsz meg.

A legegyszerűbb az az üzemmód, amikor az összes interface-en kíváncsiak vagyunk az összes hálózati forgalomra. Ezt a következőképpen érhetjük el:

1
tcpdump -i any

Ha ennek hatására elkezdenek a képernyőn szaladni a betűk, nem kell kétségbe esni, a Ctrl+C megnyomásával befejezhetjük a program futását. Nézzük, hogy mit is jelentenek a betűsorok:

1
22:37:52.724726 IP wordpress.org.https > obs-zyl-smallwebs01.opsbears.com.42924: Flags [P.], seq 2301339106:2301339157, ack 3205437489, win 59, options [nop,nop,TS val 2462421481 ecr 2506631540], length 51

Ebben a példában az látszik, hogy itt egyetlen TCP csomag érkezett a wordpress.org-ról az én szerveremre, méghozzá a P jelzőbittel. A többi paraméter pedig az adott TCP kapcsolat különböző adatait adja meg. A TCP-ről egy későbbi cikkben lesz szó, de egyelőre elégedjünk meg annyival, hogy a különböző jelzőbitek a kapcsolat felépítéséhez, fenntartásához és lebontásához szükségesek.

Ez eddig szép és jó, látjuk a ki-bemenő IP csomagokat, de jó lenne bennük szűrni is. Szerencsére ennek igen egyszerű a nyelvezete, nézzük a következő példát:

1
tcpdump -i any port not 22 and host not wordpress.org

Ezzel kiszűrjük a 22-es porton közlekedő csomagokat (SSH protokoll), illetve a wordpress.org-ot. Természetesen ennél jóval bonyolultabb kifejezésekre is mód van, amiről a man pcap-filter parancs tájékoztat.

A különböző szűrő feltételeken kívül a tcpdumpnak vannak egyéb parancssori kapcsolói is, amikkel a működését befolyásolhatjuk. Nézzünk néhány fontosabbat:

| | `-A` | | Kiírja a csomag tartalmának egy részét a csomag adataival együtt. Ez különösen hasznos, ha webkiszolgálást akarunk elemezni. | | |---|---------------|---|----------------------------------------------------------------------------------------------------------------------------------------|---| | | `-c` | | A megadott számú elkapott csomag után kilép. | | | | `-C` | | Fájlba íráskor korlátozza a file méretét MiB-ben. Ha a fájl az adott méretnél nagyobb, új fájlt nyit és a nevéhez hozzáfűz egy számot. (Lásd még: `-w`) | | | | `-e` | | Kiírja a kapcsolati szintű fejléceket (pl. Ethernet) minden sorhoz. | | | | `-f` | | Kikapcsolja az IP címek barátságos DNS nevekké való feloldását távoli címekre. (Lásd még: `-n`) | | | | `-F` | | A parancssor helyett a megadott fájlból olvassa a filter kifejezéseket. | | | | `-G` | | A megadott számú másodpercenként új fájlt nyit a fájlba íráskor. (Lásd még: `-w`) | | | | `-i` | | Kizárólag a megadott hálózati csatolón figyeli a csomagokat. Alapértelmezetten az első csatolót választja, az *any* kulcsszóval az összes csatolón figyel. | | | | `-K` | | Kikapcsolja a TCP, UDP, stb. ellenörzőszámok ellenörzését. | | | | `-l` | | Átkapcsolja a tcpdump kimenetét olyan üzemmódba, hogy azt további programok használni tudják. (pipe) | | | | `-L` | | Kiírja az adott hálózati csatolón támogatott kapcsolati szintű protokollokat. (pl. Ethernet, DOCSIS, stb.) | | | | `-n` | | Kikapcsolja az IP címek feloldását hostnévvé. | | | | `-p` | | Nem kapcsolja át a hálózati csatolót un. promisc módba. (Ez a mód szükséges a nem az adott gépnek címzett csomagok elkapásához.) Ez akkor hasznos, ha már egy másik program átkapcsolta. | | | | `-s` | | A megadott számú byte-ot rögzíti. Alapértelmezetten ez a szám 65535 byte. | | | | `-v
</br>-vv
</br>-vvv`
| | A tcpdump beszédességét állítja. | | | | `-w` | | A megadott fájlba írja a csomagokat. Ez hasznos, ha később pl. Wiresharkkal szeretnénk elemezni az adatfolyamot. | |

tcpflow

A tcpdump paraméterezése bevallottan nem éppen triviális. Ha egy egyszerű eszközre vágyunk pl. webes forgalom megjelenítésére, akkor a tcpflow nevű program éppen megfelelő lehet. Ez ugyanis csak a csomagok tartalmát írja ki, a küldő és a fogadó IP címmel együtt. A filterszabályai pontosan azonosak a tcpdumppal, de az egyéb paraméterezése sokkal egyszerűbb:

1
tcpflow -i any -c

Fontos! A -c kapcsolót semmiképp se hagyjuk le, különben a képernyő helyett megannyi file-ba íródik a kimenet.

Wireshark

Természetesen a csinos felhasználói felületek barátai sem maradnak hálózati monitorozó eszköz nélkül. A Wireshark MacOS X kivételével minden aktuális operációs rendszeren kiválóan működik, és meglehetősen mély analízist tesz lehetővé az elkapott csomagokon.

wireshark

Ha esetleg egy szerveren tcpdumppal rögzítettünk csomagokat, azokat a Wireshark képes betölteni és megjeleníteni.

mitmproxy

Időnként nem elegendő passzívan figyelni, hanem közbe kell ékelődni a megfelelő információ megszerzéséhez. Ez különösen akkor igaz, ha egy olyan alkalmazást akarunk debugolni, aminek nem csak a forráskódja nem érhető el, de titkosított csatornán (pl. HTTPS-en) kommunikál. Erre való a mitmproxy. Ez az egyszerű kis alkalmazás a gépünkön levő tűzfal segítségével a célszerver helyett fogadja a HTTP vagy HTTPS kéréseket, rögzíti őket, majd a célszerverről lekéri a kívánt oldalt.

A szoftver beállítása koránt sem triviális, éppen ezért a dokumentációt érdemes alaposan szemügyre venni. A különböző üzemmódjai abban különböznek, hogy a debugolni kívánt szoftverben lehet-e proxy-t beállítani, vagy sem. Az előbbi beállítása viszonylag egyszerű, az utóbbinál viszont némi tűzfal konfigurálás elébe nézünk, mivel a szoftver forgalmát át kell irányítanunk a mitmproxy-hoz. Szerencsére ehhez a mitmproxy fejlesztői kiváló segítséget nyújtanak.

Ezen felül ha HTTPS oldalakat is szeretnénk kiszolgálni ezen keresztül, akkor a mitmproxy SSL certificate-jét be kell töltenünk a szerelőpadon heverő szoftver alatti operációs rendszerbe.

Figyelem!
A debugolás végeztével mindenképpen távolítsuk el a mitmproxy CA-t az operációs rendszerből, különben az adott gép sebezhető lesz!

fiddler

Megint csak a csinos felhasználói felületek kedvelőihez szólunk ezzel a szoftverrel. A Fiddler hasonló a mitmproxy-hoz, de többé-kevésbé barátságos felülettel rendelkezik. Az egyetlen hibája, hogy kizárólag Windowson működik. További szomorító tényező, hogy a szoftver gyártója kötelezően kér egy e-mail címet a letöltéshez.

fiddler

Gyakorlati példa avagy miért fontos ez?

Pont miután megírtam a cikk első részét, futottunk bele egy jellemző példába. Az egyik általam is karbantartott alkalmazás logjában feltűnt egy hiba, amivel nem tudtunk mit kezdeni. Az egyik backend API-t használó JSON encode folyamat hibát dobott, nem tudott kódolni egy UTF-8 karaktert. Ráadásul pár másodpercenként. Az viszonylag hamar kiderült, hogy itt valaki megpróbál jelszavakat brute force-olni, az viszont nem derült ki, hogy mi okozza a hibát.

Maga az alkalmazás nem adott elegendő információt, és - mivel nagy forgalmat bonyolító szolgáltatásról volt szó - az éles rendszeren való debugolást is kizártuk. Ennek hiányában nem volt más lehetőségünk, kénytelenek voltunk az ebben, és az előző cikkben leírtakat használni a probléma felderítésére. Előszőr a strace-t használtuk, hogy felderítsük, mi is történik:

1
POOL="php-fpm-pool-neve";strace -f -s 999 $(ps auwfx | grep php | grep "pool $POOL" | awk ' { print $2 } ' | xargs -i echo -n '-p {} ')

Ezzel természetesen hihetetlenül sok adatot kaptunk, de a lényeg benne volt. A hibaüzenetre keresve megtaláltuk, hogy melyik processz futtatta a kódot. Miután a processz ID-t (PID) tudtuk, már egyszerű volt a keresés. Láttuk, hogy tényleg fura karakterek jönnek be. Sajnos a FastCGI protokollból nem lettünk okosabbak, de tudtuk, hogy valami fura.

Nem volt más hátra, a hálózati forgalmat kellett megnéznünk. Szerencsére a reverse proxy-tól már titkosítatlanul jött a forgalom, tehát bele tudtunk nézni. (Ez egy meglehetősen gyakori megoldás nagyobb terhelésnél, hogy a titkosítást egy, a tényleges webszerver előtt levő reverse proxy végződteti.) Hogy tudjunk később szűrni, beleírtuk a teljes forgalmat egy file-ba:

1
tcpdump -i any -n -w interesting-bug.pcap port 80

Miután megláttuk a hibát a logban, leállítottuk a capture-t és megnéztük, hogy mi is volt benne:

1
tcpdump -r interesting-bug.pcap -A

Ebben már könnyű volt keresni, és meggyőződtünk róla, hogy valóban benne van a hibát okozó lekérés. Ezek után nem volt más hátra, betöltöttük Wiresharkba a file-t, és a következő szűrőt alkalmaztuk:

1
http.request.uri=="/login"

Ezzel szépen leszűrtük az összes csomagot kizárólag a megfelelő címre menő lekérdezésekre. Végül egy jobb kattintás, Follow TCP Stream megadta a teljes lekérdezést, amit ezután le tudtunk menteni file-ba.

Összegzés

Elméletben természetesen tökéletes alkalmazást írunk, felkészülünk minden helyzetre, és soha nincs olyan helyzet, ahol az alkalmazásunk nem ad elegendő információt. A gyakorlatban viszont sajnos ez sokszor nincs így. Még ha tökéletes is a saját kódunk, nem biztos, hogy az alatta futó platformról ugyanezt el lehet mondani.

Éppen ezért érdemes begyakorolni ezen alacsony szintű elemző eszközök használatát. Amikor élesben használni kell őket, már ujjgyakorlat szintjén lehessen kezelni a problémás eseteket.

comments powered by Disqus