Carga segura de bibliotecas para evitar ataques de precarga de DLL

El soporte técnico para Windows Vista Service Pack 1 (SP1) termina el 12 de julio de 2011. Para seguir recibiendo actualizaciones de seguridad para Windows, asegúrese de ejecutar Windows Vista con Service Pack 2 (SP2). Para obtener más información, consulta esta página web de Microsoft: el soporte está finalizando para algunas versiones de Windows.

Cuando una aplicación carga dinámicamente una biblioteca de vínculos dinámicos (DLL) sin especificar una ruta de acceso completa, Windows intenta localizar la DLL buscando un conjunto de directorios bien definido. Si un atacante obtiene el control de uno de los directorios, pueden obligar a la aplicación a cargar una copia malintencionada de la DLL en lugar de la DLL que esperaba. Estos ataques se conocen como "ataques de precarga de DLL" y son comunes a todos los sistemas operativos que admiten la carga dinámica de bibliotecas de DLL compartidas. El efecto de estos ataques podría ser que un atacante puede ejecutar código en el contexto del usuario que está ejecutando la aplicación. Cuando la aplicación se ejecuta como administrador, esto podría conducir a una elevación local de privilegios. Sabemos de un interés renovado en estos ataques. Para limitar el efecto que este problema tiene en nuestros clientes mutuos, publicamos este documento para la comunidad de desarrolladores para asegurarnos de que conocen este problema y tienen las herramientas necesarias para abordar el problema en sus aplicaciones.

Resumen

Descripción de ataques de precarga de DLL

Ataques basados en LoadLibrary

Cuando una aplicación carga dinámicamente un archivo DLL sin especificar una ruta de acceso completa, Windows intenta localizar este archivo DLL mediante la búsqueda lineal a través de un conjunto bien definido de directorios, conocido como orden de búsqueda de DLL. Si Windows localiza el archivo DLL dentro del orden de búsqueda de DLL, cargará ese archivo DLL. Sin embargo, si Windows no encuentra el archivo DLL en ninguno de los directorios en el orden de búsqueda de DLL, devolverá un error a la operación de carga de DLL. A continuación se muestra el orden de búsqueda de DLL para las funciones LoadLibrary y LoadLibraryEx , que se usan para cargar archivos DLL dinámicamente:

  1. El directorio desde el que se cargó la aplicación
  2. El directorio del sistema
  3. El directorio del sistema de 16 bits
  4. El directorio Windows
  5. El directorio de trabajo actual (CWD)
  6. Directorios enumerados en la variable de entorno PATH

                
Tenga en cuenta el siguiente escenario:

  • Una aplicación carga un ARCHIVO DLL sin especificar una ruta de acceso completa que espera encontrar en el CWD de la aplicación.
  • La aplicación está totalmente preparada para manejar el caso cuando no encuentra el archivo DLL.
  • El atacante conoce esta información sobre la aplicación y controla el CWD.
  • El atacante copia su propia versión especialmente elaborada de la DLL en el CWD. Esto supone que el atacante tiene permiso para hacer esto.
  • Windows busca a través de los directorios en el orden de búsqueda de DLL y encuentra el ARCHIVO DLL en el CWD de la aplicación.

En este escenario, el DLL especialmente diseñado se ejecuta dentro de la aplicación y obtiene los privilegios del usuario actual.

Recomendación

Para evitar este ataque, las aplicaciones pueden quitar el directorio de trabajo actual (CWD) de la ruta de búsqueda de DLL llamando a la API SetDllDirectory mediante una cadena vacía (""). Si una aplicación depende de la carga de un ARCHIVO DLL desde el directorio actual, por favor obtenga el directorio de trabajo actual y utilice eso para pasar en una ruta de acceso completa de LoadLibrary.

También somos conscientes de que algunos desarrolladores utilizan LoadLibrary para validar si una DLL específica está presente con el fin de determinar qué versión de Windows está ejecutando el usuario. Usted debe ser consciente de que esto podría hacer que la aplicación vulnerable. Si la biblioteca afectada realmente no existe en la versión de Windows en la que se ejecuta la aplicación, un atacante podría introducir una biblioteca con el mismo nombre en CWD. Recomendamos encarecidamente no usar esta técnica. En su lugar, use las técnicas recomendadas que se describen en el artículo de MSDN"Obtener la versión del sistema".

