Desbordamiento de enteros
Un desbordamiento de enteros es una situación en la aritmética informática en la que el valor calculado como resultado de una operación no se puede colocar en un tipo de datos enteros de n bits. Distinguir entre desbordamiento por el límite superior de la representación y por el inferior ( Underflow en inglés ).
Ejemplo: sumando dos variables de 8 bits y almacenando el resultado en una variable del mismo tamaño:
se produce un desbordamiento.
En este caso, el resultado no se escribe como se esperaba , sino como . Vale la pena señalar que el cálculo aquí se realizó módulo 2 n , y la aritmética módulo es cíclica, es decir, 255+1=0 (para n = 8). Esta situación de desbordamiento la soluciona la computadora configurando bits especiales del registro de las banderas Overflow y Carry (cláusula 3.4.3.1 Volumen combinado: Volumen 1 [1] ). Cuando se programa en lenguaje ensamblador, dicha situación se puede establecer directamente, por ejemplo, al verificar manualmente el estado del registro de bandera después de realizar la operación (cláusula 7.3.13.2 Volumen combinado: Volumen 1 [1] ).
Origen del problema
La profundidad de bits de un registro determina el rango de datos que se pueden representar en él. Rangos de representación para tipos enteros en computadoras binarias:
Bitness
|
8 bits
|
16 bits
|
32 bits
|
64 bits
|
no firmado
|
Rango
|
0..2 8 −1
|
0..2 16 −1
|
0..2 32 −1
|
0..2 64 −1
|
Rango (decimales)
|
0..255
|
0..65535
|
0..4294967295
|
0.. 18446744073709551615
|
Icónico
|
Rango
|
-2 7 .. 2 7 −1
|
-2 15 .. 2 15 −1
|
-2 31 .. 2 31 −1
|
-2 63 .. 2 63 −1
|
Rango (decimales)
|
-128..127
|
-32768..32767
|
-2147483648.. 2147483647
|
-9223372036854775808.. 9223372036854775807
|
Puede ocurrir un desbordamiento en el código fuente debido a un error del programador oa la falta de vigilancia de los datos de entrada [2] .
- Desajuste firmado y sin firmar . Si los números se representan en la computadora en un código adicional, entonces diferentes números corresponden a un flujo de bits. En aritmética de 32 bits, −1 con signo corresponde a 4294967295 sin signo (el límite superior de la representación). Es decir, pasar un tipo a otro puede resultar en una diferencia significativa en el significado. Este tipo de error es a menudo el resultado de un error de firma ( y ), es decir, un encasillamiento incorrecto entre tipos con diferentes signos.
- Problema de corte. Ocurre cuando un número se interpreta como un entero de menor longitud. En este caso, solo los bits menos significativos permanecerán en el número. Se descartarán seniors, lo que supondrá un cambio en el valor numérico
- Extensión de signo. Vale la pena recordar que al convertir un número con signo a un tipo de mayor longitud, se copia el bit más significativo, lo que, si se interpreta como sin signo, dará lugar a un número muy grande [3]
Los programadores utilizan ampliamente la capacidad de desbordamiento, por ejemplo, para hash y criptografía, generar números aleatorios y encontrar límites en una representación de tipo [4] . Al mismo tiempo, por ejemplo, según el estándar de los lenguajes C y C++ , los cálculos sin signo se realizan módulo 2, mientras que el desbordamiento con signo es un ejemplo clásico [5] de comportamiento indefinido [6] .
Este tipo de incorrección en el código conduce a las siguientes consecuencias [4] :
- La compilación puede ir inesperadamente. Debido a la presencia de un comportamiento indefinido en un programa, las optimizaciones del compilador pueden cambiar el comportamiento del programa.
- Bomba de tiempo. En la versión actual del sistema operativo, el compilador, las opciones de compilación, la organización estructural del programa, etc., todo puede funcionar, pero con cualquier cambio, por ejemplo, la aparición de optimizaciones más agresivas, se romperá.
- Ilusión de previsibilidad. Una configuración de compilador particular puede tener un comportamiento muy específico, por ejemplo, los compiladores de C y C++ generalmente implementan operaciones módulo 2 n y para tipos firmados (solo aquellos interpretados en complemento a dos) si las optimizaciones agresivas están deshabilitadas. Sin embargo, uno no puede esperar tal comportamiento, de lo contrario existe el riesgo del efecto de una "bomba de tiempo".
- Formación de dialectos. Algunos compiladores brindan opciones adicionales para extender el comportamiento indefinido . Por ejemplo, tanto GCC como Clang admiten la opción -fwrapv, que proporciona el comportamiento descrito anteriormente (en el punto 3).
Cambiar el estándar puede introducir nuevos problemas de desbordamiento. Por ejemplo, 1<<31 dependía de la implementación en los estándares ANSI C y C++98, mientras que quedó indefinido en C99 y C11 (para enteros de 32 bits). [cuatro]
Además, puede haber otras consecuencias de dicho error, por ejemplo, un desbordamiento de búfer .
Explotación y secuelas
Implicaciones clave de seguridad [7] :
Clásicamente, un desbordamiento puede explotarse a través de un desbordamiento de búfer.
img_t * tabla_ptr ; /*estructura que contiene datos img, 10kB cada uno*/
int num_imgs ;
...
num_imgs = obtener_num_imgs ();
table_ptr = ( img_t * ) malloc ( tamaño de ( img_t ) * num_imgs );
...
Este ejemplo [7] ilustra varias vulnerabilidades a la vez. En primer lugar, un num_imgs demasiado grande asignará un búfer enorme, lo que puede hacer que el programa consuma todos los recursos del sistema o que se bloquee .
Otra vulnerabilidad es que si num_imgs es aún mayor, desbordará el argumento malloc. Entonces solo se asignará un pequeño búfer. Al escribir en él, se producirá un desbordamiento de búfer , cuyas consecuencias pueden ser: interceptación del control sobre la ejecución, ejecución del código del atacante, acceso a información importante. [ocho]
Evitando el problema
La protección contra tal comportamiento debe llevarse a cabo en varios niveles [7] :
- Planificación del programa y requisitos:
- Asegúrese de que todos los protocolos de comunicación entre los componentes estén estrictamente definidos. Incluyendo que se detectarán todos los cálculos fuera de los límites de la vista . Y exigir el estricto cumplimiento de estos protocolos
- Utilice un lenguaje de programación y un compilador que no permita que se materialice esta vulnerabilidad , que la haga más fácil de detectar o que realice una verificación de límites automáticos. Las herramientas proporcionadas por el compilador incluyen desinfectantes (p. ej ., Address Sanitizer o Undefined Behavior Sanitizer).
- Arquitecturas del programa:
- Utilice bibliotecas o marcos probados que lo ayuden a realizar cálculos sin el riesgo de consecuencias impredecibles . Los ejemplos incluyen bibliotecas como SafeInt (C++) o IntegerLib (C o C++).
- Cualquier verificación de seguridad en el lado del cliente debe duplicarse en el lado del servidor para evitar CWE-602 . Un atacante puede eludir la validación del lado del cliente cambiando los valores inmediatamente después de pasar la validación, o modificando el cliente para eliminar la validación por completo.
- Implementaciones:
- Valide cualquier dato numérico entrante para asegurarse de que esté dentro del rango esperado. Asegúrese de comprobar tanto el umbral mínimo como el máximo. Utilice números sin firmar siempre que sea posible. Esto facilitará la comprobación de desbordamientos.
- Explore todos los matices necesarios del lenguaje de programación asociado con la computación numérica ( CWE-681 ). Cómo se representan, cuáles son las diferencias entre firmado y sin firmar , 32 bits y 64 bits , problemas con la conversión (recorte, conversión de tipo firmado-sin firmar - arriba) y cómo los números que son demasiado pequeños o, por el contrario, demasiado grandes para se procesan sus representaciones de máquina. También asegúrese de que el tipo que está utilizando (por ejemplo, int o long) cubra el rango de representación requerido
- Examine las advertencias del compilador en detalle y resuelva los posibles problemas de seguridad, como discrepancias en el signo del operando en las operaciones de memoria o el uso de variables no inicializadas . Incluso si la vulnerabilidad es muy pequeña, puede generar peligro para todo el sistema.
Otras reglas para evitar estas vulnerabilidades publicadas en CERT C Secure Coding Standard en 2008 incluyen [9] :
- No escriba ni use funciones de manejo de entrada de cadenas a menos que manejen todos los casos
- No use operaciones de bits en tipos firmados
- Evalúe expresiones en un tipo más grande antes de comparar o asignar a uno más pequeño
- Tenga cuidado antes de lanzar entre un número y un puntero
- Asegúrese de que los cálculos de módulo o los resultados de la división no den como resultado una división posterior por cero
- Use intmax_t o uintmax_t para E/S formateadas de tipos numéricos personalizados
Ejemplos de la vida real
Estudio SPECTCINT
En el artículo [4] , como tema de estudio de los programas C y C++ para desbordamiento de enteros , se estudia en detalle uno de los paquetes de prueba más utilizados y conocidos, SPEC , utilizado para mediciones de rendimiento. Consta de fragmentos de las tareas más comunes, tales como: pruebas de matemática computacional, compilación, trabajo con bases de datos, disco, red, etc.
Los resultados del análisis SPECCINT2000 muestran la presencia de 219 fuentes estáticas de desbordamiento en 8 de 12 puntos de referencia, de los cuales 148 usaron desbordamiento sin firmar y 71 usaron desbordamiento con signo ( comportamiento indefinido nuevamente ). Al mismo tiempo, el desbordamiento sin firmar tampoco siempre es intencional y puede ser un error y una fuente de vulnerabilidad (por ejemplo, el Listado 2 del mismo artículo [4] ).
También probado para "bombas de tiempo" en SPECCINT2006. Su idea es devolver un número aleatorio en cada lugar de comportamiento indefinido y ver qué consecuencias puede tener. Si evaluamos el comportamiento indefinido desde el punto de vista del estándar C99 / C ++ 11, hasta 6 de los 9 puntos de referencia fallarán en la prueba.
Ejemplos de otros paquetes de software
int addi ( int lhs , int rhs ) {
error = 0 ;
if (((( izquierda + derecha ) ^ izquierda ) & (( izquierda + derecha ) ^ derecha )) >> ( tamaño de ( int ) * CHAR_BIT -1 )) {
error_handler ( "ERROR DE DESBORDAMIENTO" , NULL , EDESBORDAMIENTO );
errno = EINVAL ;
}
volver lhs + rhs ;
}
Este fragmento de código [4] del paquete IntegerLib comprueba si lhs y rhs se pueden sumar sin desbordamiento. Y exactamente en la línea 3, puede ocurrir este desbordamiento (al sumar lhs + rhs). Esto es UB porque lhs y rhs son tipos con signo. Además, se encontraron 19 desbordamientos de UB más en esta biblioteca.
Los autores también informaron 13 desbordamientos en SQLite, 43 en SafeInt, 6 en la biblioteca GNU MPC, 30 en PHP, 18 en Firefox, 71 en GCC, 29 en PostgreSQL, 5 en LLVM y 28 en Python. La mayoría de los errores se corrigieron pronto.
Otros ejemplos
Un famoso ejemplo de desbordamiento de enteros ocurre en el juego Pac-Man , al igual que otros juegos de la serie: Ms. pac-man , jr. Pac Man . Además, esta falla aparece en el Pac-Man Google Doodle como el llamado "huevo de Pascua". [10] Aquí, en el nivel 256, se puede observar una " pantalla de la muerte ", y el nivel en sí se llama " nivel de pantalla dividida ". Los entusiastas han desensamblado el código fuente en un intento de corregir el error modificando el juego .
Supuestamente, el mismo problema estaba en el juego Sid Meier's Civilization y se conoce como Nuclear Gandhi [11] . Según la leyenda, en algún momento del juego con un Gandhi muy pacífico, hay un desbordamiento de 0 niveles de hostilidad, lo que puede resultar en una guerra nuclear con Gandhi. De hecho, tal mito apareció solo con el lanzamiento de Civilization V , donde el parámetro de su inteligencia artificial , que regula la creación y el uso de armas nucleares , tiene el valor más alto de 12, lo que no contradecía el hecho de que Gandhi es uno. de los líderes más pacíficos del juego [12] .
Otro ejemplo es una falla en SimCity 2000 [13] . El punto aquí es que el presupuesto del jugador se hizo muy grande, y después de pasar por 2 31 , de repente se volvió negativo. El juego termina en derrota.
Este fallo es de Diablo III . Debido a uno de los cambios en el parche 1.0.8, la economía del juego se vino abajo. Se aumentó el monto máximo para transacciones de 1 millón a 10 millones, el costo de compra se desbordó por el tipo de 32 bits, y cuando se canceló la operación se devolvió el monto total. Es decir, el jugador se quedó con una ganancia de 2 32 moneda del juego [14]
Véase también
Notas
- ↑ 1 2 Manuales para desarrolladores de software de las arquitecturas Intel® 64 e IA-32 | Software Intel® . software.intel.com. Consultado: 22 de diciembre de 2017.
- ↑ x86 Exploitation 101: "Integer overflow" - agregando uno más... aaaaaaaaaa y se ha ido , /dev/null de gb_master (12 de agosto de 2015). Consultado el 20 de diciembre de 2017.
- ↑ El consorcio de seguridad de aplicaciones web/desbordamientos de enteros . proyectos.webappsec.org. Recuperado: 8 de diciembre de 2017. (indefinido)
- ↑ 1 2 3 4 5 6 W. Dietz, P. Li, J. Regehr, V. Adve. Comprender el desbordamiento de enteros en C/C #x002B; #x002B; // 2012 34° Congreso Internacional de Ingeniería de Software (ICSE). - Junio 2012. - S. 760-770 . -doi : 10.1109/ icse.2012.6227142 .
- ↑ CWE - 2011 CWE/SANS Los 25 errores de software más peligrosos . cwe.mitre.org. Consultado: 21 de diciembre de 2017.
- ↑ ISO/IEC 9899 : 2011 - Tecnología de la información -- Lenguajes de programación -- C. www.iso.org. Consultado: 21 de diciembre de 2017.
- ↑ 1 2 3 CWE-190: Integer Overflow o Wraparound (3.0 ) . cwe.mitre.org. Consultado: 12 de diciembre de 2017.
- ↑ CWE-119: Restricción incorrecta de operaciones dentro de los límites de un búfer de memoria (3.0 ) . cwe.mitre.org. Consultado: 12 de diciembre de 2017.
- ↑ CWE-738: CERT C Secure Coding (versión 2008) Sección 04 - Enteros (INT) (3.0 ) . cwe.mitre.org. Recuperado: 15 de diciembre de 2017.
- ↑ Mapa 256 Glitch , Pac - Man Wiki . Consultado el 12 de diciembre de 2017.
- ↑ Gandhi nuclear , conoce tu meme . Consultado el 15 de diciembre de 2017.
- ↑ Artemy Leonov. ¿Por qué la historia del error "Gandhi nuclear" de Civilization es probablemente inventada ? DTF (5 de septiembre de 2019). Fecha de acceso: 24 de octubre de 2020. (indefinido)
- ↑ Desbordamiento de enteros de Sim City 2000 . Blake O'Hare. Consultado: 12 de diciembre de 2017. (indefinido)
- ↑ Economía de Diablo III rota por un error de desbordamiento de enteros , minimaxir | El blog de Max Woolf . Consultado el 12 de diciembre de 2017.