Sikker indlæsning af biblioteker for at forhindre DLL-forudindlæsning af angreb

Support til Windows Vista Service Pack 1 (SP1) ophører den 12. juli 2011. Hvis du vil fortsætte med at modtage sikkerhedsopdateringer til Windows, skal du kontrollere, at du kører Windows Vista med Service Pack 2 (SP2). Du kan finde flere oplysninger på denne Microsoft-webside: Support ophører for nogle versioner af Windows.

Når et program indlæser et DLL (Dynamic Link Library) dynamisk uden at angive en fuldt kvalificeret sti, forsøger Windows at finde DLL-filen ved at søge i et veldefineret sæt mapper. Hvis en hacker får kontrol over en af mapperne, kan vedkommende tvinge programmet til at indlæse en ondsindet kopi af DLL-filen i stedet for den DLL-fil, den forventede. Disse angreb kaldes "DLL-forudindlæsning af angreb" og er fælles for alle operativsystemer, der understøtter dynamisk indlæsning af delte DLL-biblioteker. Virkningen af sådanne angreb kan være, at en hacker kan udføre kode i forbindelse med den bruger, der kører programmet. Når programmet køres som administrator, kan det føre til en lokal rettighedsudvidelse. Vi kender til fornyet interesse for disse angreb. For at begrænse den effekt, dette problem har på vores gensidige kunder, udgiver vi dette dokument til udviklerfællesskabet for at sikre, at de kender til problemet og har de nødvendige værktøjer til at løse problemet i deres programmer.

Resumé

Beskrivelse af DLL-forudindlæsning af angreb

LoadLibrary-baserede angreb

Når et program indlæser en DLL-fil dynamisk uden at angive en fuldt kvalificeret sti, forsøger Windows at finde denne DLL ved at søge lineært gennem et veldefineret sæt af mapper, kaldet DLL-søgerækkefølge. Hvis Windows finder DLL-filen i DLL-søgerækkefølgen, indlæses dll'en. Men hvis Windows ikke finder DLL-filen i nogen af mapperne i DLL-søgerækkefølgen, returneres en fejl i DLL-indlæsningshandlingen. Følgende er DLL-søgerækkefølgen for funktionerne LoadLibrary og LoadLibraryEx , som bruges til dynamisk indlæsning af DLL'er:

  1. Den mappe, som programmet indlæste fra
  2. Systemmappen
  3. 16-bit systemmappen
  4. Windows-mappen
  5. Den aktuelle arbejdsmappe (CWD)
  6. De mapper, der er angivet i miljøvariablen PATH

                
Overvej følgende scenarie:

  • Et program indlæser en DLL-fil uden at angive en fuldt kvalificeret sti, som programmet forventer at finde i programmet CWD.
  • Programmet er fuldt klar til at håndtere sagen, når den ikke finder DLL-filen.
  • Hackeren kender disse oplysninger om applikationen og kontrollerer CWD.
  • Hackeren kopierer deres egen specialdesignede version af DLL'en i CWD. Dette forudsætter, at hackeren har tilladelse til at gøre dette.
  • Windows søger gennem mapperne i DLL-søgerækkefølgen og finder DLL-filen i programmet CWD.

I dette scenarie kører den særligt udformede DLL-fil i programmet og får den aktuelle brugers rettigheder.

Anbefaling

For at forhindre dette angreb kan programmer fjerne den aktuelle arbejdsmappe (CWD) fra DLL-søgestien ved at kalde SetDllDirectory API ved hjælp af en tom streng (""). Hvis et program afhænger af indlæsning af en DLL-fil fra den aktuelle mappe, skal du hente den aktuelle arbejdsmappe og bruge den til at overføre den til en fuldt kvalificeret sti til LoadLibrary.

Vi er også opmærksomme på, at nogle udviklere bruger LoadLibrary til at validere, om en bestemt DLL-fil findes, for at afgøre, hvilken version af Windows der køres af brugeren. Du skal være opmærksom på, at dette kan gøre programmet sårbart. Hvis det berørte bibliotek faktisk ikke findes på den Windows-udgivelse, som programmet udføres på, kan en hacker introducere et bibliotek med det samme navn i CWD. Vi anbefaler på det kraftigste, at du ikke bruger denne metode. Brug i stedet de anbefalede teknikker, der er beskrevet i MSDN-artiklen "Getting the System Version".

