Kódtárak biztonságos betöltése a DLL-előtelepítési támadások megelőzése érdekében

2011. július 12-én véget ér a Windows Vista Service Pack 1 (SP1) támogatása. Ha továbbra is hozzá szeretne jutni a Windows biztonsági frissítéseihez, győződjön meg arról, hogy Service Pack 2 (SP2) szervizcsomaggal bővített Windows Vista rendszert futtat. További információért keresse fel a Microsoft következő weblapját: Megszűnik egyes Windows-verziók támogatása.

Amikor egy alkalmazás dinamikusan tölt be egy dinamikus csatolású függvénytárat (DLL) a teljes elérési út megadása nélkül, a Windows egy jól definiált könyvtárkészletben történő kereséssel próbálja megkeresni a DLL-t. Ha a támadó átveszi az egyik könyvtár feletti ellenőrzést, kényszerítheti az alkalmazást, hogy a várt DLL helyett a DLL egy rosszindulatú másolatát töltse le. Az ilyen támadásokat "DLL-előtelepítési támadásoknak" nevezik, és közösek minden olyan operációs rendszerben, amely támogatja a megosztott DLL-függvénytárak dinamikus betöltését. Az ilyen támadások hatására a támadó kódot hajthat végre az alkalmazást futtató felhasználó környezetében. Ha az alkalmazást rendszergazdaként futtatja, ez a jogosultságok helyi szintemelkedéséhez vezethet. Tudunk arról, hogy megújult az érdeklődés e támadások iránt. Annak érdekében, hogy korlátozzuk a probléma közös ügyfeleinkre gyakorolt hatását, közzétesszük ezt a dokumentumot a fejlesztői közösség számára, hogy biztosan tudjanak a problémáról, és rendelkezzenek az alkalmazásaikban a probléma megoldásához szükséges eszközökkel.

Összegzés

A DLL-előtelepítési támadások leírása

LoadLibrary-alapú támadások

Amikor egy alkalmazás dinamikusan tölt be egy DLL-t teljes elérési út megadása nélkül, a Windows egy jól definiált könyvtárkészletben (DLL-keresési sorrend) lineárisan keresve próbálja megkeresni ezt a DLL-t. Ha a Windows megtalálja a DLL-t a DLL keresési sorrendjében, akkor azt tölti be. Ha azonban a Windows nem találja a DLL-fájlt a DLL keresési sorrendjében egyik könyvtárban sem, hibát ad vissza a DLL betöltési műveletnek. A DLL-ek dinamikus betöltésére szolgáló LoadLibrary és LoadLibraryEx függvények DLL-keresési sorrendje a következő:

  1. Az a könyvtár, ahonnan az alkalmazás betöltődött
  2. A rendszerkönyvtár
  3. A 16 bites rendszerkönyvtár
  4. A Windows-címtár
  5. Az aktuális munkakönyvtár (CWD)
  6. A PATH környezeti változóban felsorolt könyvtárak

                
Vegyük például a következő esetet:

  • Az alkalmazás anélkül tölt be egy DLL-t, hogy megadna egy teljesen minősített elérési utat, amelyet az alkalmazás CWD-jében várnak.
  • Az alkalmazás teljes mértékben fel van készülve az eset kezelésére, ha nem találja a DLL-t.
  • A támadó ismeri az alkalmazással kapcsolatos információkat, és felügyeli a CWD-t.
  • A támadó a DLL saját, speciálisan kialakított verzióját másolja a CWD-ben. Ehhez feltételezzük, hogy a támadó jogosult erre.
  • A Windows a DLL keresési sorrendjében keres a könyvtárakban, és megtalálja a DLL-t az alkalmazás CWD-fájljában.

Ebben az esetben a speciálisan kialakított DLL az alkalmazáson belül fut, és megszerzi az aktuális felhasználó jogosultságait.

Javaslat

A támadás megakadályozása érdekében az alkalmazások eltávolíthatják az aktuális munkakönyvtárat (CWD) a DLL keresési útvonalából a SetDllDirectory API üres karakterlánc ("") használatával történő hívásával. Ha egy alkalmazás DLL-t tölt be az aktuális könyvtárból, szerezze be az aktuális munkakönyvtárat, és használja azt a LoadLibrary teljes elérési útjának átadásához.

Tisztában vagyunk vele, hogy egyes fejlesztők a LoadLibrary használatával ellenőrzik, hogy megtalálható-e egy bizonyos DLL annak meghatározásához, hogy a Windows melyik verzióját futtatja a felhasználó. Vegye figyelembe, hogy ez sebezhetővé teheti az alkalmazást. Ha az érintett kódtár valóban nem létezik azon a Windows-kiadáson, amelyen az alkalmazást futtatják, a támadó ugyanazzal a nevű kódtárat nyithat meg a CWD-ben. Erősen javasoljuk, hogy ne használja ezt a technikát. Ehelyett használja "A rendszerverzió beszerzése" című MSDN-cikkben ismertetett javasolt módszereket.

