Bezpieczne ładowanie bibliotek w celu zapobiegania atakom ładowania wstępnego biblioteki DLL

Pomoc techniczna dla systemu Windows Vista z dodatkiem Service Pack 1 (SP1) kończy się 12 lipca 2011 r. Aby nadal otrzymywać aktualizacje zabezpieczeń dla systemu Windows, upewnij się, że korzystasz z systemu Windows Vista z dodatkiem Service Pack 2 (SP2). Aby uzyskać więcej informacji, zobacz tę stronę internetową firmy Microsoft: Pomoc techniczna dla niektórych wersji systemu Windows kończy się.

Gdy aplikacja dynamicznie ładuje bibliotekę linków dynamicznych (DLL) bez określania w pełni kwalifikowanej ścieżki, system Windows próbuje zlokalizować bibliotekę DLL, wyszukując dobrze zdefiniowany zestaw katalogów. Jeśli osoba atakująca zyska kontrolę nad jednym z katalogów, może wymusić załadowanie przez aplikację złośliwej kopii biblioteki DLL zamiast oczekiwanej biblioteki DLL. Te ataki są nazywane "atakami wstępnego ładowania bibliotek DLL" i są wspólne dla wszystkich systemów operacyjnych obsługujących dynamiczne ładowanie udostępnionych bibliotek DLL. Skutkiem takich ataków może być to, że osoba atakująca może wykonać kod w kontekście użytkownika, który uruchamia aplikację. Gdy aplikacja jest uruchamiana jako administrator, może to prowadzić do lokalnego podwyższenia uprawnień. Wiemy o ponownym zainteresowaniu tymi atakami. Aby ograniczyć wpływ tego problemu na naszych wspólnych klientów, udostępniamy ten dokument społeczności deweloperów, aby upewnić się, że wiedzą o tym problemie i mają niezbędne narzędzia do rozwiązania tego problemu w swoich aplikacjach.

Podsumowanie

Opis ataków ładowania wstępnego biblioteki DLL

Ataki typu LoadLibrary

Gdy aplikacja dynamicznie ładuje bibliotekę DLL bez określania w pełni kwalifikowanej ścieżki, system Windows próbuje zlokalizować tę bibliotekę DLL, wyszukując ją liniowo za pomocą dobrze zdefiniowanego zestawu katalogów, nazywanego kolejnością wyszukiwania bibliotek DLL. Jeśli system Windows znajdzie bibliotekę DLL w ramach kolejności wyszukiwania bibliotek DLL, załaduje tę bibliotekę DLL. Jeśli jednak system Windows nie znajdzie biblioteki DLL w żadnym z katalogów w kolejności wyszukiwania bibliotek DLL, zwróci niepowodzenie operacji ładowania biblioteki DLL. Poniżej przedstawiono kolejność wyszukiwania bibliotek DLL dla funkcji LoadLibrary i LoadLibraryEx , które służą do dynamicznego ładowania bibliotek DLL:

  1. Katalog, z którego aplikacja została załadowana
  2. Katalog systemowy
  3. 16-bitowy katalog systemowy
  4. Katalog systemu Windows
  5. Bieżący katalog roboczy (CWD)
  6. Katalogi wymienione w zmiennej środowiskowej PATH

                
Rozważmy następujący scenariusz:

  • Aplikacja ładuje bibliotekę DLL bez określania w pełni kwalifikowanej ścieżki, którą oczekuje się znaleźć w CWD aplikacji.
  • Aplikacja jest w pełni przygotowana do obsługi sprawy, gdy nie znajduje biblioteki DLL.
  • Osoba atakująca zna te informacje na temat aplikacji i kontroluje CWD.
  • Osoba atakująca kopiuje własną specjalnie spreparowaną wersję biblioteki DLL w CWD. Założono, że osoba atakująca ma do tego uprawnienia.
  • System Windows przeszukuje katalogi w kolejności wyszukiwania bibliotek DLL i znajduje bibliotekę DLL w cwd aplikacji.

W tym scenariuszu specjalnie spreparowana biblioteka DLL działa w aplikacji i uzyskuje uprawnienia bieżącego użytkownika.

Zalecenie

Aby zapobiec temu atakowi, aplikacje mogą usunąć bieżący katalog roboczy (CWD) ze ścieżki wyszukiwania DLL, wywołując interfejs API SetDllDirectory, używając pustego ciągu (""). Jeśli aplikacja zależy od ładowania biblioteki DLL z bieżącego katalogu, uzyskaj bieżący katalog roboczy i użyj go, aby przejść w pełni kwalifikowaną ścieżkę loadlibrary.

