Rootkit

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2020. augusztus 20-án felülvizsgált verziótól ; az ellenőrzések 12 szerkesztést igényelnek .

A Rootkit ( eng.  rootkit , azaz " gyökérkészlet ") olyan szoftvereszközök (például futtatható fájlok, szkriptek, konfigurációs fájlok ) halmaza, amelyek a következőket biztosítják:

A Rootkit kifejezés történelmileg a UNIX világból származik , és ez a kifejezés egy sor segédprogramra vagy egy speciális kernelmodulra utal, amelyet a támadó a szuperfelhasználói jogok megszerzése után azonnal feltört számítógépre telepít. Ez a készlet általában számos segédprogramot tartalmaz a rendszerbe való behatolás nyomainak lefedésére, láthatatlanná téve a szippantókat , szkennereket, kulcsnaplókat , trójaiakat , leváltva a fő UNIX segédprogramokat (nem nukleáris rootkit esetén). A Rootkit lehetővé teszi a támadók számára, hogy megvegyék a lábukat egy feltört rendszerben, és elrejtsék tevékenységeik nyomait azáltal, hogy elrejtik a fájlokat, folyamatokat és a rootkit jelenlétét a rendszerben.

A rootkit többféleképpen telepíthető a rendszerbe: egy exploit segítségével , shell hozzáférés megszerzése után (ebben az esetben egy olyan eszközzel, mint a wget vagy az eredeti FTP kliens használható a rootkite letöltésére egy távoli eszközről), a szoftvertermék forráskódjában vagy erőforrásaiban.

A rootkitek osztályozása

A megvalósítás alapvető módszerei

Microsoft Windows rendszeren

Különféle rootkit technológiák léteznek, a legelterjedtebbek a hívástábla rögzítése (IAT, IDT, SSDT, GDT ), a funkcióelfogás (például a kezdeti bájtok módosítása), a rendszerobjektumok közvetlen módosítása (DKOM), az illesztőprogramok használatának módszerei.

Hívástáblázatok rögzítése

A hívástábla egy tömb, amelyben minden elem a megfelelő eljárás címét tárolja. Ilyen táblák mind kernel módban (IDT, CPU MSR-ek, GDT, SSDT, IRP diszpécsertábla), mind felhasználói módban (IAT) léteznek.

Az Import Address Table (IAT) a fő felhasználói módú modulhívási táblázat. A legtöbb végrehajtható fájl egy vagy több beépített IAT-tal rendelkezik, amelyek a DLL-ből importált könyvtári rutinok címeit tartalmazzák [2] .

Egy többprocesszoros gépen több hívási tábla is létezik (pl. IDT, GDT , MSR ). Mivel minden processzornak saját rendszerregisztere van (különösen a GDTR - a globális leíró tábla regisztere (GDT), az IDTR - a megszakítási tábla leíró regisztere (IDT) és az IA32_SYSENTER_EIP - tartalmazza a kernel módú belépési pont (MSR) virtuális címét). , saját rendszerstruktúrái is vannak [3] .

A hívási tábla egy bejegyzésének megváltoztatásakor a programok végrehajtása vezérlésre kerül, és szükség esetén átirányításra kerül a szükséges funkciókhoz. Az elfogott eljárás [4] :

A rögzítés általános ötlete a következő:

  • Azonosítsa a hívástáblát, szerezze meg a címét
  • Mentse el a meglévő rekordot a táblázatba
  • Cserélje ki a bejegyzést új címre
  • Az eredeti bejegyzés visszaállítása

Ha az elfogási funkció az eredeti eljárás hívását jelenti, akkor a hívás előtt a blokkolás és a figyelés, utána a paraméterszűrés történik.

Az IAT egy hívástábla, amely az alkalmazás fájlstruktúrájában található. Az IAT tárolja az adott DLL által exportált eljárások címét . Minden DLL-nek, amelyhez az alkalmazás a rendszerindításkor hivatkozik, saját IAT-ja van. Az IAT rögzítéséhez a következőket kell tennie:

  • Hozzáférhet a processzor címteréhez
  • Az IAT lokalizálása a processzormemória képében
  • A szükséges IAT módosítása

Az IAT manipulálásához hozzá kell férni annak az alkalmazásnak a címteréhez, amelyhez a tábla tartozik. Az egyik módja egy DLL beillesztése. A DLL-nek egy folyamat címterébe történő beillesztésének módszerei között megadható [5] :

  • Az AppInit_DLL beállításjegyzék értékének módosítása
  • SetWindowsHookEx() API hívás
  • Távoli szálak használata
