El otro día ayudando a un cliente a desarrollar software seguro se me ocurrió que este tema podría ser de interés para mis lectores. Lógicamente esta temática es bastante amplia, pero en este artículo me centraré: es un patch para el compilador GCC que mejora la protección de stack protector (stack canary) mitigando las vulnerabilidades del tipo buffer overflow.
Stack Protector Strong es un patch desarrollado en Google y aplicado al Proyecto Chromium (Navegador Chromium y Chromium OS) que mejora sustancialmente esta defensa. Por defecto en GGC tenemos los parámetros –fstack-protector y –fstack-protector-all: el primero analiza cada función en el código y si detecta una posible vulnerabilidad aplica la defensa al compilar el programa (el programador no tiene que hacer nada, bueno sí, desarrollar de forma segura ;)), mientras que el segundo parámetro aplica esta defensa a TODAS las funciones del programa sin validar si son vulnerables.
Ambas opciones tienen sus respectivos problemas: la primera opción (-fstack-protector) está limitada por el código que considera vulnerable, mientras que la segunda (-fstack-protector-all) es demasiado agresiva y afecta al rendimiento de la aplicación.
Debido a estos problemas en Google optaron por desarrollar un tercer parámetro, -fstack-protector-strong, que abarca más casos de código vulnerable sin sacrificar rendimiento. En la figura 1 podemos ver una comparativa entre –fstack-protector y –fstack-protector-strong.
Fig. 1 – -fstack-protector vs. –fstack-protector-strong
Claramente es una mejora sustancial que abarca más clases de posibles vulnerabilidades en código, pero basta de teoría y pasemos a un ejercicio práctico donde vamos a instalar el patch a la última versión de GCC 4.8.0 publicada recientemente en un Linux Debian 6.0.
El primer paso es bajarnos la versión GCC que nos interese parchear. El parche se escribió para la versión 4.6, aunque he probado con las versiones 4.7 y 4.8 y funciona correctamente. Para ello ejecutamos el comando wget con la URL de GCC y luego lo descomprimimos (ver figura 2).
Para compilar GCC debemos tener una serie de librerías instaladas por lo que utilizaremos el comando apt-get para su instalación (ver figura 3):
- Build-essential
- libgmp3-dev
- libmpfr-dev
- libmpc-dev
- zip
- autogen
Fig. 3 – Instalando paquetes necesarios para compilar GCC
Ahora bajamos el parche –fstack-protector-strong de aquí. El parche está compuesto por 5 ficheros diff.
A continuación procedemos a parchear GCC y debemos seguir el orden que aparece en la figura 5. Prestad especial atención al orden de los directorios dentro de GCC.
Fig. 5 – Aplicando parches a GGC
Una vez que tengamos GCC parcheado podemos compilarlo, para su instalación en el sistema necesitamos tener privilegios de administrador (ver figura 6). Mientras el comando se ejecuta podemos leer otros artículos de este blog ya que el proceso tarda bastante 🙂
Fig. 6 – Compilando e instalando GCC
Ahora ya estamos listos para compilar programas con la última versión de GCC y con una mejor defensa ante vulnerabilidades buffer overflow.
En la figura 7 compilamos un programa vulnerable con el parámetro –fstack-protector-strong.
Fig. 7 – Probando –fstack-protector-strong
Al desensamblar (reversing) myapp podemos ver que se ha aplicado esta defensa en varias funciones y que con –fstack-protector no se hubiera aplicado (aunque este ejercicio lo dejo para otro artículo).
Actualmente este parche no está por defecto en GCC pero esperemos que lo esté en futuras versiones, así como nuevas y mejores defensas.
Es cierto que existen vectores de ataque para saltarse esta protección, aunque toda defensa es poca y hoy en día todos los compiladores modernos (GCC, Visual Studio y LLVM) incorporan diversas defensas que los programadores deberían utilizar siempre.
Sin duda el uso de estas defensas en los compiladores no quita la necesidad de desarrollar software de forma segura utilizando un marco de desarrollo seguro como son el MS SDL o el OpenSAMM.
¿Qué parámetros de seguridad utilizas al compilar software?
— Simon Roses Femerling