Безопасная загрузка библиотек для предотвращения атак предварительной загрузки БИБЛИОТЕК DLL

Поддержка Windows Vista с пакетом обновления 1 (SP1) заканчивается 12 июля 2011 г. Чтобы продолжить получать обновления для системы безопасности для Windows, убедитесь, что вы используете Windows Vista с пакетом обновления 2 (SP2). Дополнительные сведения см. на этой веб-странице Майкрософт: Поддержка некоторых версий Windows заканчивается.

Когда приложение динамически загружает библиотеку динамической компоновки (DLL) без указания полного пути, Windows пытается найти библиотеку DLL, выполнив поиск в четко определенном наборе каталогов. Если злоумышленник получает контроль над одним из каталогов, он может заставить приложение загрузить вредоносную копию библиотеки DLL вместо библиотеки DLL, которую он ожидал. Эти атаки называются "атаками предварительной загрузки DLL" и являются общими для всех операционных систем, поддерживающих динамическая загрузка общих библиотек DLL. Результатом таких атак может быть то, что злоумышленник может выполнить код в контексте пользователя, который запускает приложение. Если приложение запускается от имени администратора, это может привести к локальному повышению привилегий. Мы знаем о возобновлении интереса к этим атакам. Чтобы ограничить влияние этой проблемы на наших общих клиентов, мы выпускаем этот документ сообществу разработчиков, чтобы убедиться, что они знают об этой проблеме и имеют необходимые инструменты для решения этой проблемы в своих приложениях.

Сводка

Описание атак предварительной загрузки DLL

Атаки на основе LoadLibrary

Когда приложение динамически загружает библиотеку DLL без указания полного пути, Windows пытается найти эту библиотеку DLL путем линейного поиска по четко определенному набору каталогов, известному как порядок поиска DLL. Если Windows находит библиотеку DLL в порядке поиска DLL, она загрузит ее. Однако если Windows не находит библиотеку DLL ни в одном из каталогов в порядке поиска DLL, она вернет ошибку операции загрузки DLL. Ниже приведен порядок поиска DLL для функций LoadLibrary и LoadLibraryEx , которые используются для динамической загрузки библиотек DLL.

  1. Каталог, из которого загружено приложение
  2. Системный каталог
  3. 16-разрядный системный каталог
  4. Каталог Windows
  5. Текущий рабочий каталог (CWD)
  6. Каталоги, перечисленные в переменной среды PATH

                
Рассмотрим следующий сценарий.

  • Приложение загружает библиотеку DLL, не указывая полный путь, который он ожидает найти в CWD приложения.
  • Приложение полностью готово к обработке случая, когда оно не находит библиотеку DLL.
  • Злоумышленник знает эти сведения о приложении и управляет CWD.
  • Злоумышленник копирует собственную специально созданную версию библиотеки DLL в CWD. При этом предполагается, что у злоумышленника есть разрешение на это.
  • Windows выполняет поиск по каталогам в порядке поиска DLL и находит библиотеку DLL в CWD приложения.

В этом сценарии специально созданная библиотека DLL выполняется в приложении и получает права текущего пользователя.

Рекомендации

Чтобы предотвратить эту атаку, приложения могут удалить текущий рабочий каталог (CWD) из пути поиска DLL, вызвав API SetDllDirectory с помощью пустой строки (""). Если приложение зависит от загрузки библиотеки DLL из текущего каталога, получите текущий рабочий каталог и используйте его для передачи полного пути LoadLibrary.

Мы также знаем, что некоторые разработчики используют LoadLibrary для проверки наличия определенной библиотеки DLL, чтобы определить, какая версия Windows запускается пользователем. Следует помнить, что это может сделать приложение уязвимым. Если затронутая библиотека действительно не существует в выпуске Windows, в который выполняется приложение, злоумышленник может ввести библиотеку с таким же именем в CWD. Мы настоятельно не рекомендуем использовать этот метод. Вместо этого используйте рекомендуемые методы, описанные в статье MSDN "Получение версии системы".

Приложение, которое загружает сторонние подключаемые модули и которое не может заставить подключаемые модули использовать полный путь для вызовов LoadLibrary, должно вызвать SetDllDirectory(""), чтобы удалить CWD, а затем вызвать SetDllDirectory("расположение установки подключаемого модуля"), чтобы добавить каталог установки подключаемого модуля в путь поиска DLL.

Атаки на основе SearchPath

Аналогичная атака возникает, когда приложение использует API SearchPath для поиска библиотеки DLL и динамической загрузки пути, возвращаемого SearchPath. Ниже приведен порядок поиска по умолчанию для API SearchPath.

  • Каталог, из которого загружено приложение
  • Текущий рабочий каталог (CWD)
  • Системный каталог
  • 16-разрядный системный каталог
  • Каталог Windows
  • Каталоги, перечисленные в переменной среды PATH

Мы не рекомендуем использовать этот шаблон, так как он не является безопасным. Мы не рекомендуем использовать функцию SearchPath в качестве метода поиска .dll файла, если целевое использование выходных данных выполняется в вызове функции LoadLibrary. Это может привести к поиску неправильного .dll файла, так как порядок поиска функции SearchPath отличается от порядка поиска, используемого функцией LoadLibrary. Если вам нужно найти и загрузить файл .dll, используйте функцию LoadLibrary.

ShellExecute и CreateProcess

Варианты этих проблем также могут возникать, когда разработчики вызывают аналогичные функции, такие как ShellExecute и CreateProcess , для загрузки внешних исполняемых файлов. Мы рекомендуем разработчикам быть осторожными при загрузке двоичных файлов и указывать полный путь. Это должно быть менее сложно при загрузке двоичного файла вместо библиотеки.