Egy olyan alkalmazásnak, amely harmadik féltől származó beépülő modulokat tölt be, és nem tudja kényszeríteni a beépülő modulokat, hogy minősített elérési utat használjanak a LoadLibrary hívásaihoz, meg kell hívniuk a SetDllDirectory("") parancsot a CWD eltávolításához, majd meg kell hívniuk a SetDllDirectoryt ("plugin telepítési helye") a beépülő modul telepítési könyvtárának hozzáadásához a DLL keresési útvonalához.

SearchPath-alapú támadások

Hasonló támadás következik be, amikor egy alkalmazás a SearchPath API-t használja egy DLL megkeresésére, és dinamikusan betölti a SearchPath által visszaadott elérési utat. A SearchPath API keresési sorrendje a következő:

  • Az a könyvtár, ahonnan az alkalmazás betöltődött
  • Az aktuális munkakönyvtár (CWD)
  • A rendszerkönyvtár
  • A 16 bites rendszerkönyvtár
  • A Windows-címtár
  • A PATH környezeti változóban felsorolt könyvtárak

Ezt a mintát nem javasoljuk, mert nem biztonságos. Nem javasoljuk a SearchPath függvény használatát a .dll fájlok megkeresésére, ha a kimenet rendeltetése a LoadLibrary függvény hívásában történt. Ez a helytelen .dll fájl megkereséséhez vezethet, mert a SearchPath függvény keresési sorrendje eltér a LoadLibrary függvény által használt keresési sorrendtől. Ha meg kell keresnie és be kell töltenie egy .dll fájlt, használja a LoadLibrary függvényt.

ShellExecute és CreateProcess

E problémák változatai akkor is előfordulhatnak, ha a fejlesztők hasonló függvényeket, például a ShellExecute és a CreateProcess hívják meg a külső végrehajtható fájlok betöltése érdekében. Azt javasoljuk, hogy a fejlesztők legyenek körültekintően a bináris fájlok betöltésekor, és adják meg a teljesen minősített elérési utat. Ez kevésbé bonyolult, ha könyvtár helyett bináris fájlt tölt be.

Javasoljuk a fejlesztőknek, hogy tegyék meg az alábbiakat:

  • Ellenőrizze az alkalmazásokat a nem biztonságos könyvtárbetöltések előfordulásai szempontjából (ezekre a témakör későbbi részében talál példákat). Közéjük tartoznak például az alábbiak:

    • A SearchPath használata egy könyvtár vagy összetevő helyének azonosítására.
    • A LoadLibrary használata az operációs rendszer verziójának azonosítására.
  • Ahol csak lehet, használjon teljesen minősített elérési utakat az összes LoadLibrary-, CreateProcess és ShellExecute híváshoz.

  • A SetDllDirectory hívásainak megvalósítása üres karakterlánccal ("") az aktuális munkakönyvtár eltávolításához az alapértelmezett DLL-keresési sorrendből, ahol arra szükség van. Vegye figyelembe, hogy a SetDllDirectory művelet a teljes folyamatot befolyásolja. Ezért ezt egyszer kell megtennie a folyamat inicializálásának korai szakaszában, nem pedig a LoadLibrary hívásai előtt és után. Mivel a SetDllDirectory az egész folyamatot befolyásolja, a SetDllDirectoryt különböző értékekkel meghívó több szál meghatározatlan viselkedést okozhat. Emellett, ha a folyamat célja külső DLL-ek betöltése, tesztelésre lesz szükség annak megállapításához, hogy egy folyamatszintű beállítás végrehajtása okoz-e inkompatibilitást. Ismert probléma az, hogy amikor egy alkalmazás a Visual Basic for Applications alkalmazáson alapul, egy egész folyamatra kiterjedő beállítás inkompatibilitásokat okozhat.

  • A SetSearchPathMode függvénnyel engedélyezheti a biztonságos folyamatkeresési módot a folyamathoz. Ez a művelet a folyamat teljes élettartamára a SearchPath keresési listájának utolsó helyére helyezi az aktuális munkakönyvtárat.

  • Kerülje a SearchPath használatát a DLL meglétének ellenőrzésére a teljes elérési út megadása nélkül még akkor sem, ha a biztonságos keresési mód engedélyezve van, mivel ez akkor is DLL-előtelepítési támadásokhoz vezethet.

Útmutató a függvénytárak nem biztonságos betöltésének azonosításához

