Rootkit

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 20 augusti 2020; kontroller kräver 12 redigeringar .

Rootkit ( eng.  rootkit , det vill säga " root set ") är en uppsättning programvaruverktyg (till exempel körbara filer, skript, konfigurationsfiler ) som tillhandahåller:

Termen Rootkit kom historiskt från UNIX -världen , och denna term syftar på en uppsättning verktyg eller en speciell kärnmodul som en angripare installerar på ett datorsystem som han har hackat omedelbart efter att ha fått superanvändarrättigheter. Denna uppsättning innehåller som regel en mängd olika verktyg för att täcka spåren av ett intrång i systemet, göra sniffers , skannrar, keyloggers , trojaner osynliga , och ersätta de viktigaste UNIX-verktygen (i fallet med ett icke-nukleärt rootkit). Rootkit låter en angripare få fotfäste i ett komprometterat system och dölja spår av deras aktiviteter genom att dölja filer, processer och själva närvaron av ett rootkit i systemet.

Ett rootkit kan installeras i ett system på olika sätt: genom att ladda ner via en exploit , efter att ha erhållit skalåtkomst (i det här fallet kan ett verktyg som wget eller den ursprungliga FTP-klienten användas för att ladda ner rootkit från en fjärrenhet), i källkoden eller resurserna för programvaruprodukten.

Klassificering av rootkits

Grundläggande metoder för implementering

På Microsoft Windows

Det finns olika rootkit-teknologier, de vanligaste är call table capture (IAT, IDT, SSDT, GDT ), funktionsavlyssning (till exempel modifiering av initiala bytes), direkt modifiering av systemobjekt (DKOM), metoder för att använda drivrutiner.

Fånga samtalstabeller

Anropstabellen är en array i vilken varje element lagrar adressen för motsvarande procedur. Sådana tabeller finns både i kärnläge (IDT, CPU MSR, GDT, SSDT, IRP-utskickningstabell) och i användarläge (IAT).

Import Address Table (IAT) är huvudanropstabellen för användarlägesmoduler. De flesta körbara filer har en eller flera inbyggda IAT:er som innehåller adresserna till biblioteksrutiner importerade från DLL:n [2] .

På en multiprocessormaskin finns det flera instanser av anropstabeller (t.ex. IDT, GDT , MSR ). Eftersom varje processor har sina egna systemregister (i synnerhet GDTR - det globala deskriptortabellregistret (GDT), innehåller IDTR - avbrottstabellbeskrivningsregistret (IDT) och IA32_SYSENTER_EIP - den virtuella adressen till kärnlägesingångspunkten (MSR)) , den har också egna systemstrukturer [3] .

När en post i anropstabellen ändras, styrs exekveringen av program och vid behov omdirigeras till de nödvändiga funktionerna. Den avlyssnade proceduren kan [4] :

  • blockera samtal från vissa applikationer (t.ex. antivirus )
  • ersätt den ursprungliga proceduren
  • övervaka systemet genom att avlyssna ingångsparametrar
  • filterutgångsparametrar

Den allmänna idén med fångst är följande:

  • Identifiera samtalstabellen, få dess adress
  • Spara befintlig post i tabellen
  • Ersätt posten med ny adress
  • Återställ den ursprungliga posten

Om avlyssningsfunktionen innebär att den ursprungliga proceduren anropas, utförs blockering och övervakning före anropet, parameterfiltrering efter.

IAT är en anropstabell som finns i programmets filstruktur. IAT lagrar adressen till procedurer som exporteras av en viss DLL . Varje DLL som ett program länkar till vid uppstart har sin egen IAT. För att fånga IAT måste du göra följande:

  • Få tillgång till processorns adressutrymme
  • Lokalisera IAT i processorminnesbild
  • Ändra obligatoriska IAT

För att manipulera IAT krävs åtkomst till adressutrymmet för applikationen som tabellen tillhör. Ett sätt är att injicera en DLL. Bland metoderna för att injicera en DLL i adressutrymmet för en process kan man specificera [5] :

  • Ändring av registervärdet för AppInit_DLL
  • SetWindowsHookEx() API-anrop
  • Använder fjärrtrådar