Una aplicación que carga complementos de terceros y que no puede obligar a los complementos a usar una ruta de acceso cualificada para su LoadLibrary llamadas debe llamar a SetDllDirectory("") para quitar CWD y, a continuación, llamar a SetDllDirectory("plugin install location") para agregar el directorio de instalación de complementos a la ruta de acceso de búsqueda de DLL.

Ataques basados en SearchPath

Existe un ataque similar cuando una aplicación usa la API de SearchPath para buscar un archivo DLL y cargar dinámicamente la ruta de acceso devuelta por SearchPath. El siguiente es el orden de búsqueda predeterminado para la API de SearchPath:

  • El directorio desde el que se cargó la aplicación
  • El directorio de trabajo actual (CWD)
  • El directorio del sistema
  • El directorio del sistema de 16 bits
  • El directorio Windows
  • Directorios enumerados en la variable de entorno PATH

No recomendamos este patrón porque no es seguro. No se recomienda la función SearchPath como método para localizar un archivo de .dll si el uso previsto de la salida se encuentra en una llamada a la función LoadLibrary. Esto puede resultar en encontrar el archivo de .dll incorrecto porque el orden de búsqueda de la función SearchPath difiere del orden de búsqueda usado por la LoadLibrary función. Si tiene que buscar y cargar un archivo de .dll, use la función LoadLibrary.

ShellExecute y CreateProcess

También pueden existir variaciones de estos problemas cuando los desarrolladores llaman a funciones similares, como ShellExecute y CreateProcess , para cargar ejecutables externos. Recomendamos que los desarrolladores tengan cuidado al cargar archivos binarios y especifiquen la ruta de acceso completa. Esto debería suponer menos complejidad al cargar un archivo binario en lugar de una biblioteca.

Se recomienda que los desarrolladores realicen lo siguiente:

  • Valide sus aplicaciones para instancias de cargas de bibliotecas no seguras (se indican ejemplos de cada una más adelante en este artículo). Entre ellas, figuran:

    • El uso de SearchPath para identificar la ubicación de una biblioteca o un componente.
    • El uso de LoadLibrary para identificar la versión del sistema operativo.
  • Use rutas de acceso completas para todas las llamadas a LoadLibrary, CreateProcess y ShellExecute donde pueda.

  • Implemente llamadas a SetDllDirectory con una cadena vacía ("") para quitar el directorio de trabajo actual del orden de búsqueda predeterminado de DLL donde es necesario. Tenga en cuenta que SetDllDirectory afecta a todo el proceso. Por lo tanto, debe hacerlo una vez antes de la inicialización del proceso, no antes y después de las llamadas a LoadLibrary. Como SetDllDirectory afecta a todo el proceso, varios subprocesos que llamen a SetDllDirectory con valores diferentes podrían provocar un comportamiento no definido. Además, si el proceso está diseñado para cargar DLL de terceros, se necesitarán pruebas para determinar si establecer una configuración de todo el proceso provocará incompatibilidades. Un problema conocido es que, cuando una aplicación depende de Visual Basic para Aplicaciones, una configuración de todo el proceso puede causar incompatibilidades.

  • Use la función SetSearchPathMode para habilitar el modo de búsqueda de procesos seguros para el proceso. Esto mueve el directorio de trabajo actual al último lugar de la lista de búsqueda de SearchPath durante la vigencia del proceso.

  • Evite usar SearchPath para comprobar la existencia de un archivo DLL sin especificar una ruta de acceso completa, incluso si el modo de búsqueda seguro está habilitado, ya que esto puede provocar ataques de precarga de DLL.

Instrucciones para identificar cargas de bibliotecas no seguras

