En esta auxiliar probaremos unos ejemplos de código de vulnerabilidades y bugs vistos en clases, usando una máquina virtual con Lubuntu 20.04.
Para usar la máquina virtual necesitan ejecutar las siguientes tareas:
Si tienen problemas al ejecutar la máquina virtual (por la falta de un driver USB) hagan lo siguiente:
Si el error lanzado es de virtualización, necesitan activar la “Virtualización de Hardware” en la BIOS de su computador. Comuníquense con el equipo docente si necesitan ayuda para hacer esto.
Tanto el usuario como la contraseña de la máquina son el código del curso, en minúsculas.
La máquina virtual viene instalada con el sistema operativo Lubuntu 20.04, y se encuentra configurada con las siguientes opciones:
echo 0 > /proc/sys/kernel/randomize_va_space
como usuario root
build-essential
instalado: sudo apt install build-essential
, con GCC 9.3.0gdb
instalado: sudo apt install gdb
noexec=off
y noexec32=off
agregadas como parámetros de inicialización de kernelPueden bajar los ejemplos de este repositorio en Github.
Makefile
El proyecto integra un archivo con el nombre Makefile
, el cual declara las flags necesarias para la compilación de cada proyecto.
Los archivos Makefile
contienen una lista de targets
a construir, cada uno declarando un nombre, otros targets
requeridos y el/los comandos a ejecutar para completarse:
target: requirement1 requirement2
echo "completing target"
requirement1:
echo "completing requirement 1"
requirement2:
echo "completing requirement 2"
Para ejecutar el primer target
(el cual en este proyecto compila todos los ejemplos), basta con correr make
en la carpeta del makefile. Si se quiere ejecutar un target en específico, basta con correr make <nombre_target>
, cambiando <nombre_target>
por el nombre del target a ejecutar.
Les recomendamos revisar el archivo Makefile
para ver cuáles flags se están usando en cada ejemplo.
Para activar/desactivar ciertas opciones de protección del stack, se usan las siguientes flags:
-fstack-protector
: , Agrega un _canario a funciones y a buffers de tamaño mayor o igual a 8-fstack-protector-strong
: (Activada por defecto en Lubuntu) Agrega un _canario a funciones y a buffers de tamaño mayor o igual a 4, definiciones de arreglos locales y referencias a frames
locales.-fstack-protector-all
: agrega un canario a todas las funciones y buffers-fnostack-protector
: Desactiva las protecciones de stack usando canarios-z execstack
: Desactiva la protección de ejecución de código en el stack.-fcf-protection=[full|branch|return|none]
: Define protecciones contra ataques de control de flujo, como ROP y Return-To-Libc. La flag return
corresponde a revisar la integridad de las protecciones al momento de volver de un jmp
o call
. La flag branch
corresponde a revisar la integridad de las protecciones al momento de realizar un jmp
o call
. La flag full
utiliza ambas medidas anteriores y la flag none
no utiliza ninguna.Revisen el anexo correspondiente para entender mejor cómo usar GDB al momento de correr un programa.
Luego de compilarlos, podrán ejecutar los binarios producidos a partir de los siguientes códigos fuente:
format_string.c
Este código genera solamente un binario: format_string
, el cual recibe un string que es impreso directamente como único argumento de printf
.
echo 2 > /proc/sys/kernel/randomize_va_space
como usuario root
. Recuerda desactivarlo después (también puedes reiniciar la máquina virtual para desactivarlo). ¿Qué ocurre de distinto en ambos casos?%p %p %p %p %p...
hasta encontrar un patrón. Intenta identificar a qué corresponde este patrón.password
con un texto largo. Intenta mostrarla con un string de formato especial con ayuda de GDB.buffer_overflow.c
Este código fuente genera dos binarios distintos:
buffer_overflow
: el cual se compila con flags que permiten realizar un buffer overflow de forma correcta (desactivando canarios)buffer_overflow_protected
: el cual se compila con las flags por defecto de gcc en LubuntuAmbos programas reciben de input un string de tamaño arbitrario, el cual intentan copiar en un buffer de tamaño 8
Recomendamos que experimenten con distintos inputs y vean qué ocurre con el flujo del programa. Además, tambien es buena idea ejecutar las instrucciones usando GDB para ver el estado del stack.
En el laboratorio 2, vamos a intentar ejecutar shellcode a través del buffer overflow del programa vulnerable.
Actualización: 2 de junio a las 9:30: Se removió esta sección debido a que el enunciado del laboratorio contendrá los pasos para ejecutar un buffer_overflow.