Avlyssning genom att ändra funktionskoden

Funktionsprincipen är baserad på det faktum att de första byten av uppfångade funktioner ersätts av interceptorkoden. Det bör betonas att när du installerar interceptorn analyseras inte koden för den avlyssnade funktionen: de första N byten ändras och inte de första N maskininstruktionerna. Konsekvensen av detta faktum är [6] :

  1. Interceptorkoden kan endast ställas in i början av en funktion;
  2. för varje anrop till den avlyssnade funktionen måste avlyssningsapparaten återställa sin maskinkod innan samtalet och avlyssna igen efter att anropet har slutförts.

Rootkit-algoritm:

  1. En array skapas i interceptorns kropp, där de första N byte av var och en av de fångade funktionerna skrivs (vanligtvis överstiger storleken på den modifierade koden inte 20 byte)
  2. Arrayen är fylld med referensmaskinkoden för de avlyssnade funktionerna.
  3. I början av varje avlyssnad funktion skrivs en kod som överför kontrollen till interceptorn.

Interceptor operationsalgoritm:

  1. Handlingssekvensen definierad av angriparen.
  2. Återställning av de första N byte av den avlyssnade funktionen.
  3. Anropar den avlyssnade funktionen.
  4. Omändring av maskinkoden för den avlyssnade funktionen: skriva över koden som överför kontrollen till interceptorn i de första byten.
  5. Analys och vid behov modifiering av resultatet av den ursprungliga funktionen.
  6. Utför ret-operationen, återför kontrollen till programmet som anropade funktionen.

För att avlyssna räcker det med att modifiera de första fem byten av funktionen, i stället för vilken jmp-operationen skrivs, för att överföra kontrollen till rootkit-interceptorn.

Det bör noteras att de enklaste systemen för att skydda mot attacker av denna typ kontrollerar den första byten av de anropade funktionerna för närvaron av jmp-maskinens opkod i dem. Som en motåtgärd använder rootkit-utvecklare tekniker för att "maskera" koden som skrivits i början av interceptorfunktionen (med kommandon som PUSH / RET, placera flera NOP- operatorer eller skräpkod som PUSH AX / POP AX, såväl som element av polymorfism ).

Metoden för att modifiera de första byten av funktioner har ett antal nackdelar, huvudsakligen relaterade till behovet av att återställa maskinkoden för avlyssnade funktioner innan de anropas och återuppfångas efter anropet. Dessa operationer minskar systemets prestanda och kan få flertrådade applikationer att krascha.

DKOM (Direkt Kernel Object Manipulation)

Operativsystem i Windows NT- familjen använder standardobjektmodeller. Olika komponenter i exekveringssystemet definierar en eller flera typer av objekt. Varje komponent exporterar i kärnläge en uppsättning funktioner och egenskaper som stöds, kallat COM-gränssnitt, för att manipulera den typen av objekt. Ingen komponent kan direkt komma åt ett annat komponentobjekt. Typiska kärnlägesobjekt är [7] :

  • enhetstypobjekt (en objekttyp i privilegierat läge definierad av I/O-hanteraren, som används för att representera en fysisk, logisk eller virtuell enhet)
  • filobjekt
  • symboliska länkar
  • registernycklar
  • trådar och processer
  • dispatcher-objekt (en objekttypsklass i privilegierat läge som används för att styra sändnings- och synkroniseringsprocesserna)

Denna design ger flexibilitet och portabilitet, till exempel kan framtida versioner av operativsystemet innehålla kärnkomponenter som definierar liknande objekt, men har en helt annan intern struktur. Om sådana komponenter kommer att exportera funktioner med bevarade namn och parametrar kommer ändringen inte att ha någon effekt [3] .