Elfogás a funkciókód módosításával

A működési elv azon alapul, hogy az elfogott függvények első bájtjait felváltja az elfogó kód. Hangsúlyozni kell, hogy az elfogó telepítésekor az elfogott funkció kódja nem kerül elemzésre: az első N bájt módosul, és nem az első N gépi utasítás. Ennek a ténynek a következménye [6] :

  1. az elfogó kód csak a funkció elején állítható be;
  2. az elfogott funkció minden egyes hívásánál az elfogónak vissza kell állítania a gépi kódját a hívás előtt, és újra le kell fognia a hívás befejezése után.

Rootkit algoritmus:

  1. Az elfogó törzsében egy tömb jön létre, amelybe az elfogott függvények első N bájtja kerül beírásra (általában a módosított kód mérete nem haladja meg a 20 bájtot)
  2. A tömb az elfogott függvények referencia gépi kódjával van kitöltve.
  3. Minden elfogott függvény elején egy kódot írunk, amely átadja a vezérlést az elfogónak.

Az elfogó működési algoritmusa:

  1. A támadó által meghatározott műveletsor.
  2. Az elfogott függvény első N bájtjának helyreállítása.
  3. Az elfogott függvény hívása.
  4. Az elfogott funkció gépi kódjának újramódosítása: az első bájtokban az elfogónak átadó kód felülírása.
  5. Az eredeti függvény eredményeinek elemzése, szükség esetén módosítása.
  6. A ret művelet végrehajtása, a vezérlés visszaadása a függvényt meghívó programnak.

Az elfogáshoz elegendő a függvény első öt bájtját módosítani, amelyek helyére a jmp műveletet írják, átadva a vezérlést a rootkit elfogónak.

Megjegyzendő, hogy az ilyen típusú támadások elleni védelem legegyszerűbb rendszerei ellenőrzik a hívott függvények első bájtját, hogy bennük van-e a jmp gépi műveletkód. Ellenintézkedésként a rootkit fejlesztők technikákat alkalmaznak az elfogó funkció elején írt kód „lefedésére” (például PUSH / RET parancsokkal, több NOP operátor elhelyezésével vagy szemétkóddal, például PUSH AX / POP AX, valamint polimorfizmus elemeivel ).

A függvények első bájtjainak módosításának módszere számos hátránnyal jár, amelyek főként azzal kapcsolatosak, hogy az elfogott függvények gépi kódját vissza kell állítani a hívás előtt, és a hívás után újra le kell fogni. Ezek a műveletek csökkentik a rendszer teljesítményét, és a többszálas alkalmazások összeomlását okozhatják .

DKOM (Direct Kernel Object Manipulation)

A Windows NT család operációs rendszerei szabványos objektummodelleket használnak. A végrehajtási rendszer különféle összetevői egy vagy több típusú objektumot határoznak meg. Mindegyik összetevő kernel módban exportálja a támogatott függvényeket és tulajdonságokat, amelyeket COM-interfésznek neveznek, az ilyen típusú objektumok kezeléséhez. Egyetlen összetevő sem férhet hozzá közvetlenül egy másik összetevő objektumhoz. Tipikus kernel módú objektumok [7] :

  • eszköztípus objektum (az I/O-kezelő által meghatározott privilegizált módú objektumtípus, amely fizikai, logikai vagy virtuális eszközt ábrázol)
  • fájl objektum
  • szimbolikus linkek
  • rendszerleíró kulcsok
  • szálak és folyamatok
  • diszpécser objektum (privilegizált módú objektumtípus osztály, amely a diszpécser és szinkronizálási folyamatok vezérlésére szolgál)

Ez a kialakítás rugalmasságot és hordozhatóságot biztosít, például az operációs rendszer jövőbeli kiadásai tartalmazhatnak hasonló objektumokat definiáló, de teljesen eltérő belső szerkezetű kernelkomponenseket. Ha ezek a komponensek megőrzött nevekkel és paraméterekkel exportálnak függvényeket, a változtatásnak nincs hatása [3] .

A kernelobjektumok közvetlen manipulálása meglehetősen hatékony technológia, amelyet nehéz felfedezni. Ennek azonban számos hátránya van, mint például a metódusok instabilitása, a verziófüggőség, a megvalósítás bonyolultsága az objektumok szerkezetének és tulajdonságainak dokumentált leírásának hiánya miatt. E korlátozások ellenére ez a módszer lehetővé teszi a folyamatok, eszközillesztők, portok elrejtését és a szálak (tehát a folyamatok) jogosultságának növelését.

