Recientemente presentamos en nuestro blog un desafío relacionado con la explotación de un buffer overflow en un programa vulnerable. Hoy vamos a ver cómo una comprobación de la longitud del buffer, si no es correctamente implementada, puede ser fácilmente sorteada.

Como observábamos en la solución del desafío, el código era vulnerable porque se realizaba una copia de caracteres sin comprobar la longitud de la fuente, pudiendo producir un desbordamiento. La solución más intuitiva consiste en comprobar la longitud de la cadena antes de realizar la copia. Hemos adaptado el código, que queda de la siguiente forma:

codigo vulnerable integer overflow

Vemos que en la línea 9 se comprueba la longitud, antes de realizar la copia en la línea 12. Sin embargo, esta solución no contempla el desbordamiento de los números enteros. ¿Qué sucede si se intenta almacenar un número más grande del que una variable puede almacenar debido a su tipo? El siguiente cuadro muestra los tipos enteros en C y su tamaño:

tabla de tipos de datos enteros en C

Así, si se intenta almacenar un número superior a 127 en una variable de tipo signed char, la cuenta empieza de nuevo desde -128: cada unidad que sobrepasa 127 es sumada a -128. Luego, por ejemplo, para el valor 128 se termina almacenando -128; para 129 corresponde -127, etc. De esto se desprende que, si la cadena es lo suficientemente larga, se puede alterar el valor almacenado de su longitud, lo cual se conoce como integer overflow.

Al ser la variable longitud de tipo unsigned char, cualquier cadena que tenga entre 261 y 266 caracteres será aceptada como válida. Hacemos una prueba del programa ya compilado:

prueba ejecucion bash

Y con un argumento de entrada de 261 caracteres, se produce el integer overflow:

ejemplo integer overflow

Esto puede aprovecharse para insertar un payload, como una shell, en el stack (o heap) del proceso vulnerable, de la misma manera que habíamos mostrado en la solución del desafío. De igual forma existe el concepto de integer underflow, cuando el valor a almacenar en la variable numérica se encuentra por debajo del límite inferior.