La cadena de formato no controlado es un tipo de vulnerabilidad de inyección de código descubierta alrededor de 1989 que puede usarse en vulnerabilidades de seguridad . [1] Originalmente considerados inofensivos, los exploits de cadenas de formato pueden usarse para bloquear un programa o ejecutar código dañino. El problema surge del uso de entradas de usuario no marcadas como parámetro de cadena de formato en ciertas funciones de C que realizan formato, como . Un usuario malintencionado puede utilizar los tokens de formato y , entre otros, para imprimir datos de la pila de llamadas o posiblemente de otras ubicaciones en la memoria. También se pueden escribir datos arbitrarios en ubicaciones arbitrarias utilizando el token de formato, que ordena y funciones similares escribir el número de bytes formateados en una dirección almacenada en la pila.printf()
%s
%x
%n
printf()
Un exploit típico utiliza una combinación de estas técnicas para tomar el control del puntero de instrucción (IP) de un proceso, [2] por ejemplo, obligando a un programa a sobrescribir la dirección de una función de biblioteca o la dirección de retorno en la pila con un puntero. a algún código shell malicioso . Los parámetros de relleno para los especificadores de formato se utilizan para controlar el número de bytes de salida y el %x
token se utiliza para extraer bytes de la pila hasta llegar al comienzo de la cadena de formato. El inicio de la cadena de formato está diseñado para contener la dirección que el %n
token de formato puede sobrescribir con la dirección del código malicioso que se ejecutará.
Esta es una vulnerabilidad común porque antes se pensaba que los errores de formato eran inofensivos y generaban vulnerabilidades en muchas herramientas comunes. El proyecto CVE de MITRE enumera aproximadamente 500 programas vulnerables en junio de 2007, y un análisis de tendencias lo ubica como el noveno tipo de vulnerabilidad más reportado entre 2001 y 2006. [3]
Los errores de formato de cadena aparecen con mayor frecuencia cuando un programador desea generar una cadena que contiene datos proporcionados por el usuario (ya sea a un archivo, a un búfer o al usuario). El programador puede escribir por error printf(buffer)
en lugar de printf("%s", buffer)
. La primera versión se interpreta buffer
como una cadena de formato y analiza las instrucciones de formato que pueda contener. La segunda versión simplemente imprime una cadena en la pantalla, como pretendía el programador. Ambas versiones se comportan de manera idéntica en ausencia de especificadores de formato en la cadena, lo que facilita que el error pase desapercibido para el desarrollador.
Los errores de formato surgen porque las convenciones de paso de argumentos de C no son seguras para los tipos . En particular, el varargs
mecanismo permite que las funciones acepten cualquier número de argumentos (p. ej. printf
) "extrayendo" tantos argumentos de la pila de llamadas como deseen, confiando en que los primeros argumentos indiquen cuántos argumentos adicionales se extraerán y de qué tipos. .
Los errores de formato de cadenas pueden ocurrir en otros lenguajes de programación además de C, como Perl, aunque aparecen con menos frecuencia y generalmente no pueden explotarse para ejecutar código elegido por el atacante. [4]
Los errores de formato se detectaron por primera vez en 1989 mediante el trabajo de prueba de fuzz realizado en la Universidad de Wisconsin, que descubrió un "efecto de interacción" en el shell C (csh) entre su mecanismo de historial de comandos y una rutina de error que suponía una entrada de cadena segura. [5]
El uso de errores de cadena de formato como vector de ataque fue descubierto en septiembre de 1999 por Tymm Twillman durante una auditoría de seguridad del demonio ProFTPD . [6] La auditoría descubrió un snprintf
sistema que pasaba directamente datos generados por el usuario sin una cadena de formato. Pruebas exhaustivas con argumentos artificiales para funciones de estilo printf demostraron que era posible utilizar esto para escalar privilegios. Esto llevó a la primera publicación en septiembre de 1999 en la lista de correo de Bugtraq sobre esta clase de vulnerabilidades, incluido un exploit básico. [6] Sin embargo, todavía pasaron varios meses antes de que la comunidad de seguridad se diera cuenta de todos los peligros de las vulnerabilidades de cadenas de formato a medida que comenzaron a surgir exploits para otro software que utilizaba este método. Los primeros exploits que llevaron el problema a la conciencia pública (al proporcionar acceso remoto a la raíz mediante la ejecución de código) fueron publicados simultáneamente en la lista Bugtraq en junio de 2000 por Przemysław Frasunek [7] y una persona que usaba el apodo tf8 . [8] Poco después les siguió una explicación, publicada por una persona que utilizaba el sobrenombre de lamagra . [9] Pascal Bouchareine publicó "Errores de formato" en la lista Bugtraq en julio de 2000. [10] El artículo fundamental "Format String Attacks" [11] de Tim Newsham se publicó en septiembre de 2000 y se publicaron otros artículos explicativos técnicos detallados. en septiembre de 2001, como Exploiting Format String Vulnerabilities , del equipo Teso . [2]
Muchos compiladores pueden verificar estáticamente cadenas de formato y generar advertencias sobre formatos peligrosos o sospechosos. En la Colección de compiladores GNU , los indicadores de compilación relevantes son -Wall
,,,,,, y . [12]-Wformat
-Wno-format-extra-args
-Wformat-security
-Wformat-nonliteral
-Wformat=2
La mayoría de estos sólo son útiles para detectar cadenas con formato incorrecto que se conocen en tiempo de compilación. Si la cadena de formato puede provenir del usuario o de una fuente externa a la aplicación, la aplicación debe validar la cadena de formato antes de usarla. También se debe tener cuidado si la aplicación genera o selecciona cadenas de formato sobre la marcha. Si se utiliza la biblioteca GNU C, el -D_FORTIFY_SOURCE=2
parámetro se puede utilizar para detectar ciertos tipos de ataques que ocurren en tiempo de ejecución. El -Wformat-nonliteral
control es más estricto.
Al contrario de muchos otros problemas de seguridad, la causa raíz de las vulnerabilidades de las cadenas de formato es relativamente fácil de detectar en ejecutables compilados en x86: para printf
las funciones de la familia, el uso adecuado implica un argumento separado para la cadena de formato y los argumentos que se van a formatear. Los usos defectuosos de dichas funciones se pueden detectar simplemente contando el número de argumentos pasados a la función; una "deficiencia de argumento" [2] es entonces un fuerte indicador de que la función se utilizó incorrectamente.
Contar el número de argumentos suele resultar fácil en x86 debido a una convención de llamada en la que el autor de la llamada elimina los argumentos que se insertaron en la pila agregándolos al puntero de la pila después de la llamada, por lo que un simple examen de la corrección de la pila arroja el número de argumentos pasados a la printf
función -familia.' [2]
printf
scanf