Az EPROCESS egy folyamat (folyamatobjektum) belső reprezentációjaként szolgáló struktúra. A Windows az EPROCESS struktúrák körkörös, kétszeresen összekapcsolt listáját használja a végrehajtás előrehaladásának nyomon követésére. Az EPROCESS objektumokat összekötő hivatkozásokat az ActiveProcessLink mező tartalmazza, melynek szerkezete LIST_ENTRY [8] :

typedef struct _LIST_ENTRY { struct _LIST_ENTRY * Flink ; struct _LIST_ENTRY * Villogás ; } LIST_ENTRY , * PLIST_ENTRY ;

A legegyszerűbb folyamatrejtő algoritmus:

  1. Mutató lekérése arra a folyamatra, amelyhez az aktuális szál tartozik a PsGetCurrentProcess() meghívásával
  2. Egy folyamat PID-jének lekérése
  3. Ha a PID nem egyezik a kívántal, akkor az átmenet egy duplán linkelt listán keresztül történik (ActiveProcessLinks mező, LIST_ENTRY típusú)
  4. ActiveProcessLinks mezők módosítása. Pontosabban, az A blokk következő EPROCESS blokkjára mutató hivatkozás C blokkra van beállítva, hasonlóképpen a C blokk előző blokkjára mutató hivatkozás. A B blokk hivatkozásai a rekordjukon zárva vannak. Így két lista jön létre, amelyek közül az egyik egy elemből áll

Egy folyamat kizárása a folyamatlistából nem befolyásolja a végrehajtását. A Windows rendszerben a kód végrehajtása szál szinten van ütemezve, a folyamatok határozzák meg a kontextust , amelyben a szálak futnak. A folyamatok elrejtése kívülről történik olyan eszközökben, amelyek EPROCESS folyamatobjektumokra támaszkodnak, például a Feladatkezelőben. A kernel diszpécser egy másik elszámolási sémát használ, amely más adatstruktúrákra (elsősorban az ETHREAD objektumra) támaszkodik. Ez a módszer lehetővé teszi a folyamatok elrejtését a funkcionalitás elvesztése nélkül [9] .

Illesztőprogramok

A Microsoft illesztőprogram-modellje támogatja a réteges architektúrát, így az I/O kéréseket (I/O kérések, alkalmazások és illesztőprogramok közötti adatcsere) egy sor csatlakoztatott illesztőprogram szolgálja ki , amelyek mindegyike saját feladatot lát el. A fizikai eszközt kiszolgáló illesztőprogramok láncát veremnek nevezzük. Ez a moduláris megközelítés lehetővé teszi új illesztőprogramok beépítését a verembe a funkcionalitás növelése érdekében. Ebben az esetben a láncnak csak egy külön szakasza kerül módosításra vagy hozzáadásra. Ezenkívül egyes perifériák ugyanazokat a vezérlőket (és ezért I/O buszokat) használják. A modularitás lehetővé teszi, hogy optimalizálja ugyanazon kódblokkok használatát, ahelyett, hogy minden eszközhöz külön illesztőprogramot írna.

A WDM-modell három típusú illesztőprogramot határoz meg: busz-illesztőprogram, funkció-illesztőprogram és szűrő-illesztőprogram. A szűrő-illesztőprogramok általában más modulok között helyezkednek el, és rögzítik a rajtuk áthaladó IRP -ket . Mielőtt elküldi az IRP-t a szomszédos illesztőprogramnak, a szűrő megvizsgálhatja a tartalmat, vagy módosíthatja azt, hogy befolyásolja a rendszer további viselkedését. Ha például lemezképet vesz le egy kritikus állásidő-kiszolgálóról, egy szűrő-illesztőprogram használható az adatfolyam módosítására egyes fájlok elrejtése érdekében.

Az IRP csomag (I/O request packet) egy Windows kernel adatstruktúra, amely adatcserét biztosít az alkalmazások és az illesztőprogram, valamint az illesztőprogram és az illesztőprogram között. Amikor egy alkalmazástól kérés érkezik, az I/O menedzser létrehoz egy megfelelő IRP-t, amely lokalizálja és továbbítja az illesztőprogram-verem legfelső objektumát. Ha a felső illesztőprogram képes volt önállóan feldolgozni a bejövő IRP-t, akkor befejezi a kérést, és visszaküldi az IRP-t az I/O-kezelőnek. Ellenkező esetben az illesztőprogram részleges feldolgozást hajt végre, lokalizálja a mögöttes objektumot a veremben, és megkéri az I/O-kezelőt, hogy adja át az IRP-t a következő illesztőprogramnak.