Direkt manipulation av kärnobjekt är en ganska kraftfull teknik som är svår att upptäcka. Det finns dock ett antal nackdelar, såsom metodinstabilitet, versionsberoende, implementeringskomplexitet på grund av avsaknaden av en dokumenterad beskrivning av objektens strukturer och egenskaper. Trots dessa begränsningar låter den här metoden dig dölja processer, drivrutiner, portar och höja privilegierna för trådar (därav processer).

EPROCESS är en struktur som fungerar som en intern representation av en process (processobjekt). Windows använder en cirkulär dubbellänkad lista över EPROCESS-strukturer för att hålla reda på exekveringsförloppet. Länkar som länkar EPROCESS-objekt finns i fältet ActiveProcessLink, vars struktur är LIST_ENTRY [8] :

typedef struct _LIST_ENTRY { struct _LIST_ENTRY * Flink ; struct _LIST_ENTRY * Blink ; } LIST_ENTRY , * PLIST_ENTRY ;

Den enklaste processdöljningsalgoritmen:

  1. Få en pekare till processen som den aktuella tråden tillhör genom att anropa PsGetCurrentProcess()
  2. Hämta PID för en process
  3. Om PID inte matchar det önskade görs en övergång genom en dubbellänkad lista (ActiveProcessLinks-fält, LIST_ENTRY-typ)
  4. Ändra ActiveProcessLinks-fält. Speciellt är länken till nästa EPROCESS-block i block A satt till block C, likaså länken till föregående block i block C. Länkar i block B är stängda på deras post. Således skapas två listor, varav en består av ett element

Att utesluta en process från processlistan påverkar inte dess utförande. I Windows är kod schemalagd för exekvering på trådnivå, processer definierar sammanhanget i vilket trådarna körs. Att dölja en process görs externt i verktyg som förlitar sig på EPROCESS processobjekt, såsom Task Manager. Kärnavsändaren använder ett annat redovisningsschema som förlitar sig på andra datastrukturer (främst ETHREAD-objektet). Denna metod låter dig dölja processer utan att förlora funktionalitet [9] .

Drivrutiner

Microsofts drivrutinsmodell stöder en skiktad arkitektur, så en I/O-begäran (I/O-begäran, datautbyte mellan applikationer och drivrutiner) kan betjänas av en serie anslutna drivrutiner , som var och en utför sin egen uppgift. En kedja av förare som betjänar en fysisk enhet kallas en stack. Detta modulära tillvägagångssätt gör att nya drivrutiner kan inkluderas i stacken för att öka funktionaliteten. I detta fall ändras eller läggs endast en separat del av kedjan till. Dessutom använder vissa kringutrustning samma styrenheter (och därför I/O-bussar). Modularitet gör att du kan optimera användningen av samma kodblock, istället för att skriva en separat drivrutin för varje enhet.

Tre typer av drivrutiner definieras i WDM-modellen: busdrivrutiner, funktionsdrivrutiner och filterdrivrutiner. Filterdrivrutiner är vanligtvis placerade mellan andra moduler och fångar in IRP:er som passerar genom dem . Innan IRP:n skickas till den intilliggande drivrutinen kan filtret undersöka innehållet eller modifiera det för att påverka ytterligare systembeteende. Till exempel, när du tar en diskbild från en kritisk driftstoppserver, kan en filterdrivrutin användas för att ändra dataströmmen för att dölja vissa filer.

IRP-paket (I/O-förfrågningspaket) är en Windows-kärndatastruktur som tillhandahåller datautbyte mellan applikationer och drivrutinen, såväl som mellan drivrutinen och drivrutinen. När en begäran tas emot från en applikation genererar I/O-hanteraren en lämplig IRP, som lokaliserar och vidarebefordrar till det översta objektet i drivrutinsstacken. Om toppföraren kunde bearbeta den inkommande IRP på egen hand, slutför den begäran och returnerar IRP till I/O-hanteraren. Annars utför föraren partiell bearbetning, lokaliserar det underliggande objektet på stacken och ber I/O-hanteraren att skicka IRP:n till nästa drivrutin.