Wiemy również, że niektórzy deweloperzy używają funkcji LoadLibrary do sprawdzania, czy określona biblioteka DLL jest obecna, aby określić, która wersja systemu Windows jest uruchamiana przez użytkownika. Należy pamiętać, że może to spowodować narażenie aplikacji. Jeśli biblioteka, którego dotyczy problem, rzeczywiście nie istnieje w wersji systemu Windows, w którym aplikacja jest wykonywana, osoba atakująca może wprowadzić bibliotekę o tej samej nazwie do CWD. Zdecydowanie zalecamy, aby nie używać tej techniki. Zamiast tego użyj zalecanych technik opisanych w artykule MSDN "Pobieranie wersji systemu".

Aplikacja ładująca wtyczki innych firm, która nie może wymusić użycia przez wtyczki odpowiedniej ścieżki do wywołań LoadLibrary, powinna wywołać polecenie SetDllDirectory(""), aby usunąć cwd, a następnie wywołać SetDllDirectory("lokalizacja instalacji wtyczki"), aby dodać katalog instalacji wtyczki do ścieżki wyszukiwania biblioteki DLL.

Ataki oparte na funkcji SearchPath

Podobny atak występuje, gdy aplikacja używa interfejsu API SearchPath do zlokalizowania biblioteki DLL i dynamicznego ładowania ścieżki zwracanej przez program SearchPath. Poniżej przedstawiono domyślną kolejność wyszukiwania interfejsu API programu SearchPath:

  • Katalog, z którego aplikacja została załadowana
  • Bieżący katalog roboczy (CWD)
  • Katalog systemowy
  • 16-bitowy katalog systemowy
  • Katalog systemu Windows
  • Katalogi wymienione w zmiennej środowiskowej PATH

Nie zalecamy tego wzorca, ponieważ nie jest bezpieczny. Nie zalecamy funkcji SearchPath jako metody lokalizowania pliku .dll, jeśli zamierzone użycie danych wyjściowych jest wywołaniem funkcji LoadLibrary. Może to spowodować zlokalizowanie nieprawidłowego pliku .dll, ponieważ kolejność wyszukiwania funkcji SearchPath różni się od kolejności wyszukiwania używanej przez funkcję LoadLibrary. Jeśli musisz zlokalizować i załadować plik .dll, użyj funkcji LoadLibrary.

ShellExecute i CreateProcess

Odmiany tych problemów mogą również występować, gdy deweloperzy wywołają podobne funkcje, takie jak ShellExecute i CreateProcess w celu załadowania zewnętrznych plików wykonywalnych. Zalecamy, aby deweloperzy zachowali ostrożność podczas ładowania plików binarnych i określili w pełni kwalifikowaną ścieżkę. Powinno to stanowić mniejszą złożoność podczas ładowania pliku binarnego zamiast biblioteki.

Zalecamy, aby deweloperzy wykonali następujące czynności:

  • Sprawdź poprawność ich aplikacji pod kątem wystąpień ładowania biblioteki niezabezpieczonej (przykłady z nich podano w dalszej części tego artykułu). Są to między innymi poniższe typy plików:

    • Używanie programu SearchPath do identyfikowania lokalizacji biblioteki lub składnika.
    • Użycie funkcji LoadLibrary do identyfikowania wersji systemu operacyjnego.
  • Użyj w pełni kwalifikowanych ścieżek dla wszystkich wywołań loadlibrary, CreateProcess i ShellExecute tam, gdzie możesz.

  • Zaimplementuj wywołania do witryny SetDllDirectory z pustym ciągiem (""), aby usunąć bieżący katalog roboczy z domyślnej kolejności wyszukiwania DLL, jeśli jest to wymagane. Pamiętaj, że funkcja SetDllDirectory wpływa na cały proces. Dlatego należy to zrobić jednorazowo na wczesnym etapie inicjowania procesu, a nie przed i po wywołania loadlibrary. Ponieważ polecenie SetDllDirectory wpływa na cały proces, wiele wątków wywołujących polecenie SetDllDirectory z różnymi wartościami może powodować niezdefiniowane zachowanie. Ponadto, jeśli proces jest przeznaczony do ładowania bibliotek DLL innych firm, konieczne będzie przetestowanie w celu ustalenia, czy ustawienie dla całego procesu spowoduje niezgodność. Znany problem polega na tym, że gdy aplikacja zależy od Visual Basic for Applications, ustawienie dla całego procesu może powodować niezgodność.

  • Użyj funkcji SetSearchPathMode , aby włączyć tryb wyszukiwania bezpiecznego procesu dla tego procesu. Spowoduje to przeniesienie bieżącego katalogu roboczego do ostatniego miejsca na liście wyszukiwania programu SearchPath przez cały okres istnienia procesu.

  • Unikaj używania programu SearchPath do sprawdzania istnienia biblioteki DLL bez określania w pełni kwalifikowanej ścieżki, nawet jeśli jest włączony tryb bezpiecznego wyszukiwania, ponieważ może to nadal prowadzić do ataków ładowania wstępnego bibliotek DLL.

Wskazówki dotyczące identyfikowania obciążeń bibliotek niezabezpieczonych

