Sigurno učitavanje biblioteka radi sprječavanja napada učitavanja unaprijed putem DLL-a

Podrška za Windows Vista Service Pack 1 (SP1) obustavlja se 12. srpnja 2011. Da biste nastavili primati sigurnosna ažuriranja za Windows, provjerite koristite li sustav Windows Vista sa servisnim paketom Service Pack 2 (SP2). Dodatne informacije potražite na sljedećoj Microsoftovoj web-stranici: Obustavlja se podrška za neke verzije sustava Windows.

Kada aplikacija dinamički učitava biblioteku dinamičkih veza (DLL) bez navođenja potpuno kvalificiranog puta, Windows pokušava pronaći DLL pretraživanjem dobro definiranog skupa direktorija. Ako napadač stekne kontrolu nad nekim od direktorija, može prisiliti aplikaciju da učita zlonamjernu kopiju DLL-a umjesto očekivanog DLL-a. Ti su napadi poznati kao "DLL napadi unaprijed učitavanje" i zajednički su svim operacijskim sustavima koji podržavaju dinamičko učitavanje zajedničkih DLL biblioteka. Učinak takvih napada može biti da napadač može izvršiti kod u kontekstu korisnika koji pokreće aplikaciju. Kada se aplikacija pokrene kao administrator, to može dovesti do lokalnog povećanja ovlasti. Znamo za obnovljeni interes za ove napade. Da bismo ograničili učinak tog problema na naše zajedničke korisnike, objavljujemo ovaj dokument zajednici razvojnih inženjera da bismo bili sigurni da su upoznati s tim problemom i da u svojim aplikacijama imaju potrebne alate za njegovo rješavanje.

Sažetak

Opis napada učitavanja unaprijed u DLL

Napadi temeljeni na LoadLibrary-u

Kada aplikacija dinamički učitava DLL bez navođenja potpuno kvalificiranog puta, Windows pokušava pronaći taj DLL linearnim pretraživanjem kroz dobro definiran skup direktorija, poznat kao redoslijed pretraživanja DLL-a. Ako Windows pronađe DLL unutar redoslijeda pretraživanja DLL-a, učitat će taj DLL. No ako Windows ne pronađe DLL ni u jednom direktoriju redoslijeda pretraživanja DLL-a, vratit će pogrešnu radnju učitavanja DLL-a. Slijedi redoslijed DLL pretraživanja za funkcije LoadLibrary i LoadLibraryEx , koje se koriste za dinamičko učitavanje DLL-ova:

  1. Direktorij iz kojeg se aplikacija učitala
  2. Direktorij sustava
  3. 16-bitni direktorij sustava
  4. Imenik sustava Windows
  5. Trenutni radni direktorij (CWD)
  6. Direktoriji koji su navedeni u varijabli okruženja PATH

                
Razmotrite sljedeći scenarij:

  • Aplikacija učitava DLL bez navođenja potpuno kvalificiranog puta koji očekuje pronaći u CWD-u aplikacije.
  • Aplikacija je u potpunosti spremna za rješavanje slučaja kada ne pronađe DLL.
  • Napadač zna te podatke o aplikaciji i kontrolira CWD.
  • Napadač kopira vlastitu posebno izrađenu verziju DLL-a u CWD-u. To podrazumijeva da napadač ima dozvolu za to.
  • Windows pretražuje direktorije u redoslijedu pretraživanja DLL biblioteke i pronalazi DLL u CWD-u aplikacije.

U tom se scenariju posebno izrađeni DLL pokreće unutar aplikacije i stječe privilegije trenutnog korisnika.

Preporuka

Da bi spriječile taj napad, aplikacije mogu ukloniti trenutačni radni direktorij (CWD) iz puta pretraživanja DLL-a pozivanjem API-ja SetDllDirectory pomoću praznog niza (""). Ako aplikacija ovisi o učitavanju DLL-a iz trenutnog direktorija, nabavite trenutni radni direktorij i upotrijebite ga za prosljeđivanje u potpunosti kvalificiranom putu LoadLibrary.

Svjesni smo i da neki razvojni inženjeri koriste LoadLibrary da bi provjerili postoji li određena DLL biblioteka da bi odredili koju verziju sustava Windows korisnik koristi. Trebali biste biti svjesni da bi to moglo učiniti aplikaciju ranjivom. Ako zahvaćena biblioteka doista ne postoji u izdanju sustava Windows na kojem se aplikacija izvršava, napadač bi mogao u CWD uvesti biblioteku istog naziva. Toplo ne preporučujemo korištenje ove tehnike. Umjesto toga koristite preporučene tehnike opisane u članku MSDN-a "Dohvaćanje verzije sustava".

