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 más información, consulte esta página web de Microsoft: El soporte técnico finalizará 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 mediante la búsqueda en un conjunto de directorios bien definido. Si un atacante obtiene el control de uno de los directorios, puede forzar 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 pueda ejecutar código en el contexto del usuario que ejecuta la aplicación. Cuando la aplicación se ejecuta como administrador, esto podría dar lugar a una elevación local de privilegios. Sabemos del renovado interés en estos ataques. Para limitar el efecto que este problema tiene en nuestros clientes mutuos, publicamos este documento a la comunidad de desarrolladores para asegurarnos de que conocen este problema y tienen las herramientas necesarias para solucionarlo en sus aplicaciones.
Resumen
Descripción de los ataques de precarga de DLL
Ataques basados en LoadLibrary
Cuando una aplicación carga dinámicamente una DLL sin especificar una ruta de acceso completa, Windows intenta localizar esta DLL mediante una búsqueda lineal en un conjunto bien definido de directorios, conocido como orden de búsqueda de DLL. Si Windows localiza la DLL dentro del orden de búsqueda de DLL, cargará esa DLL. Sin embargo, si Windows no encuentra la DLL en ninguno de los directorios en el orden de búsqueda de DLL, devolverá un error en la operación de carga de DLL. Este es el orden de búsqueda de DLL para las funciones LoadLibrary y LoadLibraryEx , que se usan para cargar DLL dinámicamente:
- El directorio desde el que se cargó la aplicación
- Directorio del sistema
- El directorio del sistema de 16 bits
- El directorio de Windows
- El directorio de trabajo actual (CWD)
- Los directorios que se enumeran en la variable de entorno PATH
Tenga en cuenta el siguiente escenario:
- Una aplicación carga un archivo DLL sin especificar la ruta completa que espera encontrar en el CWD de la aplicación.
- La aplicación está totalmente preparada para manejar el caso cuando no encuentra la DLL.
- El atacante conoce esta información sobre la aplicación y controla el CWD.
- El atacante copia su propia versión especialmente diseñada de la DLL en el CWD. Se supone que el atacante tiene permiso para hacerlo.
- Windows busca en los directorios del orden de búsqueda de DLL y encuentra la DLL en el CWD de la aplicación.
En este escenario, la DLL especialmente diseñada 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, obtenga el directorio de trabajo actual y úselo para pasar una ruta completa de LoadLibrary.
También sabemos que algunos desarrolladores usan LoadLibrary para validar la presencia de una DLL específica, con el fin de determinar qué versión de Windows ejecuta el usuario. Debe tener en cuenta que esto podría hacer que la aplicación sea vulnerable. Si la biblioteca afectada 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 utilizar esta técnica. En su lugar, use las técnicas recomendadas que se describen en el artículo de MSDN, "Obtención de la versión del sistema".
Una aplicación que carga complementos de terceros y que no puede forzar a los complementos a utilizar una ruta calificada para sus llamadas a LoadLibrary debe llamar a SetDllDirectory("") para quitar CWD y, a continuación, llamar a SetDllDirectory("ubicación de instalación del complemento") para agregar el directorio de instalación del complemento a la ruta de búsqueda de DLL.
Ataques basados en SearchPath
Un ataque similar existe cuando una aplicación usa la API 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 SearchPath:
- El directorio desde el que se cargó la aplicación
- El directorio de trabajo actual (CWD)
- Directorio del sistema
- El directorio del sistema de 16 bits
- El directorio de Windows
- Los directorios que se enumeran en la variable de entorno PATH
No se recomienda seguir este patrón porque no es seguro. No se recomienda la función SearchPath como método para localizar un archivo .dll si el uso previsto de la salida está en una llamada a la función LoadLibrary. Esto puede dar lugar a la búsqueda de un archivo .dll incorrecto porque el orden de búsqueda de la función SearchPath difiere del orden de búsqueda usado por la función LoadLibrary. Si tiene que buscar y cargar un archivo .dll, utilice 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 archivos ejecutables externos. Se recomienda que los desarrolladores tengan cuidado al cargar archivos binarios y especifiquen la ruta de acceso completa. Esto debería suponer una menor complejidad al cargar un binario en lugar de una biblioteca.
Pasos recomendados para desarrolladores de software
Se recomienda que los desarrolladores hagan lo siguiente:
Valide sus aplicaciones para instancias de cargas de bibliotecas no seguras (se proporcionan 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 completas para todas las llamadas a LoadLibrary, CreateProcess y ShellExecute cuando pueda.
Implemente las llamadas a SetDllDirectory con una cadena vacía ("") para quitar el directorio de trabajo actual del orden de búsqueda predeterminado de DLL cuando sea necesario. Tenga en cuenta que SetDllDirectory afecta a todo el proceso. Por lo tanto, debe hacer esto una vez al principio de la inicialización del proceso, no antes y después de las llamadas a LoadLibrary. Dado que SetDllDirectory afecta a todo el proceso, varios subprocesos que llaman a SetDllDirectory con valores diferentes podrían provocar un comportamiento indefinido. Además, si el proceso está diseñado para cargar archivos DLL de terceros, será necesario realizar pruebas para determinar si realizar 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 provocar incompatibilidades.
Use la función SetSearchPathMode para habilitar el modo de búsqueda de procesos seguro para el proceso. De este modo, el directorio de trabajo actual se mueve al último lugar de la lista de búsqueda de SearchPath durante toda la duración del proceso.
Evite usar SearchPath para comprobar la existencia de una DLL sin especificar una ruta completa, incluso si el modo de búsqueda segura está habilitado, ya que esto puede provocar ataques de precarga de DLL.
Guía para identificar cargas de bibliotecas no seguras
En el código fuente, los siguientes son ejemplos de cargas de bibliotecas no seguras:
En el ejemplo de código siguiente, la aplicación busca "schannel.dll" utilizando 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 aplicación y sistema operativo descritas al principio de este documento para la llamada LoadLibrary(). Si existe 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, aún expone al usuario de la aplicación a un riesgo si el entorno no es completamente predecible.
HMODULE handle = LoadLibrary("schannel.dll");
A continuación se muestran ejemplos de cargas de bibliotecas mejoradas y más seguras:
En el ejemplo de código siguiente, la biblioteca se carga directamente mediante una ruta de acceso completa. No hay 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 acerca de 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.aspxEn 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 especificado en la ruta del usuario para poder usar un ataque de precarga de DLL.
SetDllDirectory (""); HMODULE handle = LoadLibrary("schannel.dll");En todos los sistemas que tienen instalada la actualización de seguridad 963027 (descrita en MS09-014), el código siguiente 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 especificado en la ruta de acceso del usuario para poder usar un ataque de precarga de DLL.
SetSearchPathMode (BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT ); HMODULE handle = LoadLibrary("schannel.dll");
Uso del Monitor de procesos para detectar dinámicamente cargas no seguras
Microsoft publica una herramienta denominada Monitor de procesos. Esta herramienta permite a los desarrolladores y administradores realizar un seguimiento detallado del comportamiento de un proceso en ejecución. El Monitor de procesos 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 procesos, visite la siguiente página web de Microsoft:
http://technet.microsoft.com/en-us/sysinternals/bb896645.aspxIntente iniciar la aplicación mediante 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 procesos con los siguientes filtros:
Si se golpea una ruta vulnerable, verá algo similar a lo siguiente:
La llamada al recurso compartido de archivos remoto para cargar una DLL indica que se trata de un programa vulnerable.
Más información
Para obtener más información, visite 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 RutaDeBúsqueda
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 de seguridad principal 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 los ataques de precarga de DLL