WorstFit: Se revelan los conversores ocultos de Windows ANSI
TL;DR
- Se descubrió una nueva superficie de ataque al explotar Best-Fit, la función interna de conversión de conjuntos de caracteres de Windows.
- Se convirtió esta funcionalidad en ataques prácticos como traversal de rutas, inyección de argumentos y ejecución remota de código (RCE).
- La causa raíz radica en el comportamiento del compilador, el runtime de C/C++ y los errores de los desarrolladores.
- También se discute lo difícil que es introducir parches en el ecosistema de código abierto.
Descifrado de codificación de Windows
Inicial: ANSI y páginas de códigos
- Windows inicialmente usó codificación ANSI, que era efectiva para idiomas específicos, pero no podía manejar conjuntos de caracteres mixtos.
- Existen varias páginas de códigos, y cada una soporta idiomas específicos.
Era Unicode: UTF-16
- Windows migró a Unicode a mediados de los años 90 para representar los caracteres de casi todos los idiomas en un único estándar.
- Al principio usó UCS-2 y luego lo actualizó rápidamente a UTF-16.
Era de doble codificación
- Para mantener soporte a las páginas de códigos ANSI heredadas, Windows implementó dos versiones de API.
- Existe la API ANSI y la API Unicode, y los desarrolladores pueden obtener fácilmente el formato de datos que deseen.
Ventajas de Best-Fit
- La conversión de caracteres "Best-Fit" de Windows es la forma de procesar un carácter que no está presente en la página de códigos destino al convertir de UTF-16 a ANSI.
- Por ejemplo, como el símbolo
∞ no existe en la página de códigos Windows-1252, Microsoft lo asigna a 8.
WorstFit: Nueva superficie de ataque en Windows
🔥 Pesadilla de Asia oriental - CVE-2024-4577
- CVE-2024-4577 es una vulnerabilidad que permite comprometer un servidor PHP-CGI con páginas de códigos chinas o japonesas mediante una solicitud simple
?%ADs.
- Gracias al comportamiento de Best-Fit, U+00AD (guion suave) se mapea a un guion (
-), permitiendo una evasión.
🔥 Secuestro de nombres de archivo
- Es posible abusar de WorstFit en el manejo de nombres de archivo y convertirlo en una carga útil de path traversal.
- Por ejemplo, la Developer Shell de Chrome V8 (
d8.exe) obtiene el directorio de trabajo actual usando la API ANSI.
🔥 División de argumentos
- Se puede manipular la salida de
GetCommandLineA para aprovechar el comportamiento de WorstFit durante el parseo de la línea de comandos.
- Por ejemplo, la entrada
" --use-askpass=calc " puede ejecutar calc.exe en el sistema.
Conclusión
- El comportamiento de Best-Fit introduce una superficie de ataque en el proceso de conversión a nivel del sistema, lo que puede causar vulnerabilidades en diversas herramientas.
- Estos ataques no se pueden bloquear por completo con funciones de bibliotecas estándar o de lenguajes de programación.
1 comentarios
Opiniones de Hacker News
Microsoft ya sabía de este problema desde hace al menos un año. A través de una regla especial de análisis de código, CA2101, desaconsejó usar el mapeo best-fit. Se mencionó una vulnerabilidad de seguridad, pero los detalles fueron ambiguos.
Esto es sistémico. Microsoft provee un mapeo de códigos "best fit" para convertir Unicode a ASCII. Este mapeo se usa en muchos lugares y, dado que Microsoft prioriza la retrocompatibilidad, probablemente deba seguir estando incluido. En la práctica, está conectado por defecto en todas partes.
Principalmente se explota convirtiendo puntos de código anómalos en barras, guiones, comillas y similares. Puede evaluarse bien en lenguajes modernos de programación, pero falla al pasar esos datos a comandos de shell o a la API de Win32.
El mantenedor de curl dice que "curl es la víctima", pero la causa real está en otro lado. El problema aparece cuando el servidor valida la entrada del usuario de una forma y el sistema la trata de otro modo al aplicarla a librerías del sistema.
Desactivar de manera selectiva la conversión "best fit" en Win32 podría ser la solución. Los proveedores de código abierto podrían adoptarlo como buena práctica.
Windows puede convertirse en un "Munchkin" de seguridad: varias funcionalidades terminan combinándose por casualidad y generan una vulnerabilidad fuerte. Convertir el subsistema ANSI a UTF-8 podría atenuar este problema.
Microsoft ha ido retirando ANSI desde NT 3.5 e incentivando el uso de la API de caracteres anchos. Sin embargo, la manera en que la biblioteca runtime de C/C++ de Microsoft está implementada es el principal obstáculo.
Es poco probable que Microsoft active UTF-8 por defecto en todas las ediciones de Windows. Muchas aplicaciones antiguas dependen de páginas de códigos específicas o de caracteres de 1 byte.
Hay dos formas de forzar que la página de códigos "Ansi" sea UTF-8 en una aplicación: una es usando un archivo Manifest y otra usando la herramienta "App Locale".
En mi PC personal, activar el modo UTF-8 me protegió de este bug; lo hice porque en un juego antiguo de otro idioma se veía texto corrupto.
El problema no se resuelve simplemente reemplazando main() por su versión de wide-character. Hay que convertir todas las variables a wchar_t *, y eso es doloroso y propenso a errores.
Sabía que la API de Windows ofrecía la conversión best-fit, pero no sabía que ese fuera el comportamiento por defecto. Esa función debería prohibirse.
Me preguntaba si la casilla Beta era lo mismo que configurar ActiveCodePage a UTF-8. GDI sigue solo una página de códigos global, no por proceso, así que es una pena que no se pueda elegir UTF-8 por completo.