Rootkity -------- - hacker: root -> instalace rootkitu - obvykle balik: sebemaskovaci mechanismus + doprovodne utilitky (backdoor, FTP server na distribuci warezu, editor systemovych logu, ...) - deleni dle zpusobu maskovani: trojani, LKM, /dev/(k)mem, napadajici CMOS (pres ACPI / flash BIOSu - zde ignorovano) Trojsti kone ------------ - binarky/knihovny, ktere maskuji pritomnost rootkitu a jsou jimi nahrazeny puvodni systemove binarky - ls, dd, cat, ps, netstat, ifconfig, ... - obvykle originalni zdrojaky s dodatecnymi upravami - obvykle kompilovane na hostitelskem stroji - detekce I: hledani specifickych podretezcu v binarkach - detekce II: kontrola kritickych systemovych souboru proti hashum v zaloze - zastupne binarky mohou mit stejne CRC/MD5 pro zmateni nepritele - doporucena detekce po rebootu z cisteho zdroje (napr. plny funkcni Linux na bootovatelnem DVD) - problem detektoru: hledaji znaky specificke pro defaultni nastaveni znamych rootkitu, ale zmenit defaultni nastaveni neni pro hackera problem (zmena umisteni souboru rootkitu na FS, zmena tajnych hesel nalezitelnych v otevrene podobe v binarkach, ...) - hands-on: 10.0.0.1:/tmp/coreutils-7.1.tar.gz, uprava ls.c v coreutils/src: #include // Na zac. tela fce file_ignored: if (!(strncmp(name,"HAXOR",5))) return true; - zkusit na souborech HAX, HAXO, HAXOR, HAXORR, porovnat se systemovym ls LKM (Loadable Kernel Modules) ----------------------------- - LKM: binarni modul zaveditelny za behu do kernelu, pridava funkcionalitu, bezi v kernel space => pristup k systemovym strukturam - nemusi byt podporovany (rozhodnuti admina), ale vetsinou jsou - zavedene moduly: lsmod - info o zavedenych modulech: v linearnim obousmernem seznamu - viz "struct module" v /usr/src/linux/include/linux/module.h - VFS (Virtual File System): systemova vrstva mezi drivery jednotlivych druhu FS (ext3, FAT, ...) a realnymi operacemi nad FS, ktere maji byt nezavisle na FS (obecne cteni ze souboru, obecny zapis, ...) - kazdemu souboru/adresari lze nadefinovat, jak se z nej cte/zapisuje/syncuje/... - vsechny mozne operace viz "struct file_operations" v /usr/src/linux/include/linux/fs.h - /proc: virtualni FS, kterym kernel exportuje systemove info a umoznuje omezenou konfiguraci za behu - mj. obs. seznam procesu - adresare /proc/, kde PID je unikatni ciselne ID procesu bezicich v systemu (pekny vypis napr. "ps axf") - osetrenim operace readdir (vraci obsah adresare) nad /proc ve VFS lze tedy skryvat procesy - puvodni readdir pro /proc se nahradi vlastnim, ktery se rozhodne, zda nekterou polozku(y) nevratit volajici funkci, a tim skryt proces - obejde "ps" a drtivou vetsinu dalsich; procesy by teoreticky vsak stale slo najit primo v pameti jadra (viz dale) - 10.0.0.1:/tmp/module - obs. funkcni modul (silne orezane a lehce upravene zdrojaky rootkitu Adore; kompilace: "make") pro moderni kernel (akt.: 2.6.29), ktery pomoci VFS+/proc skryje proces s danym PID (viz fce adore_proc_filldir) a ukryje svou pritomnost svym odstranenim ze seznamu zavedenych modulu (viz fce init_module) - detekce LKM rootkitu: ruzna, dle toho, co se detekuje; napr. hledani skryteho modulu v pameti kernelu (viz dale) - po rebootu systemu muze byt rootkit beze stopy pryc Exkurs: syscally ---------------- - API exportovane kernelem pro obycejne procesy, ktere nemaji mit pristup k privilegovanym operacim (I/O, tvorba/ukoncovani procesu, ...) - seznam s pevnym poradim napr. v /usr/include/asm/unistd_32.h - volani syscallu cislo X: EAX=X -> nastaveni parametru pro syscall -> INT 0x80 - preruseni 0x80 prerusi proces a preda rizeni kernelu, konkretne handleru INT 0x80, ktery podle obsahu EAX preda rizeni handleru pozadovaneho syscallu - adresy handleru syscallu v pameti kernelu jsou akumulovany ve strukture sys_call_table, a to v poradi uvedenem v /usr/include/asm/unistd_32.h - hands-on: main() { asm("mov $1,%eax"); asm("mov $4,%ebx"); asm("int $0x80"); } - po spusteni nic neprovede, ale volajicimu shellu vrati navratovou hodnotu 4 (viz "echo $?") - poradove cislo 1 ma syscall exit() - ultimatni cil rootkitu: nahradit polozky v sys_call_table za ukazatele na vlastni funkce, ktere maskuji pritomnost jinych komponent rootkitu - napr. nahrazeny handler syscallu read() muze zamlcovat obsah vybranych souboru - nahrazeny handler obvykle jen provede kontrolu, zda by normalni beh syscallu neprozradil jine casti rootkitu: pokud ne, necha probehnout puvodni handler; pokud ano, nenecha jej probehnout - syscally jsou jediny zpusob, jak veskere procesy (tedy i pripadne detektory rootkitu) muzou provadet napr. I/O - sycally jsou bottleneck, proto jsou velice atraktivnim cilem /dev/(k)mem rootkity -------------------- - problem: kde je v pameti jadra sys_call_table? (je v kazdem kernelu obecne jinde) - moznost I: soubor System.map - nemusi byt ovsem dostupny - moznost II: obdobna tabulka extrahovana primo z binarky kernelu (vmlinux, nikoli bzImage/vmlinuz), viz "nm vmlinux" - ani binarka kenrelu nemusi byt dostupna - hands-on: overit, ze v pameti kernelu sys_call_table skutecne je: * vzhled pameti kernelu (v little-endian!) - viz "objdump -s vmlinux" * na adrese odpovidajici sys_call_table (levy sloupec) najit adresy handleru jednotlivych syscallu (ostatni sloupce) * overit spravnost adres dle ocekavanych adres symbolu sys_ v System.map - pokud moznosti I+II nelze pouzit, je treba najit sys_call_table v pameti kernelu - jak se k ni dostat? - moznost I: /dev/kmem - virtualni soubor, ktery zpristupnuje pro R/W celou virtualni pamet kernelu; nemusi byt vubec podporovany jadrem - moznost II: /dev/mem - to same, ale fyzicka pamet (treba prekladat virtualni adresy <-> fyz. adresy); rovnez nemusi byt podporovan, ev. v omezene forme (jen prvni 1 MB pameti, ktery potrebuje standardni linuxove graficke rozhrani) - teoreticka moznost III: pres LKM (neoveril jsem, zda je to mozne, ale neznam rootkit, ktery by toto pouzival, takze tam asi nejaky hacek bude) - pokud je dostupna moznost I ci II, lze najit sys_call_table primo v pameti beziciho kernelu - jak? * pomoci x86 instrukce SIDT ziskat adresu IDT (Interrupt Descriptor Table) - vektoru, ktery obsahuje adresy handleru vsech preruseni * v IDT najit adresu handleru INT 0x80 * v tele handleru INT 0x80 najit binarni reprezentaci strojove instrukce "CALL *(,%eax,4)", coz v hexa odpovida "FF1485" * vyse uvedena instrukce je bodem, kdy se handler INT 0x80 odvolava na sys_call_table, instrukce je primo zavisla na obsahu EAX * odkaz na sys_call_table je reprezentovan presne touto instrukci ve vsech kernelech 2.6 minimalne po 2.6.29 - hands-on: "objdump -d vmlinux | grep -2 syscall_call" - disassembly dotycne casti handleru INT 0x80 s viditelnou adresou sys_call_table - porovnat proti ocekavane hodnote v System.map - detekce rootkitu manipulujicich se sys_call_table: velky problem - jadro nemusi zakladni I/O operace provadet soplehlive a po rebootu muze byt cely rootkit pryc - lze napr. pravidelne za behu jadra kontrolovat obsah sys_call_table proti R/O zaloze (ovsem kontrolu provadi nejaky proces, takze ...) - ciste teoreticky lze provest dump (obraz 1:1) pameti kernelu na disk a po rebootu tento soubor zkoumat debuggerem a hledat v byvalem bezicim kernelu anomalie - extremni metoda - admini nemaji na toto vsechno cas, ale nastesti tvurci rootkitu taky nemaji cas na dokonale obrnovani se proti moznym detekcnim pokusum Detekce ------- - good luck! - nepotrebujete LKM? - vypnete podporu LKM nacisto - nepotrebujete /dev/kmem (jakoze asi nepotrebujete) - to same - nepotrebujete /dev/mem - to same, ev. omezte na dolni 1 MB pro grafiku - dokonale zapatchovany system od kernelu az po posledni bezvyznamny programecek, ktery nikdy osobne nespoustite - hodi se mit obraz cisteho systemu (po instalaci) na externim R/O mediu - prubezna kontrola konzistence (ne MD5!) klicovych souboru na disku - i reboot muze (docasne) pomoct; scanovani disku je spolehlivejsi, kdyz je stroj nabootovan z cisteho media - RRD (Rootkit-Resistant Disk) - disk, ktery umozni write az po autentizaci admina fyzickym tokenem - zatim jen prototyp s mnoha chybami