Aplikacija koja učitava dodatke drugih proizvođača i koja ih ne može prisiliti da koriste kvalificirani put za svoje pozive LoadLibrary treba nazvati SetDllDirectory("") da ukloni CWD, a zatim pozvati SetDllDirectory("mjesto instalacije dodatka") da bi dodala direktorij za instalaciju dodatka u put pretraživanja DLL-a.

Napadi temeljeni na putovima pretraživanja

Sličan napad događa se kada aplikacija koristi API za put pretraživanja da bi pronašla DLL biblioteku i dinamički učitala put koji je vratio put pretraživanja. Slijedi zadani redoslijed pretraživanja za API SearchPath:

  • Direktorij iz kojeg se aplikacija učitala
  • Trenutni radni direktorij (CWD)
  • Direktorij sustava
  • 16-bitni direktorij sustava
  • Imenik sustava Windows
  • Direktoriji koji su navedeni u varijabli okruženja PATH

Ne preporučujemo ovaj uzorak jer nije siguran. Ne preporučujemo funkciju SearchPath kao metodu pronalaženja .dll datoteke ako je namjena izlaza u pozivu funkciji LoadLibrary. To može uzrokovati pronalaženje pogrešne .dll datoteke jer se redoslijed pretraživanja funkcije SearchPath razlikuje od redoslijeda pretraživanja koji koristi funkcija LoadLibrary. Ako morate pronaći i učitati .dll datoteku, koristite funkciju LoadLibrary.

ShellExecute i CreateProcess

Varijacije ovih problema mogu se pojaviti i kada razvojni inženjeri pozovu slične funkcije kao što su ShellExecute i CreateProcess za učitavanje vanjskih izvršnih datoteka. Preporučujemo da razvojni inženjeri budu oprezni prilikom učitavanja binarnih datoteka i navedu potpuno kvalificirani put. To bi trebalo predstavljati manje komplicirano kada učitate binarni sustav umjesto biblioteke.

Preporučujemo da razvojni inženjeri učine sljedeće:

  • provjeriti njihove aplikacije za slučajeve nesigurnih učitavanja biblioteka (primjeri su navedeni u nastavku članka). To uključuje sljedeće:

    • korištenje značajke SearchPath za određivanje mjesta biblioteke ili komponente
    • Korištenje komponente LoadLibrary za identifikaciju verzije operacijskog sustava.
  • Upotrijebite potpuno kvalificirane putove za sve pozive za LoadLibrary, CreateProcess i ShellExecute gdje god možete.

  • Implementirajte pozive na SetDllDirectory s praznim nizom ("") kako biste uklonili trenutni radni direktorij iz zadanog redoslijeda pretraživanja DLL-a gdje je to potrebno. Imajte na umu da SetDllDirectory utječe na cijeli proces. Zato biste to trebali učiniti jednom na početku inicijalizacije procesa, a ne prije i nakon poziva za LoadLibrary. Budući da SetDllDirectory utječe na cijeli proces, više niti koje pozivaju SetDllDirectory s različitim vrijednostima može uzrokovati nedefinirano ponašanje. Osim toga, ako je postupak osmišljen za učitavanje DLL-ova drugih proizvođača, bit će potrebno testiranje da bi se utvrdilo hoće li postavljanje na razini procesa uzrokovati nekompatibilnosti. Poznati je problem da kada aplikacija ovisi o jeziku Visual Basic for Applications, postavka cijelog procesa može uzrokovati nekompatibilnosti.

  • Koristite funkciju SetSearchPathMode da biste omogućili siguran način pretraživanja procesa za proces. Time se trenutni radni direktorij pomiče na posljednje mjesto na popisu za pretraživanje puta pretraživanja tijekom životnog ciklusa procesa.

  • Izbjegavajte korištenje značajke SearchPath za provjeru postojanja DLL-a bez navođenja potpuno kvalificiranog puta, čak i ako je omogućen siguran način pretraživanja jer to i dalje može dovesti do napada učitavanja unaprijed DLL-a.

Smjernice za prepoznavanje nesigurnih učitavanja biblioteka