A forráskódban a következő példák találhatók a függvénytárak nem biztonságos betöltésére:

  • Az alábbi példakódban az alkalmazás a "schannel.dll" kifejezésre keres a legkevésbé biztonságos keresési útvonal használatával. Ha egy támadó el tud helyezni schannel.dll a CWD-ben, akkor az még azelőtt betöltődik, hogy az alkalmazás megkeresné a megfelelő könyvtárat a Windows könyvtáraiban.

    DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL); 
    HMODULE handle = LoadLibrary(result);
    
  • A következő példakódban az alkalmazás a dokumentum elején ismertetett különböző alkalmazás- és operációsrendszer-helyekről próbálja betölteni a könyvtárat a LoadLibrary() híváshoz. Ha fennáll a veszélye, hogy a fájl nincs jelen, az alkalmazás megpróbálhatja betölteni a fájlt az aktuális munkakönyvtárból. Ez a forgatókönyv valamivel kevésbé veszélyes, mint az előző példa. Azonban továbbra is kockázatnak teszi ki az alkalmazás felhasználóját, ha a környezet nem teljesen kiszámítható.

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

                
                
Az alábbiakban láthat példákat a könyvtárak jobb és biztonságosabb betöltésére:

  • Az alábbi példakódban a függvénytár közvetlenül betöltődik egy teljesen minősített elérési út használatával. Nincs annak veszélye, hogy a támadó rosszindulatú kódot visz be, kivéve, ha már rendelkezik írási engedélyekkel az alkalmazás célkönyvtárához.

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

    Megjegyzés: A rendszerkönyvtár meghatározásának módját a következő források tartalmazzák:

    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

  • Az alábbi példakódban a LoadLibrary meghívása előtt a rendszer eltávolítja az aktuális munkakönyvtárat a keresési útvonalból. Ez jelentősen csökkenti a kockázatot, mivel a támadónak vagy az alkalmazáskönyvtárat, a Windows könyvtárat vagy a felhasználó elérési útjában meghatározott könyvtárakat kell irányítania ahhoz, hogy DLL-előtelepítési támadást használhasson.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
  • A következő kód a biztonsági wwd-t véglegesen a keresési sorrend legutolsó helyére helyezi át az összes olyan rendszeren, amelyen telepítve van az 963027-as biztonsági frissítés. A SetSearchPathMode függvény későbbi hívásai, amelyek megpróbálják módosítani a keresési módot, sikertelenek lesznek.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
  • Az alábbi példakódban a LoadLibrary meghívása előtt a rendszer eltávolítja az aktuális munkakönyvtárat a keresési útvonalból. Ez jelentősen csökkenti a kockázatot, mivel a támadónak vagy az alkalmazáskönyvtárat, a Windows könyvtárat, vagy a felhasználó elérési útjában meghatározott könyvtárakat kell irányítania ahhoz, hogy DLL-előtelepítési támadást használhasson.

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

A nem biztonságos terhelések dinamikus észlelése a Folyamatfigyelő használatával

A Microsoft közzétett egy Folyamatfigyelő nevű eszközt. Ez az eszköz lehetővé teszi a fejlesztők és rendszergazdák számára, hogy szorosan nyomon kövessék egy futó folyamat viselkedését. A Folyamatfigyelő segítségével dinamikusan észlelhető, hogy egy alkalmazás sebezhető-e egy ilyen típusú problémának.

  • A Process Monitor letöltéséhez látogasson el a következő Microsoft weboldalra:
    http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

  • Próbálja meg elindítani az alkalmazást a CWD használatával, amely egy adott könyvtárra van beállítva. Kattintson például duplán egy olyan fájlra, amelynek a kiterjesztése hozzá van rendelve az alkalmazáshoz.

  • Állítsa be a Folyamatfigyelőt a következő szűrőkkel:

    371495f2-14de-f99c-c55a-f75d31fe9ca8

  • Ha sérülékeny elérési útvonalat észlel, az alábbihoz hasonló elemet fog látni: 9acdd1ae-29b9-e499-9de9-8bc665b95e76

     A távoli fájlmegosztás hívása egy DLL betöltéséhez azt jelzi, hogy ez egy sebezhető program.

További információ

További információért keresse fel a Microsoft alábbi weblapjait:

Dinamikus csatolású függvénytár keresési sorrendje

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx MSDN-dokumentáció a SearchPath függvényről

http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx MSDN-dokumentáció a LoadLibrary függvényről

http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx MSDN-dokumentáció a SetDllDirectory függvényről

http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx MSDN-dokumentáció a SetSearchPathMode függvényről

http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx David Leblanc, a Microsoft Office vezető biztonsági mérnökének blogbejegyzése

http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx Andrew Roths, az MSRC mérnöki csapatának blogbejegyzése a DLL-előtöltési támadásokról

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

További erőforrások