Variadic Vulnerabilities Vanquished via #UseSec17

Investigadores de las universidades de Purdue, Politecnico di Milano y California – Irvine, presentaron este verano en Usenix Security un trabajo centrado en tratar de prevenir y erradicar las vulnerabilidades causadas por el abuso de funciones variádicas.

Una función variádica es aquella que puede recibir un número variable de argumentos, el ejemplo clásico en C es la función printf:

  • int printf(char *format, arg_1, arg_2, ….)

Que permite especificar un número variable de argumentos que se aplicarán a los conversores (%) en el char *format.

La flexibilidad que aportan las funciones variádicas tiene un coste, ya que estas funciones no son type-safe, y por tanto de forma estática (en tiempo de compilación) no se pueden detectar errores asociados al uso equivocado de tipos (por ejemplo confundir un float con un entero). Estos errores de tipos pueden ser explotados para ejecutar código malicioso; concretamente los investigadores proponen dos vectores de ataque.

Dado un error de memoria que nos permite sobrescribir el objetivo de una llamada indirecta: Podemos llamar a cualquier función variádica que comparta parte de la firma de la llamada indirecta. Por ejemplo, si esperamos llamar a una función con firma int (* función_a) (int, …), se podría explotar para llamar a otras funciones con firmas tan diferentes como void (* función_b) (int, …), u a funciones variádicas con una firma igual, pero que esperen diferentes argumentos, por ejemplo int (* función_c) (int, …). Se pueden sobrescribir los argumentos de la función variádica, por ejemplo los ataques de format-strings son parte de este vector de ataque.

Esta clase de ataques son los que los investigadores tratan de evitar con una herramienta llamada HexVASAN. Esta combina el análisis estático con un chequeo en tiempo de ejecución para asegurar que las llamadas a funciones variádicas no sean explotadas. Para ello, añaden un nuevo pase de compilación en LLVM que po run lado, extrae información sobre dónde van a ocurrir llamadas variádicas y además hace que el compilador inyecte instrucciones adicionales encargadas de recolectar información sobre los tipos y número de argumento de estas llamadas. En tiempo de ejecución, un segundo componente, una biblioteca, se engancha a el programa que se quiere proteger y haciendo uso de las instrucciones añadidas por el compilador va tomando nota de los tipos y número de parámetros de las funciones variádicas, para que en el momento en que se vayan a llamar hacer un chequeo de lo que realmente se está llamando frente a lo que se debería de haber llamado.

Stephen Falken
Acerca de
Maker of W.O.P.R. (AKA Joshua)
Expertise: Artificial Intelligence, Wargames, Supercomputers