Et program, der indlæser tredjeparts-plug-ins, og som ikke kan tvinge plug-in'en til at bruge en kvalificeret sti til dets LoadLibrary-kald, skal kalde SetDllDirectory("") for at fjerne CWD og derefter kalde SetDllDirectory("plug-in-installationsplacering") for at føje installationsmappen for plug-in'en til DLL-søgestien.

SearchPath-baserede angreb

Der findes et lignende angreb, når et program bruger SearchPath-API'en til at finde en DLL-fil og dynamisk indlæse den sti, der returneres af SearchPath. Følgende er standardsøgerækkefølgen for SearchPath-API'en:

  • Den mappe, som programmet indlæste fra
  • Den aktuelle arbejdsmappe (CWD)
  • Systemmappen
  • 16-bit systemmappen
  • Windows-mappen
  • De mapper, der er angivet i miljøvariablen PATH

Vi anbefaler ikke dette mønster, fordi det ikke er sikkert. Vi anbefaler ikke funktionen SearchPath som en metode til at finde en .dll fil, hvis den tilsigtede brug af outputtet er i et kald til funktionen LoadLibrary. Dette kan medføre, at du finder den forkerte .dll fil, fordi søgerækkefølgen for funktionen SearchPath adskiller sig fra den søgerækkefølge, der bruges af funktionen LoadLibrary. Hvis du skal finde og indlæse en .dll fil, skal du bruge funktionen LoadLibrary.

ShellExecute og CreateProcess

Variationer af disse problemer kan også forekomme, når udviklere kalder lignende funktioner som ShellExecute og CreateProcess for at indlæse eksterne eksekverbare filer. Vi anbefaler, at udviklere er forsigtige, når de indlæser binære filer, og angiver den fulde sti. Dette bør udgøre mindre kompleksitet, når du indlæser en binær i stedet for et bibliotek.

Vi anbefaler, at udviklere gør følgende:

  • Valider deres programmer for forekomster af ikke-usikre biblioteksindlæsninger (eksempler på dem er angivet senere i denne artikel). Det drejer sig om følgende:

    • Brug af SearchPath til at identificere placeringen af et bibliotek eller en komponent.
    • Brug af LoadLibrary til at identificere versionen af operativsystemet.
  • Brug fuldt kvalificerede stier til alle kald til LoadLibrary, CreateProcess og ShellExecute, hvor du kan.

  • Implementer kald til SetDllDirectory med en tom streng ("") for at fjerne den aktuelle arbejdsmappe fra standard-DLL-søgerækkefølgen, hvor det er påkrævet. Vær opmærksom på, at SetDllDirectory påvirker hele processen. Derfor skal du gøre dette en gang tidligt i processens initialisering, ikke før og efter kald til LoadLibrary. Da SetDllDirectory påvirker hele processen, kan flere tråde, der kalder SetDllDirectory med forskellige værdier, medføre en ikke-defineret funktionsmåde. Hvis processen er designet til at indlæse tredjeparts-DLL'er, er det desuden nødvendigt at teste for at afgøre, om en indstilling for hele processen vil medføre kompatibilitetsproblemer. Et kendt problem er, at når et program afhænger af Visual Basic for Applications, kan en indstilling for hele processen medføre kompatibilitetsproblemer.

  • Brug funktionen SetSearchPathMode til at aktivere sikker processøgetilstand for processen. Dette flytter den aktuelle arbejdsmappe til det sidste sted på søgelisten i SearchPath i hele processens levetid.

  • Undgå at bruge SearchPath til at kontrollere, om der findes en DLL-fil, uden at angive en fuldt kvalificeret sti, også selvom fejlsikret søgetilstand er aktiveret, da dette stadig kan føre til DLL-forudindlæsning af angreb.

Vejledning i at identificere ikke-usikre biblioteksbelastninger

I kildekode er følgende eksempler på ikke-usikre biblioteksindlæsninger:

  • I følgende kodeeksempel søger programmet efter "schannel.dll" ved hjælp af den mindst sikre søgesti. Hvis en hacker kan placere schannel.dll i CWD, indlæses den, selv før programmet søger i Windows-mapperne efter det relevante bibliotek.

    DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL); 
    HMODULE handle = LoadLibrary(result);
    
  • I følgende kodeeksempel forsøger programmet at indlæse biblioteket fra de forskellige program- og operativsystemplaceringer, der er beskrevet i starten af dette dokument for LoadLibrary()-opkaldet. Hvis der er risiko for, at filen ikke er til stede, kan programmet forsøge at indlæse filen fra den aktuelle arbejdsmappe. Dette scenarie er en smule mindre farligt end i det forrige eksempel. Det udsætter dog stadig applikationsbrugeren for risiko, hvis miljøet ikke er helt forudsigeligt.

    HMODULE handle = LoadLibrary("schannel.dll");
    

                
                
Følgende er eksempler på bedre og mere sikre biblioteksbelastninger:

  • I følgende kodeeksempel indlæses biblioteket direkte ved hjælp af en fuldt kvalificeret sti. Der er ingen risiko for, at hackeren introducerer skadelig kode, medmindre han allerede har skrivetilladelser til programmets destinationsmappe.

    HMODULE handle = LoadLibrary("c:\\windows\\system32\\schannel.dll");
    

    Bemærk! Du kan finde oplysninger om, hvordan du finder systemmappen, i følgende ressourcer:

    GetSystemDirectory
    http://msdn.microsoft.com/en-us/library/ms724373%28VS.85%29.aspx SHGetKnownFolderPath
    http://msdn.microsoft.com/en-us/library/bb762188%28v=VS.85%29.aspx

  • I følgende kodeeksempel fjernes den aktuelle arbejdsmappe fra søgestien, før LoadLibrary kaldes. Dette reducerer risikoen betydeligt, da hackeren er nødt til at styre enten programmappen, Windows-mappen eller eventuelle mapper, der er angivet i brugerens sti, for at bruge et DLL-forudindlæsningsangreb.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
  • På alle systemer, der har installeret sikkerhedsopdatering 963027 (beskrevet i MS09-014), vil følgende kode permanent flytte CWD til det allersidst sted i søgerækkefølgen. Eventuelle senere kald til funktionen SetSearchPathMode inde fra denne proces, der forsøger at ændre søgetilstanden, mislykkes.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
  • I følgende kodeeksempel fjernes den aktuelle arbejdsmappe fra søgestien, før LoadLibrary kaldes. Dette reducerer risikoen betydeligt, da hackeren er nødt til at styre enten programmappen, Windows-mappen eller eventuelle mapper, der er angivet i brugerens sti, for at kunne bruge et DLL-forudindlæsningsangreb.

    SetSearchPathMode (BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT );
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
    

Brug af Procesovervågning til dynamisk at registrere usikre belastninger

Microsoft udgiver et værktøj, der hedder Procesovervågning. Dette værktøj gør det muligt for udviklere og administratorer at spore funktionsmåden for en kørende proces nøje. Procesovervågning kan bruges dynamisk til at registrere, om et af dine programmer kan være sårbart over for denne type problem.

  • Hvis du vil downloade Process Monitor, skal du besøge følgende Microsoft-webside:
    http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

  • Prøv at starte dit program ved at bruge CWD indstillet til en bestemt mappe. Dobbeltklik f.eks. på en fil med et filtypenavn, hvis filbehandler er tildelt dit program.

  • Konfigurer Procesovervågning med følgende filtre:

    371495f2-14de-f99c-c55a-f75d31fe9ca8

  • Hvis en sårbar vej rammes, vil du se noget, der ligner følgende: 9acdd1ae-29b9-e499-9de9-8bc665b95e76

     Kaldet til det eksterne filshare for at indlæse en DLL-fil angiver, at dette er et sårbart program.

Flere oplysninger

Du kan finde flere oplysninger på følgende Microsoft-websider:

Søgerækkefølge for Dynamic Link-bibliotek

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx MSDN-dokumentation om funktionen SearchPath

http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx MSDN-dokumentation om funktionen LoadLibrary

http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx MSDN-dokumentation om funktionen SetDllDirectory

http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx MSDN-dokumentation om funktionen SetSearchPathMode

http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx Blogindlæg af David Leblanc, sikkerhedstekniker hos Microsoft Office

http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx Blogindlæg af Andrew Roths, MSRC Engineering-teamet om DLL-forudindlæsning af angreb

http://blogs.technet.com/b/srd/archive/2009/04/14/ms09-014-addressing-the-safari-carpet-bomb-vulnerability.aspx

Yderligere ressourcer