IRP létrehozásakor az I/O menedzser lefoglalja a fejléc utáni memóriaterületet. A lefoglalt memória az egyes verem-illesztőprogramokhoz lefoglalt IO_STACK_LOCATION struktúrák tömbjének írására szolgál:

A memória mérete a veremben lévő illesztőprogramok számának felel meg. A tömb 1-től van számozva, ami megfelel az alsó verem-illesztőprogramnak. A struktúra információkat tartalmaz az I/O menedzser által meghívott illesztőprogram-vezérlő függvényről (MajorFunction és MinorFunction mezők), a függvénynek átadott paraméterekről (Parameters mező, a tartalom függvénytől függően változik), egy mutatót az illesztőprogram objektumra (DeviceObject), egy mutató a befejezési függvényre (a CompletionRoutine mező, ez a funkció a legfelső szintű illesztőprogramban található).

Az illesztőprogram vezérlőfunkciója, amikor először kap egy IRP-t, visszaállítja a paramétereket a megfelelő I/O verem pozícióból az IoGetCurrentIrpStackLocation() meghívásával. Ezután az előírt műveleteket hajtják végre, majd az IRP-nek az alsó verem-illesztőprogramba történő továbbítása esetén a következő történik:

  • I/O verempozíció beállítása IRP-ben
  • befejező funkció regisztráció (opcionális)
  • IRP küldése a downstream meghajtónak
  • visszaküldési állapotkód (NTSTATUS)

Két szabványos mód van a verempozíció beállítására a következő illesztőprogramhoz [10] :

  • Az aktuális pozíció változtatás nélkül kerül elküldésre, funkció:
VOID IoSkipCurrentIrpStackLocation ( IN PIRP Irp );

A függvény eggyel csökkenti az IO_STACK_LOCATION tömbre mutató mutatót. Így az IRP továbbításakor a mutató visszaáll (automatikusan eggyel megnövelve), ennek eredményeként a verem ugyanazt a része kerül felhasználásra. Ha ezt a módszert használja, a verem végén lesz egy kihasználatlan terület.

  • Ha át kell adni az aktuális verempozíció tartalmát, kivéve a befejezési függvényre mutató mutatót (CompletionRoutine mező), használja:
VOID IoCopyCurrentIrpStackLocationToNext ( IN PIRP Irp );

Az IRP továbbítása a következő illesztőprogramnak a következő funkcióval történik:

NTSTATUS IoCallDriver ( IN PDEVICE_OBJECT DeviceObject , IN OUT PIRP Irp );

Az első argumentum egy mutató a mögöttes illesztőprogram objektumra. Az ilyen cím megszerzésének módját az adott vezérlőfüggvény határozza meg, szabványos módszer nincs.

Minden kérést vagy a verem utolsó meghajtójának kell leállítania (az IRP további továbbítása nem lehetséges), vagy az egyik upstream illesztőprogramnak.

Az I/O menedzser elindítja egy adott IRP befejezési folyamatát, amikor az IRP-feldolgozó illesztőprogramok bármelyike ​​meghívja az IoCompleteRoutine() befejezési függvényt. Híváskor az I/O menedzser nullákkal tölti fel az aktuális illesztőprogram I/O veremét, majd meghívja a magasabb szintű illesztőprogramot, amelynek lezárási funkciója erre az IRP-re van beállítva. Az IRP-ben csak az I/O állapotblokk áll rendelkezésre annak meghatározásához, hogy a kérést hogyan kezelje a magasabb szintű illesztőprogram befejezési funkciójának alsó szintű illesztőprogramja.

Valójában az így telepített szűrő-illesztőprogram nem csak a bejövő IRP-csomagok feldolgozását teszi lehetővé (például egy bizonyos lemezszektor blokkolvasása), hanem a downstream illesztőprogramok feldolgozási eredményeinek kezelését is a lezáró funkció inicializálásával [11] .

A rootkitek megvalósításának másik módja az MBR módosítása és az operációs rendszer kernelére való rendszerindítás - bootkit (például BackDoor.MaosBoot).

Az ilyen típusú rosszindulatú kódok a Windows környezetben az 1990-es évek eleje óta ismertek lopakodó vírusok néven .