U izvornom kodu slijede primjeri nesigurnih učitavanja biblioteka:

  • U sljedećem primjeru koda aplikacija traži "schannel.dll" pomoću najmanje sigurnog puta pretraživanja. Ako napadač može postaviti schannel.dll u CWD, on će se učitati čak i prije nego što aplikacija pretraži direktorije sustava Windows u potrazi za odgovarajućom bibliotekom.

    DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL); 
    HMODULE handle = LoadLibrary(result);
    
  • U sljedećem primjeru koda aplikacija pokušava učitati biblioteku s različitih lokacija aplikacija i operacijskih sustava opisanih na početku ovog dokumenta za poziv LoadLibrary(). Ako postoji rizik da datoteka ne postoji, aplikacija bi mogla pokušati učitati datoteku iz trenutačno aktivnog direktorija. Taj je scenarij nešto manje opasan od prethodnog. Međutim, i dalje izlaže korisnika aplikacije riziku ako okruženje nije u potpunosti predvidljivo.

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

                
                
Slijede primjeri boljeg i sigurnijeg učitavanja biblioteka:

  • U sljedećem primjeru koda biblioteka se učitava izravno pomoću potpuno kvalificiranog puta. Nema opasnosti da napadač unese zlonamjerni kod osim ako već nema dozvole za pisanje u ciljni direktorij aplikacije.

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

    Napomena Informacije o tome kako odrediti direktorij sustava potražite u sljedećim resursima:

    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

  • U sljedećem primjeru koda trenutni radni direktorij uklanja se s puta pretraživanja prije pozivanja funkcije LoadLibrary. Time se znatno smanjuje rizik jer bi napadač morao kontrolirati direktorij aplikacije, direktorij sustava Windows ili sve direktorije koji su navedeni u korisnikovu putu da bi mogao upotrijebiti napad unaprijed učitavanjem DLL-a.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
  • U svim sustavima na koje je instalirano sigurnosno ažuriranje 963027 (opisano u članku MS09-014) sljedeći kod trajno bi pomaknuo CWD na posljednje mjesto u redoslijedu pretraživanja. Svi kasniji pozivi funkciji SetSearchPathMode unutar tog postupka koji pokušavaju promijeniti način pretraživanja neće uspjeti.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
  • U sljedećem primjeru koda trenutni radni direktorij uklanja se s puta pretraživanja prije pozivanja funkcije LoadLibrary. Time se znatno smanjuje rizik jer bi napadač morao kontrolirati direktorij aplikacije, direktorij sustava Windows ili direktorije koji su navedeni u korisnikovu putu da bi mogao upotrijebiti napad unaprijed učitavanja DLL-a.

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

Dinamičko otkrivanje nesigurnih opterećenja pomoću nadzora procesa

Microsoft objavljuje alat pod nazivom Process Monitor. Taj alat razvojnim inženjerima i administratorima omogućuje pomno praćenje ponašanja pokrenutog procesa. Nadzor procesa može se koristiti za dinamičko otkrivanje može li neka od vaših aplikacija biti podložna ovakvoj vrsti problema.

  • Da biste preuzeli Process Monitor, posjetite sljedeću Microsoftovu web-stranicu:
    http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

  • Pokušajte pokrenuti aplikaciju pomoću CWD-a postavljenog na određeni direktorij. Možete, primjerice, dvokliknuti datoteku čiji je rukovatelj datoteka dodijeljen vašoj aplikaciji.

  • Postavite Process Monitor sa sljedećim filtrima:

    371495f2-14de-f99c-c55a-f75d31fe9ca8

  • Ako se pogodi ranjivi put, vidjet ćete nešto slično sljedećem: 9acdd1ae-29b9-e499-9de9-8bc665b95e76

     Poziv udaljenom resursu za zajedničko korištenje datoteka radi učitavanja DLL-a označava da je to ranjiv program.

Dodatne informacije

Dodatne informacije potražite na sljedećim Microsoftovim web-stranicama:

Redoslijed pretraživanja biblioteke dinamičkih veza

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx Dokumentacija MSDN-a o funkciji SearchPath

http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx MSDN dokumentacija o funkciji LoadLibrary

http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx Dokumentacija MSDN-a o funkciji SetDllDirectory

http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx MSDN dokumentacija o funkciji SetSearchPathMode

http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx Članak na blogu Davida Leblanca, glavnog sigurnosnog inženjera u sustavu Microsoft Office

http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx Članak na blogu Andrewa Rothsa, inženjerskog tima MSRC-a o DLL napadima unaprijed učitavanjem

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

Dodatni resursi