När du skapar en IRP reserverar I/O-hanteraren minnesområdet efter rubriken. Det tilldelade minnet används för att skriva en array av IO_STACK_LOCATION-strukturer tilldelade för varje stackdrivrutin:

Minnesstorleken motsvarar antalet drivrutiner i stacken. Arrayen är numrerad från 1, motsvarande den nedre stackdrivrutinen. Strukturen innehåller information om förarkontrollfunktionen som anropas av I/O-hanteraren (fälten MajorFunction och MinorFunction), parametrarna som skickas till funktionen (fältet Parametrar, innehållet varierar beroende på funktion), en pekare till förarobjektet (DeviceObject), en pekare till kompletteringsfunktionen (fältet CompletionRoutine, denna funktion finns i drivrutinen på översta nivån).

Förarens kontrollfunktion återställer, när den först tar emot en IRP, parametrarna från lämplig I/O-stackposition genom att anropa IoGetCurrentIrpStackLocation(). Därefter utförs de föreskrivna åtgärderna, varefter, i fallet med vidarebefordran av IRP till den nedre stackdrivrutinen, inträffar följande:

  • ställa in I/O-stackposition i IRP
  • registrering av uppsägningsfunktion (valfritt)
  • skicka en IRP till nedströmsdrivrutinen
  • returstatuskod (NTSTATUS)

Det finns två standardsätt att ställa in stackpositionen för följande förare [10] :

  • Den aktuella positionen skickas utan ändringar, funktion:
VOID IoSkipCurrentIrpStackLocation ( IN PIRP Irp );

Funktionen minskar pekaren till matrisen IO_STACK_LOCATION med en. Sålunda, när IRP:n vidarebefordras, kommer pekaren att återställas (automatiskt ökas med en), som ett resultat kommer samma sektion av stacken att användas. När du använder den här metoden kommer det att finnas ett oanvänt område i slutet av stapeln.

  • Om det är nödvändigt att skicka innehållet i den aktuella stackpositionen, förutom pekaren till kompletteringsfunktionen (CompletionRoutine-fältet), använd:
VOID IoCopyCurrentIrpStackLocationToNext ( IN PIRP Irp );

Vidarebefordran av en IRP till nästa förare görs med funktionen:

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

Det första argumentet är en pekare till det underliggande drivrutinsobjektet. Metoden för att erhålla en sådan adress bestäms av den specifika kontrollfunktionen, det finns ingen standardmetod.

Varje begäran måste avslutas antingen av den sista föraren i stacken (ingen vidare vidarebefordran av IRP är möjlig) eller av en av uppströmsförarna.

I/O-hanteraren initierar kompletteringsprocessen för en given IRP när någon av IRP-bearbetningsdrivrutinerna anropar IoCompleteRoutine() kompletteringsfunktionen. När den anropas fyller I/O-hanteraren den aktuella förarens I/O-stack med nollor och anropar sedan drivrutinen på högre nivå med termineringsfunktionen inställd på denna IRP. Endast I/O-statusblocket i IRP:n är tillgängligt för att bestämma hur begäran hanteras av drivrutinen på lägre nivå av drivrutinens kompletteringsfunktion på högre nivå.

I själva verket låter filterdrivrutinen som är installerad på detta sätt inte bara bearbeta inkommande IRP-paket (till exempel blockläsning av en viss disksektor), utan också hantera resultaten av bearbetning av nedströmsdrivrutiner genom att initiera avslutningsfunktionen [11] .

En annan metod för att implementera rootkits är att modifiera MBR och starta upp till operativsystemets kärna - bootkits (till exempel BackDoor.MaosBoot).

Denna typ av skadlig kod i Windows-miljön har varit känd sedan början av 1990-talet under namnet stealth-virus .

På UNIX och Linux

  • implementeras genom att ersätta de viktigaste systemverktygen (mycket lätt att upptäcka av integritetskontroller, dessutom blockeras de lätt av obligatoriska åtkomstkontrollverktyg som SELinux eller AppArmor );
  • implementerad som en kärnmodul och baserad på VFS-patchning eller systemanropstabellavlyssning (sys_call_table);
  • baserat på modifiering av kärnans fysiska minne.