En el código fuente, a continuación se muestran ejemplos de cargas de bibliotecas no seguras:

  • En el siguiente ejemplo de código, la aplicación busca "schannel.dll" mediante la ruta de búsqueda menos segura. Si un atacante puede colocar schannel.dll en CWD, se cargará incluso antes de que la aplicación busque en los directorios de Windows la biblioteca adecuada.

    DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL); 
    HMODULE handle = LoadLibrary(result);
    
  • En el ejemplo de código siguiente, la aplicación intenta cargar la biblioteca desde las distintas ubicaciones de la aplicación y del sistema operativo descritas al principio de este documento para la llamada LoadLibrary(). Si hay algún riesgo de que el archivo no esté presente, la aplicación puede intentar cargar el archivo desde el directorio de trabajo actual. Este escenario es ligeramente menos peligroso que el ejemplo anterior. Sin embargo, sigue exponiendo al usuario de la aplicación al riesgo si el entorno no es completamente predecible.

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

                
                
A continuación se muestran ejemplos de cargas de biblioteca mejores y seguras:

  • En el siguiente ejemplo de código, la biblioteca se carga directamente mediante una ruta de acceso completa. No hay ningún riesgo de que el atacante introduzca código malintencionado a menos que ya tenga permisos de escritura en el directorio de destino de la aplicación.

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

    Nota Para obtener información sobre cómo determinar el directorio del sistema, consulte los siguientes recursos:

    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

  • En el ejemplo de código siguiente, el directorio de trabajo actual se quita de la ruta de búsqueda antes de llamar a LoadLibrary. Esto reduce significativamente el riesgo, ya que el atacante tendría que controlar el directorio de la aplicación, el directorio de Windows o cualquier directorio que se especifique en la ruta del usuario con el fin de utilizar un ataque de precarga de DLL.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
  • En todos los sistemas que han instalado la actualización de seguridad 963027 (descrita en MS09-014), el siguiente código movería permanentemente CWD al último lugar en el orden de búsqueda. Se producirá un error en las llamadas posteriores a la función SetSearchPathMode desde dentro de ese proceso que intenten cambiar el modo de búsqueda.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
  • En el ejemplo de código siguiente, el directorio de trabajo actual se quita de la ruta de búsqueda antes de llamar a LoadLibrary. Esto reduce significativamente el riesgo, ya que el atacante tendría que controlar el directorio de la aplicación, el directorio de windows o cualquier directorio que se especifique en la ruta del usuario con el fin de utilizar un ataque de precarga de DLL.

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

Usar el Monitor de proceso para detectar dinámicamente cargas no seguras

Microsoft publica una herramienta denominada Monitor de proceso. Esta herramienta permite a los desarrolladores y administradores realizar un seguimiento detallado del comportamiento de un proceso en ejecución. El monitor de proceso se puede usar para detectar dinámicamente si una de las aplicaciones puede ser vulnerable a este tipo de problema.

  • Para descargar el Monitor de proceso, visita la siguiente página web de Microsoft:
    http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

  • Intente iniciar la aplicación utilizando CWD establecido en un directorio específico. Por ejemplo, haga doble clic en un archivo que tiene una extensión cuyo controlador de archivos está asignado a la aplicación.

  • Configure el Monitor de proceso con los filtros siguientes:

    371495f2-14de-f99c-c55a-f75d31fe9ca8

  • Si se encuentra en una ruta vulnerable, verá algo similar a lo siguiente: 9acdd1ae-29b9-e499-9de9-8bc665b95e76

     La llamada al recurso compartido de archivos remoto para cargar un archivo DLL indica que se trata de un programa vulnerable.

Más información

Para obtener más información, visita las siguientes páginas web de Microsoft:

Orden de búsqueda de biblioteca de vínculos dinámicos

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx Documentación de MSDN sobre la función SearchPath

http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx Documentación de MSDN sobre la función LoadLibrary

http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx Documentación de MSDN sobre la función SetDllDirectory

http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx Documentación de MSDN sobre la función SetSearchPathMode

http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx Entrada de blog de David Leblanc, ingeniero principal de seguridad de Microsoft Office

http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx Entrada de blog de Andrew Roths, equipo de ingeniería de MSRC sobre ataques de precarga de DLL

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

Recursos adicionales