W kodzie źródłowym poniżej przedstawiono przykłady ładowania bibliotek niezabezpieczonych:

  • W poniższym przykładzie kodu aplikacja wyszukuje ciąg "schannel.dll" przy użyciu najmniej bezpiecznej ścieżki wyszukiwania. Jeśli osoba atakująca może umieścić schannel.dll w CWD, zostanie załadowana jeszcze przed wyszukaniem odpowiedniej biblioteki w katalogach systemu Windows przez aplikację.

    DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL); 
    HMODULE handle = LoadLibrary(result);
    
  • W poniższym przykładzie kodu aplikacja próbuje załadować bibliotekę z różnych lokalizacji aplikacji i systemu operacyjnego opisanych na początku tego dokumentu dla wywołania LoadLibrary(). Jeśli istnieje jakiekolwiek ryzyko, że plik nie jest obecny, aplikacja może spróbować załadować plik z bieżącego katalogu roboczego. Ten scenariusz jest nieco mniej niebezpieczny niż w poprzednim przykładzie. Jednak nadal naraża użytkownika aplikacji na ryzyko, jeśli środowisko nie jest całkowicie przewidywalne.

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

                
                
Poniżej przedstawiono przykłady lepszych i bezpieczniejszych ładów bibliotek:

  • W poniższym przykładzie kodu biblioteka jest ładowana bezpośrednio przy użyciu w pełni kwalifikowanej ścieżki. Nie ma ryzyka, że osoba atakująca wprowadzi złośliwy kod, chyba że ma już uprawnienia do zapisu w katalogu docelowym aplikacji.

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

    Uwaga Aby uzyskać informacje na temat określania katalogu systemowego, zobacz następujące zasoby:

    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

  • W poniższym przykładzie kodu bieżący katalog roboczy jest usuwany ze ścieżki wyszukiwania przed wywołaniem LoadLibrary. To znacznie zmniejsza ryzyko, ponieważ osoba atakująca musiałaby kontrolować katalog aplikacji, katalog systemu Windows lub wszelkie katalogi określone na ścieżce użytkownika w celu użycia ataku ładowania wstępnego biblioteki DLL.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
  • We wszystkich systemach z zainstalowaną aktualizacją zabezpieczeń 963027 (opisanej w ms09-014) poniższy kod trwale przenosił cwd na ostatnie miejsce w kolejności wyszukiwania. Wszystkie późniejsze wywołania funkcji SetSearchPathMode z wewnątrz tego procesu, które próbują zmienić tryb wyszukiwania, nie powiedzie się.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
  • W poniższym przykładzie kodu bieżący katalog roboczy jest usuwany ze ścieżki wyszukiwania przed wywołaniem LoadLibrary. Znacznie zmniejsza to ryzyko, ponieważ osoba atakująca musiałaby kontrolować katalog aplikacji, katalog systemu Windows lub wszelkie katalogi określone na ścieżce użytkownika w celu użycia ataku ładowania wstępnego biblioteki DLL.

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

Dynamiczne wykrywanie obciążeń niezabezpieczonych za pomocą monitora procesu

Firma Microsoft publikuje narzędzie o nazwie Monitor procesu. To narzędzie umożliwia deweloperom i administratorom śledzenie zachowania uruchomionego procesu. Monitor procesu może być używany do dynamicznego wykrywania, czy jedna z aplikacji może być narażona na tego rodzaju problemy.

  • Aby pobrać monitor procesu, odwiedź następującą stronę internetową firmy Microsoft:
    http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

  • Spróbuj uruchomić aplikację, używając zestawu CWD do określonego katalogu. Na przykład kliknij dwukrotnie plik z rozszerzeniem, którego program obsługi plików jest przypisany do aplikacji.

  • Skonfiguruj monitor procesu za pomocą następujących filtrów:

    371495f2-14de-f99c-c55a-f75d31fe9ca8

  • Jeśli zostanie natkniętą ścieżkę, zobaczysz coś podobnego do następującego: 9acdd1ae-29b9-e499-9de9-8bc665b95e76

     Wywołanie zdalnego udziału plików w celu załadowania biblioteki DLL wskazuje, że jest to program podatny na zagrożenia.

Więcej informacji

Aby uzyskać więcej informacji, odwiedź następujące strony internetowe firmy Microsoft:

Kolejność wyszukiwania w bibliotece linków dynamicznych

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx Dokumentacja msdn w funkcji SearchPath

http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx Dokumentacja MSDN dotycząca funkcji LoadLibrary

http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx Dokumentacja msdn w funkcji SetDllDirectory

http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx Dokumentacja MSDN dotycząca funkcji SetSearchPathMode

http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx Wpis w blogu Davida Leblanca, głównego inżyniera zabezpieczeń w pakiecie Microsoft Office

http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx Wpis na blogu Andrew Rothsa, zespołu inżynierów MSRC na temat ataków ładowania wstępnego DLL

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

Dodatkowe zasoby