Ytterligare funktioner

Förutom sig själv kan ett rootkit, som regel, maskera närvaron i systemet av alla kataloger och filer som beskrivs i dess konfiguration på disken, nycklar i registret . Av denna anledning dök "monterade" rootkit-bibliotek naturligt upp. Många rootkits installerar sina egna drivrutiner och tjänster i systemet (så klart är de också "osynliga").

Rootkits för och emot DRM

Rootkits är faktiskt de flesta kopieringsskyddsprogram (och sätt att kringgå dessa skydd - till exempel emulatorer av CD- och DVD-enheter ) .

2005 införlivade Sony BMG Corporation rootkit-baserat skydd i sina ljud-cd-skivor , som installerades utan användarens vetskap.

Anti-rootkits

Dessa är verktyg eller inbyggda moduler som upptäcker närvaron av rootkits i systemet och (i varierande grad) tar bort dem. Det finns många konkurrerande verktyg för detta – både betalda och gratis, men de använder alla liknande principer.

Metoder för att upptäcka rootkits

Det finns en känd algoritm för att fånga MEP rootkits. Dess kärna ligger i det faktum att samma information registreras på flera sätt - med hjälp av API:et och "direkt", varefter den mottagna informationen jämförs på jakt efter avvikelser. Importtabellerna och  Native API -anropstabellerna skannas oftast , såväl som strukturellt hela filsystemet.

Den grundläggande arsenalen av rootkit-fällningsverktyg är baserad på följande metoder.

  1. signatursökning. Den har använts sedan tiden för de första antivirusprogrammen och är en sökning i den skannade filen efter en unik bytekedja (signatur) som är inneboende i ett skadligt program.
  2. Heuristisk eller beteendeanalysator. Denna teknik bygger på att hitta avvikelser i systeminställningar, Linux-konfigurationsfiler eller Windows-registret, misstänkt beteende hos processer och moduler, och så vidare.
  3. Integritetskontroll. Denna typ av sökning bygger på att jämföra kontrollsumman (MD5 och liknande) eller digital signatur för olika systemfiler med en bas som innehåller kontrollsumman för originalfilerna. I händelse av en missmatchning drar programmet slutsatsen att filen har ändrats eller helt ersatts.

Anteckningar

  1. Kolesnichenko, 2006 , sid. 29.
  2. Kolesnichenko, 2006 , Omskrivning av funktionsadress.
  3. 1 2 Solomon, Russinovich, Ionescu, 2012 .
  4. Blunden, 2009 .
  5. Blunden, 2009 , Injicera en DLL.
  6. Zaitsev, 2006 , Avlyssning genom modifiering av de första byten av en funktion.
  7. Hantera kärnobjekt  : [ eng. ] // MSDN .
  8. Blunden, 2009 , Kapitel 7 Ändra kärnobjekt.
  9. Blunden, 2009 , kapitel 7. Ändra kärnobjekt.
  10. Olika sätt att bearbeta IRP - Snabbreferens  : [ eng. ] // MSDN .
  11. Zaitsev, 2006 , Tangentbordsspion baserad på en filterdrivrutin.

Litteratur

  • Zaitsev O. Rootkits, SpyWare_AdWare, Keyloggers & BackDoors. Detektion och skydd / Oleg Zaitsev. - St. Petersburg: BHV-Petersburg, 2006.
  • Blunden B. The Rootkit Arsenal / Bill Blunden. — Plano, Texas: Wordware Publishing, Inc., 2009.
  • Kolesnichenko D. ROTKITS under Windows / Denis Kolesnichenko. - St. Petersburg: Science and Technology, 2006.
  • Solomon D., Russinovich M., Ionescu A. Windows Internals / David Solomon, Mark Russinovich, Alex Ionescu. — Microsoft Press, 2012.

Länkar