Рекомендуется, чтобы разработчики сделали следующее:

  • Проверьте свои приложения на наличие экземпляров небезопасных загрузок библиотеки (примеры каждого из них приведены далее в этой статье). В том числе следующие:

    • Использование SearchPath для определения расположения библиотеки или компонента.
    • Использование LoadLibrary для определения версии операционной системы.
  • Используйте полные пути для всех вызовов LoadLibrary, CreateProcess и ShellExecute, где это возможно.

  • Реализуйте вызовы SetDllDirectory с пустой строкой (""), чтобы удалить текущий рабочий каталог из порядка поиска DLL по умолчанию, где это необходимо. Имейте в виду, что SetDllDirectory влияет на весь процесс. Поэтому это следует делать один раз на ранней стадии инициализации процесса, а не до и после вызовов LoadLibrary. Так как SetDllDirectory влияет на весь процесс, несколько потоков, вызывающих SetDllDirectory с разными значениями, могут привести к неопределенному поведению. Кроме того, если процесс предназначен для загрузки сторонних библиотек DLL, потребуется тестирование, чтобы определить, приведет ли создание параметра для всего процесса к несовместимости. Известная проблема заключается в том, что, когда приложение зависит от Visual Basic для приложений, параметр для всего процесса может привести к несовместимости.

  • Используйте функцию SetSearchPathMode , чтобы включить безопасный режим поиска процесса. При этом текущий рабочий каталог перемещается в последнее место в списке поиска SearchPath на время существования процесса.

  • Избегайте использования SearchPath для проверка существования библиотеки DLL, не указывая полный путь, даже если включен безопасный режим поиска, так как это по-прежнему может привести к атакам предварительной загрузки DLL.

Руководство по выявлению небезопасных нагрузок библиотеки

В исходном коде ниже приведены примеры загрузки небезопасной библиотеки:

  • В следующем примере кода приложение выполняет поиск по запросу "schannel.dll", используя наименее безопасный путь поиска. Если злоумышленник может поместить schannel.dll в CWD, он загрузится еще до того, как приложение выполнит поиск соответствующей библиотеки в каталогах Windows.

    DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL); 
    HMODULE handle = LoadLibrary(result);
    
  • В следующем примере кода приложение пытается загрузить библиотеку из различных расположений приложений и операционных систем, описанных в начале этого документа для вызова LoadLibrary(). Если существует риск того, что файл отсутствует, приложение может попытаться загрузить файл из текущего рабочего каталога. Этот сценарий немного менее опасен, чем предыдущий пример. Однако он по-прежнему подвергает пользователя приложения риску, если среда не полностью предсказуема.

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

                
                
Ниже приведены примеры более безопасных загрузок библиотек.

  • В следующем примере кода библиотека загружается напрямую по полному пути. Злоумышленник не рискует внедрить вредоносный код, если у него еще нет разрешений на запись в целевой каталог приложения.

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

    Примечание. Сведения об определении системного каталога см. в следующих ресурсах:

    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

  • В следующем примере кода текущий рабочий каталог удаляется из пути поиска перед вызовом LoadLibrary. Это значительно снижает риск, так как злоумышленнику придется управлять каталогом приложения, каталогом Windows или любыми каталогами, указанными в пути пользователя, чтобы использовать атаку предварительной загрузки DLL.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
  • Во всех системах, в которых установлено обновление для системы безопасности 963027 (описано в ms09-014), приведенный ниже код окончательно перемещает CWD в самое последнее место в порядке поиска. Все последующие вызовы функции SetSearchPathMode из этого процесса, которые пытаются изменить режим поиска, завершаются ошибкой.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
  • В следующем примере кода текущий рабочий каталог удаляется из пути поиска перед вызовом LoadLibrary. Это значительно снижает риск, так как злоумышленнику придется управлять каталогом приложения, каталогом Windows или любыми каталогами, указанными в пути пользователя, чтобы использовать атаку предварительной загрузки DLL.

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

Использование монитора процессов для динамического обнаружения небезопасных нагрузок

Корпорация Майкрософт публикует средство с именем Монитор процессов. Это средство позволяет разработчикам и администраторам внимательно отслеживать поведение выполняющегося процесса. Монитор процессов можно использовать для динамического определения уязвимости одного из ваших приложений к проблеме такого рода.

  • Чтобы скачать монитор процессов, посетите следующую веб-страницу Майкрософт:
    http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

  • Попробуйте запустить приложение с помощью параметра CWD, заданного для определенного каталога. Например, дважды щелкните файл с расширением, обработчик которого назначен приложению.

  • Настройте монитор процессов со следующими фильтрами:

    371495f2-14de-f99c-c55a-f75d31fe9ca8

  • При попадании на уязвимый путь вы увидите примерно следующее: 9acdd1ae-29b9-e499-9de9-8bc665b95e76

     Вызов удаленного файлового ресурса для загрузки библиотеки DLL указывает на то, что это уязвимая программа.

Дополнительные сведения

Дополнительные сведения см. на следующих веб-страницах Майкрософт:

Порядок поиска динамической библиотеки ссылок

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx Документация MSDN по функции SearchPath

http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx Документация MSDN по функции LoadLibrary

http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx Документация MSDN по функции SetDllDirectory

http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx Документация MSDN по функции SetSearchPathMode

http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx Запись блога Дэвида Леблана (David Leblanc), главного инженера по безопасности в Microsoft Office

http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx Запись блога Эндрю Ротса (Andrew Roths), инженерная группа MSRC по атакам предварительной загрузки DLL

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

Дополнительные ресурсы