UNIX és Linux rendszeren

  • a fő rendszer-segédprogramok cseréjével valósítható meg (az integritás-ellenőrzések nagyon könnyen észlelhetők, ráadásul könnyen blokkolhatók olyan kötelező hozzáférés-vezérlő eszközökkel , mint a SELinux vagy az AppArmor );
  • kernelmodulként van megvalósítva, és VFS-foltozáson vagy rendszerhívási tábla elfogásán (sys_call_table) alapul;
  • a kernel fizikai memóriájának módosítása alapján.

További funkciók

Önmaga mellett a rootkit általában elfedheti a rendszerben a konfigurációjában leírt könyvtárak és fájlok jelenlétét a lemezen, kulcsokat a rendszerleíró adatbázisban . Emiatt természetesen megjelentek a "csatolt" rootkit könyvtárak. Sok rootkit saját illesztőprogramokat és szolgáltatásokat telepít a rendszerbe (természetesen ezek is "láthatatlanok").

Rootkitek a DRM mellett és ellen

A rootkitek valójában a legtöbb másolásvédelmi szoftver (és olyan eszközök, amelyek megkerülhetik ezeket a védelmet – például a CD- és DVD-meghajtók emulátorai ) .

2005-ben a Sony BMG Corporation rootkit alapú védelmet épített be audio CD -ibe , amelyek a felhasználó tudta nélkül telepítettek.

Anti-rootkit

Ezek olyan segédprogramok vagy rezidens modulok, amelyek észlelik a rootkitek jelenlétét a rendszerben, és (különböző mértékben) eltávolítják azokat. Ehhez számos versengő eszköz létezik – fizetős és ingyenes is, de mindegyik hasonló elveket használ.

Módszerek a rootkitek kimutatására

Ismert algoritmus a MEP rootkitek elfogására. Lényege abban rejlik, hogy ugyanazt az információt többféle módon - az API segítségével és "közvetlenül" - regisztrálják, majd a kapott adatokat összehasonlítják az eltérések keresésére. A leggyakrabban az importálási táblákat és  a natív API -hívástáblákat vizsgálják , valamint szerkezetileg a teljes fájlrendszert.

A rootkit csapdázási eszközök alapvető arzenálja a következő módszereken alapul.

  1. aláírás keresés. Az első antivírusok óta használják, és egy rosszindulatú programban rejlő egyedi bájtlánc (aláírás) keresése a vizsgált fájlban.
  2. Heurisztikus vagy viselkedéselemző. Ez a technológia a rendszerbeállításokban, a Linux konfigurációs fájljaiban vagy a Windows rendszerleíró adatbázisában, a folyamatok és modulok gyanús viselkedésén stb.
  3. Integritás ellenőrzése. Ez a fajta keresés a különböző rendszerfájlok ellenőrző összegének (MD5 és hasonlók) vagy digitális aláírásának összehasonlításán alapul az eredeti fájlok ellenőrző összegét tartalmazó alappal. Eltérés esetén a program arra a következtetésre jut, hogy a fájlt módosították vagy teljesen kicserélték.

Jegyzetek

  1. Kolesnichenko, 2006 , p. 29.
  2. Kolesnichenko, 2006 , Funkció cím átírása.
  3. 1 2 Solomon, Russinovich, Ionescu, 2012 .
  4. Blunden, 2009 .
  5. Blunden, 2009 , DLL beszúrása.
  6. Zaitsev, 2006 , Elfogás egy függvény első bájtjának módosításával.
  7. Kernel objektumok kezelése  : [ eng. ] // MSDN .
  8. Blunden, 2009 , 7. fejezet A kernelobjektumok megváltoztatása.
  9. Blunden, 2009 , 7. fejezet: Kernelobjektumok megváltoztatása.
  10. Az IRP feldolgozás különböző módjai - Gyors referencia  : [ eng. ] // MSDN .
  11. Zaitsev, 2006 , Billentyűzet-kém szűrő-illesztőprogramon alapul.

Irodalom

  • Zaitsev O. Rootkitek, SpyWare_AdWare, Keyloggers és BackDoors. Észlelés és védelem / Oleg Zaicev. - Szentpétervár: BHV-Petersburg, 2006.
  • Blunden B. The Rootkit Arsenal / Bill Blunden. – Plano, Texas: Wordware Publishing, Inc., 2009.
  • Kolesnichenko D. ROOTKITS Windows alatt / Denis Kolesnichenko. - Szentpétervár: Tudomány és technológia, 2006.
  • Solomon D., Russinovich M., Ionescu A. Windows Internals / David Solomon, Mark Russinovich, Alex Ionescu. – Microsoft Press, 2012.

Linkek