NOTE: If you want to read the post in English, please use the Google Translate button located on the right side of the page.
Un nuevo año, un nuevo reto y un nuevo Pwn. ]¬)
En esta ocasión el reto se trata de realizar la traducción de un listado de código en Lenguaje Ensamblador a código en Lenguaje "C", identificar la vulnerabilidad existente y aprovecharse de la misma para imprimir en pantalla un mensaje.
Bien, revisemos los puntos que se necesitan completar:
1. ¿Cuántas variables locales hay en la función main?
2. ¿De qué tipo son cada una de las variables locales identificadas en el punto anterior?
3. Detecta la vulnerabilidad existente en el código.
4. Define en qué condiciones exactas es posible explotarla.
5. Convierte a código C el codigo ASM y compílalo sin errores para conseguir el ejecutable final.
6. Explota el fallo y modifica el flujo del programa para que imprima por pantalla el siguiente mensaje "[*] Pwned!"
7. Propón correcciones para evitar la vulnerabilidad tanto en el código en C como en ASM
NOTA: Intentaré llevar en la secuencia que indican las preguntas, sin embargo, es probable que o salte puntos o toque ciertos temas antes de abordar por completo el objetivo de la pregunta.
Bien, sin más ni más, ¡al ataque!
Para empezar, hay que ponernos cómodos con respecto a nuestro objetivo a analizar. En este caso, demos un vistazo al código en Lenguaje Ensamblador para darnos una idea que como se encuentra compuesto y de igual modo, identificar puntos importantes que nos ayudarán en próximos pasos.
5.- Convierte a código C el codigo ASM y compílalo sin errores para conseguir el ejecutable final.
Después de un breve análisis, nos dimos cuenta que la estructura es muy intuitiva, es decir, es muy fácil de identificar los "pedazos" que se refieren a alguna rutina la cual ejecuta cierta acción y dará un resultado posterior. Las rutinas antes mencionadas son las que comienzan con un punto y la letra L (.L), los que tengan experiencia programando en Ensamblador se sentirán cómodos con esta estructura.
Ahora, para simplificar un poco la tarea del análisis, vamos a identificar las funciones utilizadas en el listado. Esta tarea la resolvemos fácilmente ya que las funciones inician con un "CALL". Veamos...
Identificamos 5 funciones y nos podemos dar una idea de que se trata:
1. Hay un cálculo de tamaño de una string (strlen();)
2. Hay copiado de datos (strncpy(); y strcpy(); respectivamente) <- buffers? ]¬)
3. Las funciones (printf(); y puts();) muestran en pantalla datos
Para los que se encuentran familiarizados con la programación en lenguajes de alto nivel, sabrán que el llamado a una función es muy sencilla. Si requerimos imprimir en pantalla "ph33r" simplemente tenemos que hacer un printf("ph33r"); sin embargo, cuando dicha función es ejecutada, las instrucciones en ensamblador "internamente" ejecutan la función de manera distinta.
Ahora, veamos cómo se visualiza la función printf en el código ensamblador que tenemos: