Upload
others
View
7
Download
0
Embed Size (px)
Citation preview
Universidad de Costa Rica
Sistema de Estudios de Posgrado
DEFENSA DINAMICA PARA LA PREVENCIONDE LA VULNERABILIDAD USE-AFTER-FREE
EN SISTEMAS EMBEBIDOS
Trabajo final de investigacion aplicada sometido a laconsideracion de la Comision del Programa de Estudios de
Posgrado en Computacion e Informatica para optar al grado ytıtulo de Maestrıa Profesional en Computacion e Informatica
DAVID HERDOIZA MORALES
Ciudad Universitaria Rodrigo Facio, Costa Rica
2018
Quitar esta
i
Dedicatoria
A mi madre y a mi padre.
ii
Agradecimientos
Quiero agradecer a la Dra. Gabriela Barrantes Sliesarieva quien ha estado junto a
mı durante el desarrollo de este trabajo y me ha orientado en todo el proceso. Muchas
gracias por su apoyo y guıa en este proyecto.
iii
“Este trabajo final de investigacion aplicada fue aceptado por la Comision del
Programa de Estudios de Posgrado en Computacion e Informatica de la Universidad
de Costa Rica, como requisito parcial para optar al grado y tıtulo de Maestrıa
Profesional en Computacion e Informatica.”
Dr. Juan Jose Vargas Morales
Representante del Decano
Sistema de Estudios de Posgrado
Dra. Gabriela Barrantes Sliesarieva
Profesora Guıa
Dra. Ileana Castillo Arias
Representante de la Directora
Programa de Posgrado en Computacion e Informatica
David Herdoıza Morales
Candidato
iv
Indice general
Dedicatoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii
Hoja de Aprobacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv
Indice general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii
Indice de figuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
Indice de cuadros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x
Palabras Clave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
1. Introduccion 1
1.1. Antecedentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3. Justificacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4. Trabajo Relacionado . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5. Descripcion del resto del documento . . . . . . . . . . . . . . . . . . . . 7
2. Marco Teorico 8
2.1. Tabla de Funciones Virtuales . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2. Vulnerabilidades de memoria . . . . . . . . . . . . . . . . . . . . . . . . 10
3. Descripcion de la defensa propuesta 14
4. Metodologıa de pruebas 20
4.1. Descripcion del ambiente de prueba . . . . . . . . . . . . . . . . . . . . 20
4.2. Descripcion del experimento . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3. Evaluacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5. Resultados y analisis 34
5.1. Eficacia de la defensa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.2. Eficiencia de la defensa . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.3. Eficacia de la defensa con un programa real . . . . . . . . . . . . . . . 36
5.4. Comparacion con defensas similares . . . . . . . . . . . . . . . . . . . . 37
v
6. Conclusiones y trabajo futuro 39
6.1. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.2. Trabajo futuro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
vi
Resumen
La vulnerabilidad Use-After-Free ocurre por un mal manejo de punteros por parte
del autor del programa, generalmente cuando el programa es escrito en lenguajes que
no hacen un manejo automatico de la memoria como C/C++. Si un atacante logra
aprovecharse de una vulnerabilidad Use-After-Free puede lograr ejecucion arbitraria de
codigo, controlando ası el flujo del programa atacado. El atacante podrıa tomar control
total de un sistema y comprometer su integridad, confidencialidad y disponibilidad.
La gran demanda de dispositivos IoT ha provocado un crecimiento en el desarrollo de
sistemas embebidos que usan C/C++, incrementando el problema de vulnerabilidades
de este tipo en estos sistemas.
En este trabajo final se propone una defensa dinamica para la vulnerabilidad Use-
After-Free en sistemas embebidos y se muestra su diseno, implementacion y evaluacion.
La defensa se diseno en torno a la proteccion de la tabla de funciones virtuales de un
objeto de C++. Se agrega una funcion extra en el codigo del programa a ser defendido
la cual se encarga de verificar que la direccion de una funcion que se encuentra en la
tabla de funciones virtuales sea valida. Se implemento la defensa para que fuera sencilla
de instalar en un sistema. La defensa como tal es un programa ejecutable el cual se va
a encargar de ejecutar otro programa y lo va a proveer de la defensa necesaria para
evitar que sea atacado por la vulnerabilidad Use-After-Free.
La evaluacion de la defensa se realizo probando su eficacia y eficiencia. Para medir
la eficacia se probo la defensa con ambientes de ataque sinteticos y con vulnerabilidades
reales de Use-After-Free para el navegador web Chromium. La defensa logro exitosa-
mente detener los ataques y prevenir que se explotara Use-After-Free en todos los casos.
Para medir la eficiencia se crearon programas de prueba que realizaran un alto numero
de llamadas a funciones virtuales. Para un programa que realiza 10 millones de llamadas
a funciones virtuales, la defensa solo supone un 0,35 % de impacto en el rendimiento.
vii
Abstract
The Use-After-Free vulnerability occurs due to poor handling of pointers by the
author of the program, generally when the program is written in languages that do
not make an automatic handling of the memory as C/C ++. If an attacker manages
to exploit a vulnerability Use-After-Free he can achieve arbitrary code execution, thus
controlling the flow of the attacked program. The attacker could take full control of a
system and compromise its integrity, confidentiality and availability. The great demand
of IoT devices has caused a growth in the development of embedded systems that use
C/C ++, increasing the problem of vulnerabilities of this type in these systems.
In this final work a dynamic defense for the Use-After-Free vulnerability in em-
bedded systems is proposed as well as its design, implementation and evaluation. The
defense was designed around the protection of the virtual function table of a C++
object. An extra function is added in the code of the program to be defended which is
responsible for verifying that the address of a function that is in the table of virtual
functions is valid. The defense was implemented to be simple to install in a system.
The defense is an executable program which will be responsible for executing anot-
her program and will provide the necessary defense to avoid being attacked by the
Use-After-Free vulnerability.
The evaluation of the defense was done proving its effectiveness and efficiency. To
measure effectiveness, defense was tested with synthetic attack environments and with
real Use-After-Free vulnerabilities for the Chromium web browser. The defense success-
fully managed to stop the attacks and prevent it from exploiting Use-After-Free in all
cases. To measure efficiency, test programs were created that made a high number of
calls to virtual functions. For a program that makes 10 million calls to virtual functions,
the defense only makes a 0.35 % of impact on performance.
viii
Indice de figuras
1.1. Reportes de UAF por ano segun NVD [50]. . . . . . . . . . . . . . . . . 3
2.1. Jerarquıa de clases con funciones virtuales. . . . . . . . . . . . . . . . . 9
2.2. Representacion de una tabla de funciones virtuales en memoria. . . . . 10
2.3. Patron de un Use-After-Free en C++. . . . . . . . . . . . . . . . . . . 11
2.4. Esquema de un Heap Spray afectando un objeto polimorfico de C++ . 12
2.5. Extracto de un codigo en JavaScript de un ataque que utilizo la tecnica
de Heap Spray [22] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1. Programa en C++ que hace uso de funciones virtuales. . . . . . . . . . 15
3.2. Thunk generado por el compilador GCC para ARM de 32 bits. . . . . . 15
3.3. Flujo de la defensa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.1. Diferencia en milisegundos del impacto al rendimiento con la defensa
activada. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2. Diferencia en porcentaje del impacto al rendimiento con la defensa activada. 36
ix
Indice de tablas
4.1. Lista de vulnerabilidades UAF analizadas. . . . . . . . . . . . . . . . . 25
5.1. Rendimiento de los programas de prueba con y sin la defensa. . . . . . 35
5.2. Resultados de la eficacia de la defensa para vulnerabilidades UAF reales
para el navegador web Chromium . . . . . . . . . . . . . . . . . . . . . 37
x
Palabras clave
Vulnerabilidades de memoria, Use-After-Free, UAF, Heap Spray, VTables, Tabla de
funciones virtuales, Defensa dinamica, Sistemas embebidos, Internet of Things.
xi
1Capıtulo 1
IntroduccionEn el area de la seguridad de software existen diferentes tipos de amenazas que
permiten a un atacante tomar control de un programa ejecutando codigo de forma
arbitraria. El mal manejo de memoria es la principal causa, creando vulnerabilidades
tales como buffer overflows [5], heap overflows [6], format strings [7] y Use-After-Free
[12, 21], entre otros. Los atacantes han usado estas vulnerabilidades por anos para
realizar ataques a personas o empresas, denegaciones de servicio o robo de propiedad
intelectual [54, 50]. En 2015, la companıa de seguros Lloyds estimo que los ataques de
seguridad le cuestan a los negocios hasta $400 billones por ano [33]. En 2014, Hewlett
Packard realizo un estudio en IoT (Internet of Things) el cual revelo que el 70 % de
dispositivos son vulnerables a ataques [40], esto supone un riego mayor conforme incre-
mente su uso. Intel proyecta un crecimiento para el 2020 de 200 billones de dispositivos
conectados [24]. En 2016, el ataque de denegacion de servicio mas grande fue lanza-
do usando una botnet llamada Mirai de dispositivos IoT vulnerables, principalmente,
camaras de seguridad [26].
Las vulnerabilidades producidas por un mal manejo de memoria se han explota-
do mas en lenguajes que brindan la libertad de decidir como manejar la memoria de
un programa, tal como C/C++. Estos lenguajes no brindan controles de memoria au-
tomaticos sino que relegan esta tarea al programador [56, 5, 12, 21, 31, 38, 54]. Algunas
de las vulnerabilidades mas usadas en estos lenguajes, tales como los buffer overflow,
han venido disminuyendo, sin embargo, aun existen vulnerabilidades que han venido en
aumento, como el Use-After-Free (UAF)[50]. Esta vulnerabilidad se ha explotado en
navegadores web, debido a su complejidad al momento de interpretar el codigo JavaS-
cript de un sitio web. Esto ha permitido que atacantes puedan tomar control de forma
remota del navegador web cuando un usuario trata de acceder a un sitio web y el codigo
JavaScript proveniente de la pagina se interpreta en el navegador del usuario de forma
local [46, 28].
La gran demanda de dispositivos IoT, especialmente los que son basados en Linux,
ha provocado un crecimiento del desarrollo de sistemas embebidos [13]. De acuerdo con
un estudio realizado en el 2018 por IEEE Spectrum, C y C++ tuvieron el puesto mas
alto en los lenguajes mas usados para el desarrollo de sistemas embebidos [49]. Estas
2
plataformas suelen ser blancos de ataque para ataques que exploten el mal manejo de
la memoria, como el caso Use-After-Free.
La defensa que se implementara tiene como objetivo evitar que un atacante tome
control de forma arbitraria de un sistema embebido debido al aprovechamiento de la
vulnerabilidad Use-After-Free. Use-After-Free (UAF) ocurre debido al mal manejo de
punteros por parte del autor del programa, generalmente escrito en lenguajes como
C/C++. Como su nombre lo indica, sucede al reservar memoria dinamica en un puntero,
seguidamente el puntero se libera y despues se vuelve a utilizar despues de haber sido
liberado. Para explotar esta vulnerabilidad, un atacante reserva tanta memoria libre
como sea posible realizando un heap spray con el fin de poder ocupar la misma direccion
de memoria que tenıa el puntero que va a ser reusado [17]. Si se logra, el atacante puede
reservar memoria con su propio codigo a ejecutar y si el puntero siendo controlado es
un puntero a una funcion, este va a ejecutar el codigo del atacante. Los punteros a
funciones son la principal entrada de ataque para la vulnerabilidad Use-After-Free y
son mas frecuentes en codigo escrito en C++ ya que los objetos de C++ presentan una
tabla de funciones virtuales que puede ser controlada. [50, 60, 58, 28, 46, 39, 34].
Para poder defenderse de la vulnerabilidad UAF se han implementado diferentes
tipos de defensas. Estas defensas generalmente recurren a realizar dos tipos de tareas.
Primero, un analisis del codigo para detectar la vulnerabilidad y despues, suelen imple-
mentar la defensa instrumentando el codigo. El analisis del codigo puede ser realizado
estaticamente, cuando el codigo no esta siendo ejecutado, por lo que se suele realizar
sobre el binario o codigo fuente. Tambien puede ser realizado dinamicamente, cuando
el codigo esta siendo ejecutado, para ello se realiza el analisis en memoria. Se tiene la
ventaja de que los datos y flujos del programa son reales [15]. La instrumentacion de
codigo puede ser realizada tambien estatica o dinamicamente, si es estatica, se realiza
cuando el codigo no esta siendo ejecutado y si es dinamica se realiza mientras el codigo
esta siendo ejecutado [25].
A pesar de existir diferentes tipos de defensas, la vulnerabilidad UAF aun no ha sido
resuelta completamente [46]. Es por eso que es importante explorar una metodologıa
de defensa adicional. En este documento se propone y describe la implementacion de
una defensa dinamica para la vulnerabilidad UAF en sistemas embebidos.
3
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
0
100
200
300
Ano
Rep
ortes
Figura 1.1: Reportes de UAF por ano segun NVD [50].
1.1. Antecedentes
Los ataques UAF han venido creciendo desde el 2006, ano en que se reporto por
primera vez la vulnerabilidad UAF en la National Vulnerability Database (NVD) [50].
Como se puede ver en la figura 1.1, a partir del 2010 los reportes sobre ataques UAF
han aumentado considerablemente, convirtiendose en una de las vulnerabilidades mas
usadas para la ejecucion arbitraria de codigo.
Pese a los esfuerzos para detener los ataques de UAF, no se ha logrado tener una
solucion eficaz a este problema. La deteccion de esta vulnerabilidad es especialmente
difıcil, mas aun cuando se agrega el problema de diferentes hilos accediendo a un mismo
puntero [46]. Muchos programas populares y escritos en C/C++ han reportado haber
sido vulnerados con UAF. Adobe’s FlashPlayer y varios navegadores de internet como
Internet Explorer y Google Chrome son algunos ejemplos [28, 50]. Estas aplicaciones
estan entre las mas utilizadas entre usuarios finales por lo que una defensa para la
prevencion de la vulnerabilidad UAF mejorarıa significativamente su seguridad.
Los navegadores web son el blanco predilecto de los atacantes, principalmente las
versiones implementadas para sistemas embebidos [31]. Esto sucede porque se utiliza
el mismo codigo base para crear diferentes implementaciones especıficas para diferentes
plataformas. El codigo base que se utiliza es Webkit, una solucion abierta y popular
4
entre los desarrolladores de sistemas embebidos [57]. El problema de usar la misma
implementacion en diferentes navegadores y ademas diferentes plataformas causa que
una sola vulnerabilidad afecte a todas las demas versiones del navegador web. Cuando la
vulnerabilidad se arregla, es complicado para las demas versiones incorporar los cambios
a tiempo o incorporarlos del todo si ya el codigo ha cambiado producto de ser adaptado
a necesidades especıficas producto de las diferencias del hardware soportado. [55].
Esta investigacion tiene como objetivo implementar una defensa dinamica que actue
en el tiempo de ejecucion del programa. Esto permite no tener que modificar el ejecu-
table del programa evitando crear diferentes versiones de un programa ya existente.
Ademas, a diferencia de otros tipos de defensas, no se necesita tener que compilar el
programa de nuevo para implementar la defensa. Este tipo de defensas son principal-
mente utiles en programas viejos aun utilizados de los cuales no se tiene el codigo
fuente, por lo que no se les puede realizar una actualizacion que arregle posibles vulne-
rabilidades, algo comun en sistemas embebidos [4]. Por ultimo, esta defensa pretende
mitigar vulnerabilidades UAF en tiempo de ejecucion independientemente de la version
del programa que se este defendiendo. Esto permite que si una vulnerabilidad es descu-
bierta en otra plataforma, esta no impacte el programa siendo defendido el cual puede
encontrarse en otra plataforma con una version diferente.
1.2. Objetivos
Ya que no existen defensas que resuelvan de forma completa el problema de los
ataques que se aprovechan de vulnerabilidades UAF en sistemas embebidos, se pretende
crear una defensa dinamica que logre detener los ataques de UAF. Para eso se plantean
los siguientes objetivos.
Objetivo General
Disenar y validar una defensa contra la vulnerabilidad Use-After-Free
para programas escritos en C++, resistente a ataques de ejecucion arbitraria
de codigo y que pueda ser utilizada en el contexto de sistemas embebidos y
IoT.
5
Objetivo Especıfico 1
Describir las principales limitaciones de las implementaciones de defensas
para la vulnerabilidad Use-After-Free existentes, ası como las consideracio-
nes especiales de diseno en el contexto de sistemas embebidos.
Objetivo Especıfico 2
Implementar una defensa dinamica que proteja la tabla de funciones
virtuales de objetos de C++ en una arquitectura ARM y que sea aplicable
a sistemas embebidos.
Objetivo Especıfico 3
Validar la eficacia y eficiencia de la defensa bajo ataques de ejecucion
remota de codigo.
1.3. Justificacion
Dado el incremento de vulnerabilidades UAF por ano [50] y como estas afectan a
todo tipo de sistemas, incluyendo a sistemas embebidos [53], es importante fortalecer
esta area proveyendo mecanismos de defensa.
En este caso, se presenta una defensa que pretende detener vulnerabilidades UAF
en sistemas embebidos. La implementacion de esta defensa ayudara a sistemas que no
reciben actualizaciones de seguridad con los respectivos parches para estas vulnerabi-
lidades, o que no lo logran recibir a tiempo dandole una ventaja al atacante al poder
usar vulnerabilidades que ya han sido reportadas publicamente [55].
La ventaja de tener una defensa dinamica es que esta corre todo el tiempo mientras
se encuentre activa y el programa a ser defendido se este ejecutando. Esto permite que
cuando se encuentra una nueva vulnerabilidad, el programa que esta corriendo no tenga
que ser modificado o recompilado para seguir siendo defendido [56, 45, 15].
Debido a que una defensa dinamica agrega trabajo al sistema, se evaluara el desem-
peno con el fin de verificar que la defensa pueda ser utilizada en un ambiente de pro-
duccion, para que el usuario no se vea afectado por el overhead que esta pueda causar
6
[45]. Las defensas dinamicas han sido poco explotadas en sistemas embebidos ya que la
velocidad y el bajo consumo de recursos han sido las prioridades [44].
1.4. Trabajo Relacionado
Muchas investigaciones se han hecho con el fin de mitigar la vulnerabilidad UAF. En
esta seccion se presenta un resumen de los principales tipos de defensa encontrados en
la literatura. Se categorizaron en cuatro diferentes grupos [29] de acuerdo a su metodo
de defensa propuesto: VTable protection, Use-After-Free protection, Secure allocators y
Memory analyzers, los cuales van a ser descritos a continuacion.
VTable protection : Las defensas en esta categorıa [47, 56, 19] pretenden defender
la tabla de funciones virtuales que tienen los objetos de C++. Verificar la integridad
de la tabla de funciones virtuales o vtables es uno de los metodos utilizados o veri-
ficar cuando un puntero es liberado y este no puede acceder de nuevo a su tabla de
funciones. Estas defensas suelen ser poco factibles al tener que modificar el ejecutable
con el fin de defender las tablas de funciones, en otros casos no son efectivas cuando
se realizan ataques de reutilizacion de codigo. La defensa dinamica propuesta en este
documento es de este tipo, con la diferencia de proveer un mecanismo dinamico para
prevenir la vulnerabilidad UAF sin necesidad de la modificacion del ejecutable y toma
en consideracion los ataques de reutilizacion de codigo.
Use-After-Free protection : Este metodo ataca el problema de la creacion, li-
beracion y reutilizacion de punteros. Las defensas que hacen uso de este metodo
[60, 46, 16, 11, 39, 58, 18, 14, 42, 6, 30] pretenden verificar que el programa no realice
esta secuencia de pasos sobre un puntero de modo que no se pueda disparar la vul-
nerabilidad. Realizar un analisis estatico del codigo buscando este patron es uno de
los metodos mas utilizados en combinacion con otras tecnicas. Estas defensas suelen
realizar un analisis estatico el cual puede terminar en falsos positivos o ser ineficiente
para ejecutables mas grandes.
Secure allocators : Muchas defensas [31, 36, 21, 5] hacen uso de la modificacion
de las funciones para la asignacion o liberacion de memoria de modo que puedan garan-
tizar que los objetos en memoria al ser liberados no vuelvan a ser accedidos. Tambien
permiten rastrear un puntero desde su creacion hasta su liberacion validando cada uso
de este. Estas defensas suelen fallar al implementar una debil defensa al momento de
7
asegurar las funciones de asignacion de memoria. El objetivo de estas defensas es hacer
un manejo de memoria menos predecible para el atacante realizando diferentes tecnicas
como liberar la memoria en un tiempo aleatorio. Al no poder ser lo suficientemente
aleatoria un atacante puede determinar el comportamiento de la memoria haciendo que
la defensa sea facil de burlar.
Memory analyzers: La deteccion generica de vulnerabilidades de memoria y a la
vez UAF ha sido investigada ampliamente [28, 34, 7, 62, 23, 54, 37, 12, 38, 61]. Estas
defensas realizan inspecciones de memoria buscando fallos comunes o realizando una
verificacion automatica de la memoria que no se va utilizar, tambien la verificacion
de punteros y su uso. Muchas de estas defensas logran servir de garbage collector para
lenguajes que no tienen esta caracterıstica. Este tipo de defensas resultan poco practicas
para ambientes de produccion al agregar una sobre carga de procesamiento importante
[61].
Pese a que se han propuesto diferentes tipos de defensas, muchas de estas no ofrecen
una completa proteccion o una defensa eficaz, como se ve en el crecimiento de ataques
de UAF en los ultimos anos [50].
1.5. Descripcion del resto del documento
El resto del documento se organiza de la siguiente forma. En el capıtulo 2 se define
el marco teorico en el cual se detallan conceptos para entender la defensa como la tabla
de funciones virtuales y las vulnerabilidades de memoria. Seguidamente, en el capıtulo
3 se describe la defensa propuesta. Asimismo, en el capıtulo 4 se define la metodologıa
de evaluacion definida la cual explica detalladamente los pasos seguidos para cumplir
con los objetivos del estudio. Seguidamente, en el capıtulo 5 se realiza un analisis de
los resultados obtenidos de los experimentos ejecutados. Por ultimo, en el capıtulo 6
se presentan las conclusiones de la investigacion donde se evidencia si se logro cumplir
con los objetivos planteados y se prepara el terreno para el trabajo futuro.
8Capıtulo 2
Marco TeoricoEn esta seccion se presentan conceptos de seguridad y sistemas embebidos para
entender la defensa planteada. Es importante entender el funcionamiento de las tablas
de funciones virtuales que se utilizan en C++ ya que es la principal entrada de ataque
para la vulnerabilidad UAF. Igualmente, es importante conocer como se explota la
vulnerabilidad UAF entendiendo el funcionamiento de esta en memoria y como un
atacante puede aprovecharse de esto para lograr ejecutar codigo de forma arbitraria. Se
quiere entender cual es el patron de una vulnerabilidad UAF, especialmente el codigo
en C++ que la representa y como este es interpretado por el compilador.
2.1. Tabla de Funciones Virtuales
Tıpicamente un programa escrito en C/C++ lleva un proceso de compilacion y
enlazamiento. En la etapa inicial de compilacion, varios archivos son compilados de
forma independiente generando archivos objeto resultantes, por ultimo estos se enlazan
de forma ordenada junto con otras librerıas ya compiladas para generar el ejecutable
final [1].
Este proceso final es realizado por un programa llamado enlazador o Linker en
ingles y se encarga, entre otras cosas, de reemplazar los llamados a funciones por las
direcciones de memoria que van a tener cuando el ejecutable sea cargado en memoria.
Existen dos tipos de enlazado, el estatico y el dinamico. Para entender la tabla de
funciones virtuales y su importancia se explicara el enlazamiento dinamico en C++
[52].
El lenguaje de programacion C++ tiene la capacidad de soportar programacion
orientada a objetos (POO) por lo que su enlazado difiere de otros lenguajes parecidos
que no soportan orientacion a objetos, tal es el caso del lenguaje C. La POO le permite
a C++ utilizar polimorfismo, debido a esto se pueden definir jerarquıas de clases con
su propia implementacion para una funcion en especıfico [1]. Debido a que un objeto en
C++ se puede definir como su clase base e instanciar de forma dinamica en alguna de
sus clases derivadas, no es posible saber de forma estatica y en tiempo de compilacion
que implementacion de dicha funcion virtual se va a utilizar [1].
9
Un enlazador ocupa realizar las siguientes tres tareas para que un objeto polimorfico
pueda llamar a la funcion correcta en tiempo de ejecucion [52]:
1. Para cada clase que tenga funciones virtuales se crea una tabla llamada vtable de
punteros a funciones. Esta tabla mantiene una lista de punteros a funciones que
le pertenecen a una clase en especıfico. Ası se le puede asignar esta tabla a una
clase en tiempo de ejecucion.
2. Cuando un objeto polimorfico se instancia, se crea una variable oculta la cual co-
rresponde a un puntero llamado vptr que apunta a la tabla de funciones virtuales.
3. En tiempo de compilacion, se anade un trozo de codigo llamado thunk el cual
corresponde a unas pocas lineas en ensamblador que permiten calcular la direccion
de la funcion a llamar utilizando el vptr y vtable del objeto.
Se presenta en la figura 2.1 un ejemplo de una jerarquıa pequena de clases donde se
definen funciones virtuales las cuales se implementan en sus clases derivadas.
Figura 2.1: Jerarquıa de clases con funciones virtuales.
En la figura 2.2 se muestra como el compilador GCC para un ambiente Linux genera
la tabla de funciones virtuales de la figura 2.1 para poder ser utilizada por instancias
de una clase con metodos virtuales en tiempo de ejecucion. En tiempo de compilacion,
se crea la definicion de la funcion func1 y el enlazador la pone en la seccion de memoria
.text. Seguidamente pone en la seccion de memoria .rodata la tabla de funciones virtuales
para esta clase. De este modo, en tiempo de ejecucion, las instancias creadas en el heap
pueden encontrar la implementacion de una funcion correctamente. Las funciones no
virtuales de una clase no presentan este esquema de enlazamiento.
10
Figura 2.2: Representacion de una tabla de funciones virtuales en memoria.
2.2. Vulnerabilidades de memoria
Las vulnerabilidades de memoria se caracterizan por ser aprovechadas de tal for-
ma que un atacante logra corromper la memoria de un proceso siendo ejecutado para
forzarlo a comportarse de manera diferente [32]. El primer ataque importante se re-
gistro en 1988 cuando se libero Morris-Worm, que se aprovechaba por primera vez
de un desbordamiento del buffer en el stack para auto propagarse por internet cau-
sando denegacion del servicio en las maquinas afectadas[10]. Algunas vulnerabilidades
de corrupcion de memoria comunes son buffer overflows[2], heap overflows[36], format
strings[35] y Use-After-Free[39].
Esta investigacion se enfoca en la vulnerabilidad Use-After-Free. Como se ve en la
figura 2.3, esta ocurre cuando un programa crea un objeto en memoria, lo libera y
despues lo vuelve a utilizar. En el caso de C/C++, cuando se reusa un puntero que
ha sido liberado, si este no apunta a null, va a seguir apuntando a la memoria que
tenıa anteriormente, la cual es libre en un caso normal. Esto va a generar un fallo
11
de segmentacion al referenciar memoria libre. Este problema puede parecer trivial de
resolver pero hay ciertos casos cuando el ciclo de vida de un puntero es compartido
entre varios hilos corriendo al mismo tiempo, el manejo de la memoria del puntero se
vuelve menos predecible y puede ser destruido mientras otro hilo esta aun utilizandolo.
Esto sucede porque diferentes hilos tienen acceso a la misma memoria y pueden manejar
los mismos punteros, de modo que un hilo puede liberar un puntero mientras otro hilo
esta utilizandolo, lo que va a causar un fallo de segmentacion. Este tipo de fallos de
segmentacion los va a aprovechar un atacante para realizar un UAF [36]. De la misma
manera, un proceso puede controlar el ciclo de vida de un puntero que existe en otro
proceso si este proceso expone una interfaz que pueda crear, usar y destruir objetos
de C++ [36]. Por ejemplo, el proceso A va a atacar al proceso B el cual expone una
interfaz vulnerable a UAF, el proceso A va a usar la interfaz para crear un puntero,
despues liberarlo y por ultimo reutilizarlo, realizando diferentes llamadas a la interfaz
causando un UAF si el proceso B siendo atacado no valido correctamente el uso de
punteros.
Figura 2.3: Patron de un Use-After-Free en C++.
Para explotar esta vulnerabilidad se utiliza una tecnica llamada Heap Spray. Con-
siste en que un atacante reserva tanta memoria libre como sea posible con el fin de
poder ocupar la misma direccion de memoria que tenıa el puntero que va a ser reusado
12
[43]. Si se logra, el atacante puede reservar memoria con su propio codigo a ejecutar.
El objetivo del atacante es reemplazar la direccion de la variable oculta vptr para que
ya no apunte a la direccion de la vtable original del objeto sino que apunte al heap el
cual esta siendo controlado por el atacante como se puede ver en la figura 2.4[43].
Figura 2.4: Esquema de un Heap Spray afectando un objeto polimorfico de C++
Un Heap Spray requiere que un atacante tome control del contenido del heap del
proceso a ser atacado. Una de las formas mas sencillas es tomar ventaja del soporte para
algun lenguaje de scripting que pueda crear los objetos directamente en memoria. Esto
hace especıficamente vulnerables a un Heap Spray a los navegadores web ya que estos
procesan JavaScript en el lado del cliente que recibe la pagina web. En la figura 2.5 se
muestra un extracto de ataque real en JavaScript el cual se basa en poder reservar tanta
memoria como sea posible con un shellcode que sera el codigo arbitrario a ser ejecutado
por el atacante. En este caso, el atacante trata de reservar 1000 de estos segmentos,
basta con un segmento que logre ser reservado donde antes estaba un objeto de C++
para poder realizar el ataque. El objeto que se reuse en este segmente ejecutara el codigo
reservado por el atacante. En la figura 2.5, el atacante hace uso de un NOP sled para
aumentar la probabilidad de ejecutar su shellcode.
Un NOP sled es una parte del shellcode que se utiliza cuando un atacante quiere
ejecutar codigo de forma arbitraria y necesita realizar un salto del flujo normal de ejecu-
cion de un programa al codigo malicioso que fue inyectado [22]. Si el atacante no puede
13
Figura 2.5: Extracto de un codigo en JavaScript de un ataque que utilizo la tecnica deHeap Spray [22]
predecir con exactitud la direccion donde se va a inyectar el shellcode a ser ejecutado,
el atacante agrega un NOP sled al inicio del shellcode para aumentar la cantidad de
direcciones validas a las cuales el atacante puede brincar estando en el flujo normal
del programa [22]. Un NOP sled esta compuesto por mas de una instruccion NOP de
ensamblador, estas instrucciones no realizan ninguna accion, por ende, el atacante pue-
de brincar en una de estas instrucciones sin realizar ningun cambio en la ejecucion del
programa. Una vez el atacante se logro situar en el NOP sled, se van a seguir ejecutando
instrucciones NOP hasta llegar al shellcode [22].
14Capıtulo 3
Descripcion de la defensa propuestaDurante la investigacion de la defensa propuesta, se analizaron vulnerabilidades
publicas reportadas a NVD [50] que hicieran uso de la vulnerabilidad UAF para el
navegador web Chromium. El objetivo de esta investigacion era determinar el modo
en que una vulnerabilidad UAF es aprovechada por un atacante en un ambiente real.
Se identifico que un atacante en la mayorıa de casos va a tratar de tomar control del
puntero vptr de un objeto que apunta a la tabla de funciones virtuales de dicho objeto.
El objetivo del ataque es que vptr apunte a una direccion de memoria controlada por
el atacante donde el creo su propia tabla de funciones. Dicha tabla se va a usar para
brincar a codigo malicioso. Se concluye entonces que el objetivo de la defensa sera
defender esta tabla de funciones virtuales para que el atacante no logre ejecutar su
codigo de forma arbitraria aunque tenga control de vptr.
Para evitar que el atacante tome control de vptr se analiza el flujo de acciones
que ocupa hacer el procesador para poder llamar a funciones que estan en la tabla de
funciones virtuales de un objeto. Se va a usar en el programa mostrado en la figura 3.1
como referencia de un programa que hace un llamado a una funcion virtual. Se escoge
plantear la defensa en torno al segmento de codigo generado por el compilador para
resolver las llamadas a dichas funciones llamado thunk. En tiempo de compilacion, el
compilador va generar varias lıneas de codigo en ensamblador para resolver las llamadas
a funciones virtuales en tiempo de ejecucion, este codigo se denomina thunk. El thunk
correspondiente a la funcion virtual utilizada en la lınea 13 de la figura 3.1 se puede ver
en codigo de ensamblador ARM de 32 bits en la figura 3.2.
Se identifica que las 5 lıneas de codigo que se muestran en la figura 3.2 no verifican
que la direccion de la funcion virtual que se va a llamar esta en un espacio valido de
memoria. Esta es la razon por la que un atacante puede llamar a su propio codigo
dentro del heap despues de haber realizado el Heap Spray. Las funciones virtuales solo
pueden existir dentro de la seccion de memoria denominada RODATA [48].
El objetivo de la defensa va a ser agregar una verificacion extra al thunk verificando
que la llamada a la funcion original esta dentro de la seccion RODATA. Para realizar
esto, se va reemplazar el thunk por uno mas seguro de forma dinamica mientras el
programa esta siendo ejecutado. Hace falta definir como la defensa se va a encargar de
15
Figura 3.1: Programa en C++ que hace uso de funciones virtuales.
Figura 3.2: Thunk generado por el compilador GCC para ARM de 32 bits.
reemplazar todos los thunks del programa a ser defendido. El thunk que se observa en
la figura 3.2 realmente no cambia mucho con respecto a otros thunk generados por el
compilador. Hay dos cambios principales, en la lınea 2 de la 3.2 va a cambiar el ındice (0
en la figura) ya que este depende de la posicion donde se encuentre la funcion virtual en
la tabla de funciones virtuales. El segundo cambio es en la lınea 4 de la 3.2, la cantidad
de parametros puede cambiar por funcion. Si se toman en cuenta estos dos casos, se
puede usar el thunk como un patron para buscar mas en el codigo del programa a ser
defendido.
Las tablas de funciones virtuales son en sı un vector de punteros a funciones y por
lo tanto son almacenados en la seccion de memoria RODATA [48]. Esta seccion se usa
para almacenar constantes, por lo que su acceso es de solo lectura. De esta manera, la
defensa solo tiene que verificar que el puntero vptr este apuntando a una direccion de
memoria en RODATA y no a una direccion en alguna otra seccion que pueda estar siendo
controlada por el atacante. Debido a que RODATA se crea en tiempo de compilacion,
16
el atacante no puede modificar esta seccion de ninguna manera [48].
La defensa debe reemplazar el thunk creado por el compilador por uno mas seguro,
que valide que la funcion que se va a llamar este en el rango de memoria correcto.
Si se trata de agregar codigo nuevo para cada thunk en el programa se corromperıan
las llamadas a funciones normales o cualquier tipo de instruccion de salto. Ya que la
direccion a la que se va a saltar se calcula en tiempo de compilacion, una modificacion al
codigo corromperıa estas direcciones y requerirıa recalcularlas, lo que no es optimo. Para
resolver este problema se tiene que agregar la verificacion usando la misma cantidad de
instrucciones ya existentes en el thunk.
El thunk se va a reemplazar por una llamada a una funcion que verifique que la
direccion sea la correcta. En ARM de 32 bits, una llamada a una funcion equivale a
una instruccion, pero no podemos reemplazar todo el thunk por una instruccion ya que
corromperıa las instrucciones de salto del resto del programa. Se va a usar una instruc-
cion de salto y el resto de instrucciones debe permanecer en la misma cantidad, esto
se logra reemplazando el resto del thunk por instrucciones NOP, las cuales no realizan
ninguna accion [22]. La defensa debe inyectar la funcion de verificacion y reemplazar
los thunks con una instruccion de salto que salte a la funcion correcta. La instruccion
de salto de ARM utilizada para esta defensa es BL. BL o Branch with Link es una
instruccion que permite brincar a una direccion especificada con la caracterıstica de
que almacena en el registro r14 la direccion de la siguiente instruccion despues de BL
[3]. Se escogio esta instruccion ya que permite que la defensa use el registro r14 para
proporcionar una direccion de retorno a la funcion virtual que se esta verificando.
Ya que se tiene que calcular el OPCODE completo de la instruccion BL en tiempo de
ejecucion, se tiene entonces que saber en donde esta la funcion de verificacion inyectada
para poder calcular el OPCODE correcto y ası poder brincar a la funcion de verificacion.
El OPCODE se calcula de la siguiente manera:
1. Se resta la direccion actual de memoria que se esta ejecutando menos la direccion
de la funcion de verificacion. BL no brinca a una direccion exacta, ya que la di-
reccion no cabrıa dentro del OPCODE, BL ocupa brincar a una direccion relativa
a la direccion actual.
2. Se aplica la operacion de bit a bit NOT sobre el resultado del paso 1. Como
requerimiento, las direcciones a las que se salta deben estar en complemento de 2
17
[3] ya que las direcciones tienen que ser positivas.
3. Se hace un desplazamiento binario a la derecha de dos posiciones al resultado del
paso 2. Esto se hace para eliminar los ultimos 2 bits de la direccion, los cuales no
se usan por la instruccion de salto.
4. Se trunca el resultado del paso 3 aplicando una operacion de bit a bit AND entre
el resultado y el valor hexadecimal 0xebffffff. Esto se hace para eliminar cualquier
bit extra que no este en el rango de 0xebffffff.
5. Se le agrega el OPCODE de la instruccion de salto BL de ARM usando la ope-
racion de bit a bit OR entre el resultado del paso 4 y el valor hexadecimal
0xeb000000. Esto proporciona el resultado final del OPCODE el cual serıa el
valor en hexadecimal eb mas la direccion relativa de la funcion de verificacion.
El OPCODE resultante se va a utilizar para brincar a la funcion de verificacion.
Por ejemplo, si se tiene que la direccion actual es 0xe51b3010 y la direccion donde se
encuentra la funcion de verificacion es 0xe51c3000, despues de ejecutar el primer paso,
se obtiene el valor 0xffffffffffff0010. Despues de aplicar el segundo paso se obtiene el
valor 0xffef, en el paso 3 se obtiene 0x3ffb y como no hay bits de sobra, en el paso 4
obtenemos el mismo resultado de 0x3ffb. Por ultimo, anadimos el OPCODE de BL en
el paso 5 y obtenemos 0xeb003ffb como un OPCODE valido para saltar de 0xe51b3010
a 0xe51c3000.
La funcion de verificacion debe ser agregada por la defensa en un espacio de memoria
con privilegios de lectura y ejecucion para el programa a ser defendido. Para ello, la
defensa busca una direccion de memoria vacıa que cumpla con estos requisitos y que
sea del tamano suficiente para poder copiar la funcion de verificacion. La defensa usa
el archivo de mapeo de la memoria que crea Linux para cada proceso que es ejecutado.
Cuando Linux ejecuta un programa, se crea un archivo con el mapeo completo del
proceso que va a ejecutar. En este mapa se especifica cuales son las direcciones que
le pertenece a las diferentes secciones de memoria del programa, tambien muestra los
privilegios que tiene el proceso en cada seccion. El archivo que contiene este mapa se
almacena en /proc/proceso/maps donde proceso es el identificador del proceso para cual
el mapa fue creado. La defensa va a buscar en este archivo del mapa de la memoria del
proceso a ser defendido un segmento para el cual tenga privilegios de lectura y escritura.
18
Ya definimos que la defensa va prevenir un UAF validando que la direccion de la
funcion virtual es correcta, ası un atacante no puede llamar a una funcion virtual dentro
del heap que es donde se guarda durante un Heap Spray. Definimos que para realizar
esta validacion la defensa ocupa agregar una funcion de verificacion a la memoria del
programa a ser defendido, ademas ocupa reemplazar los thunks dentro del programa
por una llamada a esta funcion de verificacion usando el thunk como patron para buscar
las llamadas a funciones virtuales. Para realizar estas acciones de forma completa, la
defensa se crea como un programa que va correr como cualquier otra aplicacion en el
sistema.
El programa de la defensa va a tener la caracterıstica de ejecutar un programa
externo como proceso hijo, este programa externo sera el programa a ser defendido.
Esto le permite a la defensa detener el proceso hijo mientras esta corriendo para poder
realizar los cambios necesarios. Cuando el proceso hijo es detenido, la defensa va a
buscar el mapa de la memoria para poder agregar la funcion de verificacion y ademas
obtener las direcciones validas de RODATA necesarias para la funcion de verificacion.
Una vez tiene estos datos, el programa de la defensa va copiar la funcion de verificacion
en memoria ejecutable. El ultimo paso consiste en reemplazar en la seccion de TEXT
todos los thunks con el salto a la funcion de verificacion. Una vez realizada esta accion,
la defensa le devuelve el control de ejecucion a su proceso hijo, por ende, permite que
el programa a ser defendido pueda continuar con su ejecucion normal. El flujo descrito
anteriormente se puede observar en la figura 3.3. El flujo representa la interaccion entre
los diferentes actores para poder instalar la defensa con exito en el programa a ser
defendido.
La instalacion de la defensa desde la perspectiva de un usuario que quiera imple-
mentarla en su sistema es bastante sencilla. El programa de la defensa ocupa nada
mas la ruta del programa a ser defendido. El usuario debera proporcionar la ruta del
programa y ejecutar el programa de la defensa. El programa de la defensa va a ejecutar
el programa a ser defendido el cual va a correr con la defensa instalada, el programa de
la defensa no necesita seguir corriendo despues de haber instalado la defensa.
19
Figura 3.3: Flujo de la defensa.
20Capıtulo 4
Metodologıa de pruebasEn esta seccion se describe el ambiente de prueba que se utilizo durante la realizacion
de los experimentos. Este ambiente se basa en la motivacion de realizar una defensa
que se logre ejecutar en un sistema embebido debido a los problemas descritos en el
capıtulo 1 con los dispositivos Iot y como estos son vulnerables a ataques UAF. Ademas,
se definen los experimentos que se quieren ejecutar con la finalidad de verificar la defensa
ante ataques de UAF. Por ultimo se realiza la evaluacion de la defensa utilizando los
experimentos descritos en esta seccion.
4.1. Descripcion del ambiente de prueba
Primero, es necesario seleccionar un sistema que debera correr la defensa, debido a
que su arquitectura sera una parte fundamental del diseno. Se plantea crear una de-
fensa dinamica que ejecute su funcionalidad en tiempo de ejecucion, por lo tanto, solo
tendremos acceso al codigo binario del programa a ser defendido. Esto significa que la
defensa se diseno en torno a la arquitectura seleccionada. El objetivo de esta investi-
gacion era crear una defensa para un sistema embebido, se selecciono la arquitectura
de procesadores ARM de 32 bits. Esta arquitectura es usada extensivamente en dis-
positivos embebidos al ser basada en arquitectura RISC, esta tiene menor cantidad de
transistores por lo tanto un menor tamano y menor consumo de energıa [27].
Una vez seleccionada la arquitectura con la que se disenara la defensa, se escogio un
dispositivo embebido que usa esta arquitectura y que permite ejecutar nuestra defensa.
Se escogio utilizar un Raspberry pi 2B el cual usa el sistema operativo Rasbian basado
en Linux para sistemas embebidos [20] debido al auge de dispositivos IoT basados en
Linux. De esta forma, la defensa debera servir para cualquier dispositivo ARM con un
sistema operativo basado en Linux sin muchos problemas.
Con la arquitectura definida, se desarrollo la defensa usando C como lenguaje de
programacion, debido a que se requiere tener acceso a funciones del sistema operativo
implementadas en la biblioteca PTRACE implementada en C [41]. Esta biblioteca le
permite a la defensa tener acceso a la memoria de un proceso externo y poder modificarla
a gusto. Aparte de esta biblioteca, al usar C en un sistema operativo basado en Linux
21
tenemos acceso a muchas funciones de utilidad para controlar el sistema operativo que
solo existen en C, por ejemplo, tener acceso al mapeo de memoria de un proceso que
esta corriendo. Ademas, la defensa debera tener los privilegios necesarios para poder
acceder a la memoria del programa a ser defendido, tanto para escritura como para
lectura.
Una vez se haya implementado la defensa, se creo un banco de pruebas funcionales
que permitan determinar si la defensa esta funcionando correctamente. Estas pruebas
sirven para verificar que la defensa realiza las acciones correctas cuando es ejecutada.
Los resultados de estas pruebas no miden la efectividad de la defensa, unicamente
determinaran si la funcionalidad es la esperada.
4.2. Descripcion del experimento
Se evalua la defensa de dos maneras distintas, primero con respecto a su eficacia y
por ultimo a su eficiencia. La eficiencia de la defensa se evalua usando diferentes am-
bientes sinteticos similares a ambientes reales donde se puede explotar la vulnerabilidad
UAF. Para preparar dichos ambientes, se realizo un analisis de 30 vulnerabilidades UAF
que se hicieron publicas para el navegador web de codigo abierto Google Chromium. Se
escogio este navegador al ser de codigo abierto y proveer un sitio web para el manejo
del ciclo de las vulnerabilidades llamado Bugs Chromium [8] . Especıficamente, el ciclo
de las vulnerabilidades de Chromium se maneja de manera publica, desde el momento
en que se descubre un fallo de seguridad hasta el momento en que se arregla, lo que
brinda la posibilidad de saber como se arreglaron y por ende entender mejor el codigo
donde se encontraron y aprovecharon. Las vulnerabilidades UAF publicas se recolecta-
ron usando la base de datos de vulnerabilidades CVE Details [9]. El analisis de estas 30
vulnerabilidades permitio categorizar ambientes vulnerables a UAF al existir escenarios
comunes donde se repetıa el mismo fallo de seguridad.
El analisis de las 30 vulnerabilidades se realizo de forma sistematica y se explica a
continuacion:
1. Se obtuvo una lista de vulnerabilidades de UAF para Chromium de CVE Details
usando como filtro la cadena de busqueda: use after free Chromium.
2. Se recolectaron las primeras 30 vulnerabilidades que presentaran un enlace de la
22
vulnerabilidad a la herramienta Bugs Chromium con el fin de poder obtener el
parche al codigo que arregla la vulnerabilidad.
3. Se estudiaron los parches de seguridad al codigo de Chromium documentado en
la herramienta con el fin de entender las vulnerabilidades y el ambiente en el que
se desarrollan.
4. Se documento el ciclo de vida del puntero que causo el UAF y cual era el medio
que provoco la reutilizacion.
5. Se documentaron los ambientes que se presentaron en cada vulnerabilidad, los
cuales se agruparon de acuerdo a como se desarrollo el codigo vulnerable a UAF.
Como resultado de este analisis, se crearon 5 ambientes de ataque comunes donde
puede ocurrir la vulnerabilidad UAF. Todos estos escenarios describen un estado del
programa el cual un atacante utilizo para provocar un UAF y aprovecharlo de manera
exitosa con un Heap Spray y por ultimo logrando ejecucion arbitraria de codigo. Estos
escenarios son programas sinteticos los cuales por sı mismos tienen una vulnerabilidad
UAF aprovechable. Estos ambientes estan compuestos por uno o mas procesos que pue-
den tener varios hilos siendo ejecutados. La principal tarea del proceso es atacarse a sı
mismo y provocar una ejecucion arbitraria de codigo. Ya que no queremos realizar el
ataque manualmente, el ambiente es el programa vulnerable y tambien es el atacante,
por lo tanto, tiene un Shellcode por dentro y se va a atacar de forma automatica apro-
vechando un UAF y usando un Heap Spray para poder ejecutar el Shellcode. Todos los
ambientes descritos ejecutan el mismo codigo de forma arbitraria, este codigo consiste
en escribir en un archivo un valor numerico, esta accion no deberıa de ocurrir en el flujo
normal del programa.
El conjunto del programa vulnerable mas el ataque le llamaremos escenario de ata-
que y se definen a continuacion:
Escenario de ataque 1: Un proceso corriendo el cual recibe datos por la en-
trada estandar de datos, el proceso es unico y no se crean hilos aparte. Simula el
ambiente mas comun donde se tiene un puntero que no se manejo correctamente.
Al momento de ejecutarse, el proceso va a leer datos de la entrada estandar, la
combinacion adecuada de datos va a causar que se libere un objeto en memoria,
23
esta accion va a generar que el mismo programa realice un Heap Spray para llenar
este espacio con un Shellcode. Por ultimo, otro valor leıdo de la entrada estandar
va a causar un reuso del objeto liberado causando que se ejecute el Shellcode.
Escenario de ataque 2: Un proceso corriendo con dos hilos ejecutandose si-
multaneamente, recibe datos por la entrada estandar de datos. Simula el ciclo de
vida de un objeto que es compartido entre varios hilos, condiciones de carrera
suelen crear UAF frecuentemente en estos casos. Al momento de ejecutarse, el
proceso va a leer datos de la entrada estandar, la combinacion adecuada de datos
va a causar que el primer hilo cree un objeto en memoria compartida. La proxima
entrada de datos leıda por el proceso va a causar que el segundo hilo libere este
objeto en memoria, esta accion causa el que proceso principal realice un Heap
Spray para llenar el espacio del objeto liberado con un Shellcode. Por ultimo, otro
valor leıdo de la entrada estandar va a causar que el primer hilo use el objeto
liberado por el segundo hilo causando que se ejecute el Shellcode.
Escenario de ataque 3: Dos procesos corriendo simultaneamente, se comunican
entre ellos usando una interfaz de comunicacion entre procesos llamada Unix
Domain Socket que provee el sistema operativo Rasbian [51]. Un proceso va a
actuar como servidor mientras que el otro va a actuar como cliente. El servidor se
va a encargar de recibir datos del cliente usando un socket de Unix. Se simula el
ciclo de vida de un objeto que es controlado por un proceso externo. Al momento
de ejecutarse ambos procesos, el proceso cliente va a mandar datos por un socket,
el servidor va a estar escuchando este socket para leer los datos, la combinacion
adecuada de datos va a causar que el servidor cree un objeto en memoria. A
continuacion, el cliente manda otra combinacion de datos los cuales van a causar
que el servidor libere el objeto creado anteriormente en memoria, esta accion
causa el que proceso servidor realice un Heap Spray para llenar el espacio del
objeto liberado con un Shellcode. Por ultimo, otro valor leıdo del socket por el
servidor va a causar que el servidor use el objeto liberado causando que se ejecute
el Shellcode.
Escenario de ataque 4: Un proceso corriendo el cual recibe datos por medio de
un archivo XML. Simula la mayorıa de ataques de inyeccion de codigo a lectores
de PDF o procesadores de texto. En este caso, cuando el proceso es ejecutado,
24
se va a leer un archivo con formato XML. El proceso va a crear objetos basados
en la informacion leıda del documento, estos objetos realizan acciones sobre la
memoria del programa de acuerdo a la propia logica del programa. La combinacion
adecuada de informacion en el XML va a generar que se creen objetos, se destruyan
y se vuelvan a reutilizar. Al momento que el proceso destruye un objeto, se va
a realizar un Heap Spray usando un Shellcode embebido en el archivo XML. Al
momento de que el programa reutiliza el objeto, se va a ejecutar el codigo en el
Shellcode.
Escenario de ataque 5: Un proceso corriendo el cual recibe datos por medio
de un archivo el cual tiene codigo en JavaScript a ser interpretado. Simula la
mayorıa de ataques por medias paginas web maliciosas que usan JavaScript. Como
el codigo JavaScript de una pagina web se corre en el navegador del usuario,
el atacante puede aprovecharse de navegadores web vulnerables para ejecutar
codigo de forma remota [17]. Cuando se ejecuta el proceso, se va interpretar un
archivo con codigo JavaScript. Este archivo tiene la capacidad para crear objetos
de JavaScript, liberarlos, realizar un Heap Spray y por ultimo reusar los objetos
creados. El proceso en este caso, va a interpretar el lenguaje y va a crear memoria
cuando el codigo se lo pida, va a liberar memoria de la misma manera y ademas
va a utilizar los objetos que se creen en memoria si el lenguaje se lo pide. La
combinacion correcta de estas acciones va a provocar un ataque en el proceso
aprovechando un UAF y finalmente causando ejecucion de forma arbitraria.
El analisis de las 30 vulnerabilidades se documento en la tabla 4.1. Estas vulnera-
bilidades se agruparon en los escenarios descritos anteriormente con el fin de entender
el ambiente en el cual una vulnerabilidad UAF se puede presentar.
Estos ambientes de prueba se van a usar como punto de entrada de un ataque
para probar la efectividad de la defensa. La defensa debera poder detectar un ataque y
evitar que el ataque ejecute codigo de forma arbitraria. Se considerara exitoso cuando la
defensa logra escribir en un archivo especificado un 1, si el ataque es exitoso, el atacante
escribira un 2 si logra ejecutar codigo de forma arbitraria. La unica condicion para que
un escenario de ataque escriba un 1 es si este no logra ejecutar el ataque y por ende no
logra ejecucion arbitraria de codigo puesto que la caracterıstica para escribir un 2 esta
en el Shellcode. Si la defensa detecta el ataque, esta va a escribir el 1.
25
Tabla 4.1: Lista de vulnerabilidades UAF analizadas.
No. Codigo Descripcion Categorıa
1 CVE-2017-15399 Biblioteca libxml2 vulnerable a UAF al
procesar un archivo de XML malicioso
permitiendole al atacante controlar el
ciclo de vida de un objeto.
Escenario
de ataque
4
2 CVE-2017-15411 Biblioteca PDFium vulnerable a UAF
al procesar un archivo de PDF malicio-
so permitiendole al atacante controlar
el ciclo de vida de un objeto.
Escenario
de ataque
4
3 CVE-2017-15410 Biblioteca PDFium vulnerable a UAF
al procesar un archivo de PDF malicio-
so permitiendole al atacante controlar
el ciclo de vida de un objeto.
Escenario
de ataque
4
4 CVE-2017-5043 Mal manejo de punteros entre varios hi-
los le permiten a un atacante reutiliza-
cion de punteros.
Escenario
de ataque
2
5 CVE-2017-5039 Memoria no se libera correctamente de
un objeto provocando una reutilizacion
en otro hilo y por ende un UAF.
Escenario
de ataque
2
6 CVE-2017-5038 Variable es liberada y despues utilizada
en el mismo flujo del programa produc-
to de un mal manejo de punteros.
Escenario
de ataque
1
7 CVE-2017-5036 Biblioteca PDFium vulnerable a UAF
al procesar un archivo de PDF malicio-
so permitiendole al atacante controlar
el ciclo de vida de un objeto.
Escenario
de ataque
4
8 CVE-2017-5034 Un tab de Chromiun el cual es un pro-
ceso aparte se comunica con el proceso
principal de Chromium a traves de una
interfaz provocando un UAF al utilizar
incorrectamente un puntero.
Escenario
de ataque
3
26
Tabla 4.1: Lista de vulnerabilidades UAF analizadas. (Cont.)
No. Codigo Descripcion Categorıa
9 CVE-2017-5031 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
10 CVE-2013-6647 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
11 CVE-2017-5021 Variable es liberada y despues utilizada
en el mismo flujo del programa produc-
to de un mal manejo de punteros.
Escenario
de ataque
1
12 CVE-2017-5019 Un tab de Chromiun el cual es un pro-
ceso aparte se comunica con el proce-
so de otro tab de Chromium a traves
de una interfaz provocando un UAF al
utilizar incorrectamente un puntero.
Escenario
de ataque
3
13 CVE-2016-5219 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
14 CVE-2016-5216 Diferentes hilos manejando el ciclo de
vida de un puntero. Una condicion de
carrera provoca el UAF.
Escenario
de ataque
2
15 CVE-2016-5215 Variable es liberada y despues utilizada
en el mismo flujo del programa produc-
to de un mal manejo de punteros.
Escenario
de ataque
1
16 CVE-2016-5213 Memoria no se libera correctamente de
un objeto provocando una reutilizacion
en otro hilo y por ende un UAF.
Escenario
de ataque
2
17 CVE-2016-5211 Biblioteca PDFium vulnerable a UAF
al procesar un archivo de PDF malicio-
so permitiendole al atacante controlar
el ciclo de vida de un objeto.
Escenario
de ataque
4
27
Tabla 4.1: Lista de vulnerabilidades UAF analizadas. (Cont.)
No. Codigo Descripcion Categorıa
18 CVE-2016-5203 Biblioteca PDFium vulnerable a UAF
al procesar un archivo de PDF malicio-
so permitiendole al atacante controlar
el ciclo de vida de un objeto.
Escenario
de ataque
4
19 CVE-2016-5190 Diferentes hilos manejando el ciclo de
vida de un puntero. Una condicion de
carrera provoca el UAF.
Escenario
de ataque
2
20 CVE-2016-5185 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
21 CVE-2016-5184 Archivo PDF genera un UAF al no va-
lidarse correctamente el manejo de ob-
jetos que renderizan el PDF en el nave-
gador.
Escenario
de ataque
4
22 CVE-2016-5183 Biblioteca PDFium vulnerable a UAF
al procesar un archivo de PDF malicio-
so permitiendole al atacante controlar
el ciclo de vida de un objeto.
Escenario
de ataque
4
23 CVE-2012-5140 Diferentes hilos manejando el ciclo de
vida de un puntero, una mala valida-
cion del uso de un puntero genera un
UAF en un plugin de PDF
Escenario
de ataque
2
24 CVE-2012-5139 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
25 CVE-2016-5156 Diferentes hilos manejando el ciclo de
vida de un puntero, incorrecto uso de
unique ptr provoca el UAF al ser reuti-
lizado.
Escenario
de ataque
2
28
Tabla 4.1: Lista de vulnerabilidades UAF analizadas. (Cont.)
No. Codigo Descripcion Categorıa
26 CVE-2016-5151 Biblioteca PDFium vulnerable a UAF
al procesar un archivo de PDF malicio-
so permitiendole al atacante controlar
el ciclo de vida de un objeto.
Escenario
de ataque
4
27 CVE-2012-5137 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
28 CVE-2012-5133 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
29 CVE-2012-5125 Proceso de captura de imagenes genera
un UAF en el proceso principal cuan-
do ambos proceso se comunican usando
una interfaz de IPC a traves de sockets.
Escenario
de ataque
3
30 CVE-2012-5116 Autor de pagina en JavaScript puede
controlar la memoria del navegador re-
utilizando objetos ya liberados.
Escenario
de ataque
5
La segunda manera para evaluar la defensa sera midiendo el tiempo de ejecucion de
un programa antes y despues de haber implementado la defensa. Se midio el porcentaje
de sobrecarga que agrego la defensa al programa original. Para medir esto, se creo un
programa especial el cual hace un uso mas extensivo de las partes de codigo donde
la defensa corre y ası mide cuanto impacto realmente se esta agregando cuando se
anade la defensa. No se usaron programas de benchmarking ya que la defensa puede no
tener impacto alguno en el resultado de estos programas debido a que pueden no ser
vulnerables a ataques UAF.
Para medir la eficiencia de la defensa, se midio el impacto al rendimiento que causa
la defensa al programa donde la defensa se instalo. El programa a ser defendido pa-
ra medir el rendimiento es sintetico y creado especıficamente para esta prueba. Este
programa esta escrito en C++ con la finalidad de hacer un uso extensivo de funciones
virtuales. Se crearon 4 versiones del programa con un numero distinto de llamadas a
29
funciones virtuales. Estos programas se definen como programas de prueba de llamadas
a funciones virtuales y se definen a continuacion:
Programa de prueba 1: 500 mil llamadas a funciones virtuales. Al ejecutar
este programa, se va a llamar a una funcion virtual 500 mil veces y terminar.
Programa de prueba 2: 1 millon de llamadas a funciones virtuales. Al ejecutar
este programa, se va a llamar a una funcion virtual 1 millon de veces y terminar.
Programa de prueba 3: 5 millones de llamadas a funciones virtuales. Al ejecutar
este programa, se va a llamar a una funcion virtual 5 millones de veces y terminar.
Programa de prueba 4: 10 millones de llamadas a funciones virtuales. Al
ejecutar este programa, se va a llamar a una funcion virtual 10 millones de veces
y terminar.
La funcion virtual que se llama en cada programa de prueba es la misma y se encarga
de aumentar un contador global cada vez que se llama, este contador no se usa para
otra cosa durante la ejecucion del programa. Debido a que el numero de llamadas a
funciones virtuales va acoplado a la logica del programa y los requerimientos que tenga,
no se puede predecir realmente cuantas llamadas a funciones virtuales pueden existir
en un programa. El objetivo de las llamadas definidas en esta investigacion es ver si
hay un crecimiento del impacto en el rendimiento conforme se incrementa el numero de
llamadas a funciones virtuales.
Los datos para la medicion de la eficiencia se recolectaron primero sin la defensa,
midiendo lo que dura el programa en ser ejecutado de principio a fin y por ultimo se
recolectaron con la defensa instalada midiendo lo que dura el programa de igual manera
de principio a fin. Se compara al final las diferencias entre ambas mediciones.
Se quiere, ademas, correr la defensa en un programa real, utilizando una vulnerabi-
lidad real que haya sido documentada publicamente. De la misma manera, se utilizo la
base de datos de vulnerabilidades CVE Details [9] para recolectar 3 vulnerabilidades pa-
ra el navegador web Chromium. Se escogio este programa ya que previamente se habıan
estudiado sus vulnerabilidades y por ser un programa que se utiliza bastante en distin-
tas plataformas y por ende una vulnerabilidad descubierta en este programa se replica
a todas las plataformas donde se le de soporte. Se espera que la defensa logre evitar que
30
estas vulnerabilidades que explotan UAF se sigan replicando para la version del progra-
ma donde es vulnerable, se va a tomar como exito de la defensa si el ataque se vuelve
una denegacion de servicio del navegador web Chromium, de lo contrario se escribirıa
un 2 al archivo log.text ya que el ataque lograrıa ejecutar codigo de forma arbitraria.
Las vulnerabilidades recolectas que se probaran con la defensa son: CVE-2012-2885,
CVE-2012-2893 y CVE-2013-2864. La version de Chromiun que se va a utilizar y que
es vulnerable a estas tres vulnerabilidades de UAF es 27.0.1453.110, se usara ademas
la version compilada para la arquitectura ARM que corre en Rasbian. Esta version de
Chormiun no esta parcheada para las vulnerabilidades descritas anteriormente.
Por ultimo, se concluira si la defensa cumple con los objetivos propuestos para
defender ataques a la vulnerabilidad UAF en sistemas embebidos donde el rendimiento
es una prioridad.
4.3. Evaluacion
En esta seccion se hace el planteamiento del experimento y la ejecucion del mismo.
Para el analisis de la defensa, este documento propone la implementacion de dos expe-
rimentos que realizaran la evaluacion de la defensa propuesta tanto en eficacia como en
eficiencia.
El ambiente en el cual se van realizar los experimentos consta del sistema embebido
que se escogio describio en la seccion 4.1. Por lo tanto, el experimento se va a ejecutar
en un Raspberry pi 2B el cual usa el sistema operativo Rasbian. El sistema operativo no
tiene mas programas instalados que los programas que ya vienen en la imagen original de
este. Ademas, ningun programa externo sera ejecutado mientras se hagan las pruebas,
los unicos procesos ejecutados son los que corren de forma automatica cuando arranca
el sistema operativo. La defensa no variara en lo absoluto para las distintas corridas de
los experimentos.
El primer experimento consiste en medir la eficacia de la defensa. La entrada del
experimento son el conjunto de ambientes de ataque definidos en la seccion 4.1. Se va
a simular un ataque en un ambiente con y sin la defensa el cual debera resultar en
la escritura de un valor numerico en un archivo especifico llamado log.text. Se va a
considerar como ataque exitoso si el programa logra escribir un 2 en el archivo, si se
escribe un 1 significa que la defensa detecto y detuvo el ataque de forma satisfactoria.
31
Como se definio en la seccion 4.1, para que un escenario de ataque sea exitoso, el
programa de este escenario debe realizar un Heap Spray y lograr cargar un shellcode el
cual va a escribir un 2 en el archivo log.text, siendo esta la unica condicion para leer un
2 de dicho archivo. Si la defensa logra detener el ataque y evitar el Heap Spray evitando
que se cargue shellcode, el programa de la defensa va a ser el que escriba un 1 en el
archivo log.text, siendo esta la unica condicion para leer un 1 de dicho archivo.
Los pasos para ejecutar el experimento se definen a continuacion:
1. Se enciende el Raspberry pi 2B el cual debera iniciar el sistema operativo Rasbian.
2. Se espera 1 minuto a que inicialice el sistema operativo por completo. Se estimo
1 minuto como el tiempo mınimo de espera debido a que en promedio el Ras-
berry pi 2B dura 24 segundos en inicializar los procesos necesarios para el sistema
operativo. Usar 1 minuto nos da la certeza de que el sistema operativo inicio por
completo.
3. Se escoge un ambiente de ataque disponible aun no probado del conjunto de
ambientes de ataque.
4. Se ejecuta el ambiente de ataque sin ejecutar la defensa.
5. Se recolectan los resultados para este ambiente de pruebas manualmente del ar-
chivo log.text indicando que se ejecuto sin la defensa.
6. Se ejecuta la defensa y se le dice que corra el ambiente de ataque seleccionado en
el paso 3.
7. Se recolectan los resultados para este ambiente de pruebas manualmente del ar-
chivo log.text indicando que se ejecuto con la defensa.
8. Si aun hay ambientes de ataque no probados disponibles se brinca al paso 3.
Los resultados obtenidos se analizaron con el objetivo de demostrar la eficiencia
de la defensa en casos comunes donde se aprovecha una vulnerabilidad UAF en un
sistema embebido. Se determino si la defensa fue efectiva comparando el resultado de
no ejecutar la defensa y de haberla ejecutado.
32
El segundo experimento consiste en medir la eficiencia de la defensa. La entrada
de este experimento es el conjunto de programas que realizan llamadas a funciones
virtuales definidos en la seccion 4.2. Este programa tiene como objetivo ejercitar la
tabla de funciones virtuales protegidas por la defensa, de modo que se pueda evaluar
si existe algun impacto en el rendimiento provocado por la defensa. Cada programa de
prueba se va a ejecutar 100 veces con la defensa y 100 veces sin la defensa. El resultado
final de cada programa de prueba es el promedio en milisegundos de las 100 repeticiones.
Los pasos para ejecutar el experimento se definen a continuacion:
1. Se enciende el Raspberry pi 2B el cual debera iniciar el sistema operativo Rasbian.
2. Se espera 1 minuto a que inicialice el sistema operativo por completo. Se estimo
1 minuto como el tiempo mınimo de espera debido a que en promedio el Ras-
berry pi 2B dura 24 segundos en inicializar los procesos necesarios para el sistema
operativo. Usar 1 minuto nos da la certeza de que el sistema operativo inicio por
completo.
3. Se escoge la cantidad de llamadas a funciones virtuales, que no se haya ejecutado
aun.
4. Se toma el tiempo actual del sistema y se ejecuta el programa seleccionado en el
paso 3 sin la defensa.
5. Una vez que el programa termino de ejecutarse se recolecta el tiempo actual del
sistema.
6. El tiempo que duro el programa seleccionado en el paso 3 sin la defensa es la
diferencia entre el tiempo en el paso 5 y el tiempo en el paso 4.
7. Se toma el tiempo actual del sistema y se ejecuta el programa seleccionado en el
paso 3 con la defensa.
8. Una vez que el programa termino de ejecutarse se recolecta el tiempo actual del
sistema.
9. El tiempo en milisegundos que duro el programa seleccionado en el paso 3 con la
defensa es la diferencia entre el tiempo en el paso 5 y el tiempo en el paso 4.
33
10. Si aun falta probar el programa con un numero de llamadas a funciones virtuales
se pasa el paso 3.
11. Se realizan 100 repeticiones de los pasos anteriores para cada programa de prueba.
El objetivo de estas repeticiones es obtener un valor promedio de los tiempos que
dura cada programa en ser ejecutado. Los programas de prueba se mantienen igual
con la misma cantidad de llamadas a funciones virtuales definidas en la seccion
4.2.
12. Se obtiene un promedio en milisegundos de las 100 corridas con y sin la defensa
para cada una de las 4 pruebas.
Los resultados obtenidos se analizan con el objetivo de medir el aumento del tiempo
que duro el programa en ser ejecutado cuando se corrieron las pruebas con la defensa.
Idealmente se quiere saber si el impacto que tiene la defensa crece a medida que crecen
las llamadas a funciones en un programa. Las pruebas de rendimiento se corren primero
sin la defensa como base de lo que duran las llamadas a funciones de forma normal.
34Capıtulo 5
Resultados y analisisParte de los objetivos de esta investigacion era la evaluacion de la eficacia y eficiencia
de la defensa. Despues de haber definido los experimentos en el capıtulo 4 y haberlos
ejecutado, se obtuvieron los resultados que se presentaran en esta seccion.
5.1. Eficacia de la defensa
Los resultados del experimento de eficacia sin la defensa fue que todos los ambien-
tes de ataque lograron exitosamente correr codigo de forma arbitraria para todas las
repeticiones del experimento. Como es de esperarse, este experimento representaba el
caso base desde donde partimos. Para los resultados del experimento de eficacia con la
defensa se logro el objetivo de evitar que el ataque tuviera exito. Los resultados indican
que en ningun ambiente de ataque se logro ejecucion de codigo de forma arbitraria. Por
lo tanto, la defensa tuvo un porcentaje de exito del 100 % para todas las pruebas que
se hicieron en esta etapa. Este primer experimento valido que los valores recolectados
en el archivo log.txt fueron los correctos, no se encontro que ningun ambiente de ataque
haya logrado escribir un 2. En todas las ocasiones la defensa logro escribir un 1.
5.2. Eficiencia de la defensa
De igual forma, el experimento de eficiencia consistıa en dos partes, primero se
evaluaba los programas de prueba sin la defensa y despues con la defensa para ver
cuanta diferencia habıa causado la defensa. En la tabla 5.1 se puede observar el tiempo
en milisegundos que duran los programas de prueba en ser ejecutados con y sin la
defensa, esta figura muestra el aumento de tiempo que dura el programa conforme
aumentan las llamadas a funciones virtuales.
Se puede observar la tabla 5.1, la defensa no hace variar mucho el desempeno del
programa. Para 500 mil llamadas a funciones virtuales, en promedio la defensa aumento
el tiempo de este en 5 milisegundos de los 17,177 milisegundos que duraba sin la defensa,
lo que significa un impacto del 0,02 % del rendimiento original del programa. Para 1
millon de llamadas a funciones virtuales, en promedio la defensa aumento el tiempo de
35
Tabla 5.1: Rendimiento de los programas de prueba con y sin la defensa.
Sin defensa Con defensa500 mil llamadas 17177 ms 17182 ms1 millon de llamadas 33769 ms 33823 ms5 millones de llamadas 170189 ms 170449 ms10 millones de llamadas 350639 ms 351797 ms
este en 54 milisegundos de los 33,769 milisegundos que duraba sin la defensa, lo que
significa un impacto del 0,16 % del rendimiento original del programa. Para 5 millones
de llamadas a funciones virtuales, en promedio la defensa aumento el tiempo de este
en 260 milisegundos lo que significa un impacto del 0,15 % del rendimiento original del
programa. Y por ultimo, para 10 millones de llamadas a funciones virtuales, en promedio
la defensa aumento el tiempo de este en 1158 milisegundos de los 350,639 milisegundos
que duraba sin la defensa, lo que significa un impacto del 0,33 % del rendimiento original
del programa. En la figura 5.1 se observa el impacto en milisegundos que tiene la defensa
una vez instalada conforme aumentan las llamadas a las funciones virtuales. En la figura
5.2 se observa el porcentaje de impacto en el rendimiento del programa que tiene la
defensa instalada. Los resultados obtenidos en esta etapa se corrieron usando el sistema
embebido definido en el capıtulo 4, seccion 4.1.
Figura 5.1: Diferencia en milisegundos del impacto al rendimientocon la defensa activada.
36
Figura 5.2: Diferencia en porcentaje del impacto al rendimiento conla defensa activada.
El impacto de la defensa es mınimo, esto significa que sistemas embebidos podran
hacer uso de la defensa sin tener que preocuparse por un alto consumo de recursos
de procesamiento. Este bajo impacto en el rendimiento se obtuvo gracias a que la
defensa instala una verificacion bastante optima a nivel del ensamblador del programa
siendo ejecutado. A nivel de ejecucion, la defensa no agrega mucha complejidad mas que
verificaciones sencillas de que la tabla de funciones virtuales no ha sido comprometida.
La mayor parte del esfuerzo de la defensa se realiza mientras esta instala la defensa
cuando ejecuta el programa a ser defendido como se definio en el capıtulo 3.
5.3. Eficacia de la defensa con un programa real
Se probo la defensa con un programa real y utilizando vulnerabilidades reales que
fueron publicadas en CVE Details. El objetivo de esta prueba era validar la eficacia de
la defensa ante un escenario real. La defensa deberıa poder evitar que el ataque tuviera
exito, por ende evitar una ejecucion arbitraria de codigo. Si la defensa tenıa exito el
ataque no se realizarıa y el programa de la defensa escribirıa un 1 al archivo log.text, de
lo contrario, si el ataque tiene exito, se escribirıa un 2 al archivo log.text. Los resultados
37
de esta prueba fueron satisfactorios, la defensa logro que los ataques no se efectuaran
y ademas se obtuvo el valor de 1 del archivo log.text como se puede ver en la tabla 5.2.
Estos resultados implican que la defensa se logro instalar correctamente en un programa
real y en un ambiente real de un sistema embebido.
La implementacion que se definio en el capıtulo 3 permitio que la instalacion de la
defensa en el programa real fuera bastante sencilla.
Los resultados de esta investigacion, con base en los experimentos descritos anterior-
mente, son positivos tanto en eficacia como en eficiencia. La posibilidad de tener una
defensa dinamica que este constantemente evitando ataques que se aprovechen de la
vulnerabilidad UAF sin tener un impacto significativo de rendimiento es una gran ven-
taja. De esta manera, la defensa puede estar corriendo indefinidamente en un sistema
embebido, pese a que las actualizaciones de seguridad no lleguen a tiempo, el sistema
podra seguir siendo seguro sin afectar su usabilidad.
Tabla 5.2: Resultados de la eficacia de la defensa para vulnerabilidades UAFreales para el navegador web Chromium
Version de Chromium Vulnerabilidad Resultados27.0.1453.110 CVE-2012-2885 Escribio un 127.0.1453.110 CVE-2012-2893 Escribio un 127.0.1453.110 CVE-2013-2864 Escribio un 1
5.4. Comparacion con defensas similares
En la literatura existe trabajo relacionado a defensas para la vulnerabilidad UAF
que implementan protecciones para impedir que un atacante logre ejecutar codigo de
forma arbitraria. Zhang et al. presentaron en el 2017 un metodo para detectar UAF
en C++ controlando el manejo a memoria de los punteros que son reutilizados [63], de
forma que no haya acceso a la tabla de funciones virtuales si un puntero ya fue liberado.
La defensa presentada por Zhang introduce un 9 % de impacto en el rendimiento del
programa base con el que fue probado, el cual es considerable, sobre todo en el ambito
de sistemas embebidos.
De la misma manera, Yamuchi et al. presentaron en el 2017 un metodo de defen-
sa para la vulnerabilidad UAF basado en la instrumentacion de bibliotecas de Linux
38
encargadas del manejo de la memoria cuando se liberaban punteros, de forma que un
puntero liberado no pudiera reusar su tabla de funciones virtuales [59]. En el ambito
de eficiencia, esta defensa tuvo como resultado un 2.9 % de impacto en el rendimiento
del programa donde se instalaba. El rendimiento de esta defensa esta ligada el uso de
memoria en un programa, eventualmente, cuando el programa hace uso de memoria
por un largo tiempo el impacto comienza a aumentar. Este comportamiento impacta
en mayor medida a sistemas embebidos que hace un extensivo uso de programas por un
largo periodo de tiempo. La defensa propuesta en esta investigacion no hace cambios
en el manejo de la memoria a diferencia de la defensa propuesta por Yamuchi, por lo
que el uso de ella no deberıa ser un factor para medir el rendimiento.
Sarbinowski et al. [47] presentaron en el 2016 una defensa para verificar que las
funciones virtuales no fueran comprometidas, ellos logran esto creando vtables seguras
dentro de objetos controlados por la defensa. De esta manera, solo se pueden invocar
las funciones dentro de estas tablas controladas, ası el atacante no puede tener control
de ellas. La investigacion de Sarbinowski reporta un impacto al rendimiento del 4.1 %.
Pese a ser una defensa muy parecida a la que se diseno, el impacto del rendimiento es
mucho mayor al tener una optimizacion diferente.
39Capıtulo 6
Conclusiones y trabajo futuro6.1. Conclusiones
Las vulnerabilidades UAF vienen en crecimiento y su impacto es alto para el progra-
ma vulnerable al permitir ejecucion arbitraria de codigo. Pese a que estas vulnerabilida-
des se mitigan con parches de seguridad, la gran diversidad de dispositivos embebidos
producto del IoT ha hecho que un software diverja lo suficiente para que los parches de
seguridad no lleguen con la misma velocidad a todas las plataformas.
Se planteo como objetivo disenar una defensa para la vulnerabilidad UAF para pro-
gramas escritos en C++ para un sistema operativo basado en Linux y la arquitectura
ARM. Se planteo la defensa en torno a ser optima y que no requiriera un alto consumo
de memoria o procesamiento, ademas deberıa ser dinamica para no necesitar de modi-
ficaciones en el codigo fuente de los programas a ser defendidos. Estas consideraciones
se tuvieron en mente con el fin de que la defensa logre ser puesta en ambientes de
produccion para sistemas embebidos.
Se diseno la defensa para que de forma dinamica aplique una verificacion cada vez
que el programa a ser defendido hace una llamada a una funcion virtual. Exitosamente,
el algoritmo propuesto para evitar ataques de UAF logra evitar que un atacante se
aproveche del reuso de punteros ya liberados. Para lograr esto, la defensa busca en la
memoria del programa a ser defendido las llamadas a funciones virtuales y las reemplaza
por una llamada a una funcion de verificacion, esta funcion comprueba que la funcion
virtual que se iba a llamar este en una posicion de memoria correcta. Esta verificacion
logra evitar un ataque de UAF debido a que no le permite al atacante invocar funciones
desde el heap al momento de reusar un objeto. El atacante va a tratar de invocar su
shellcode desde el heap cuando realice el Heap Spray. La instalacion de la defensa
se realiza ejecutando el programa de la defensa, se le indica que programa se quiere
defender, el programa de la defensa se va a encargar de ejecutar el programa a ser
defendido y proveerlo de los mecanismos necesarios para evitar una vulnerabilidad UAF.
Esta investigacion tenıa como objetivo evaluar la eficacia y la eficiencia de la defensa
bajo ataques de ejecucion remota de codigo, estos dos factores son importantes debido
a que los sistemas embebidos requieren de defensas eficientes por la menor cantidad de
40
recursos que suelen tener. Los experimentos realizados de eficacia demuestran que la
defensa es capaz de detener ataques en los ambientes mas comunes donde se explotan
estas vulnerabilidades. Para poder tener un mejor criterio de como crear ataques sinteti-
cos para el experimento, se investigo ataques reales en vulnerabilidades publicas y los
ambientes en las que estas se aprovechan. Esta investigacion provee una metodologıa
de como investigar vulnerabilidades publicas, algo que hacen los atacantes comunmente
para aprovecharse de estas, en esta investigacion se usa el mismo metodo para crear
una defensa contra ataques de seguridad.
La eficiencia de la defensa era crıtica para poder ser utilizada en sistemas embebi-
dos, debido a la cantidad menor de recursos que tienen con respecto a una computadora
normal. Se realizo un experimento para evaluar la eficiencia el cual resulto exitoso al
impactar un 0.35 % al rendimiento de un programa que hace un uso extensivo de 10
millones de llamadas a funciones virtuales. El crecimiento del impacto del rendimiento
aumenta conforme aumentan las llamadas a las funciones virtuales pero en un porcenta-
je bastante bajo. En comparacion con otras defensas similares, el impacto de la defensa
planteada en este documento es bastante menor.
Los resultados satisfactorios obtenidos apuntan a que la defensa propuesta es factible
de implementar en un sistema embebido o cualquier sistema que sea basado en Linux
y proveer una defensa eficaz para vulnerabilidades UAF nuevas o vulnerabilidades que
se hayan vuelto publicas despues de haber sido arregladas.
6.2. Trabajo futuro
Como una mejora a futuro, se planea implementar la defensa en un ambiente donde
profesionales en seguridad tengan la libertad de atacar a un programa que esta siendo
defendido por la defensa planteada, esto podrıa validar si un atacante que desconozca
la implementacion realmente pueda saltarse las medidas de seguridad implementadas.
Diferentes organizaciones presentan espacios para que expertos en seguridad puedan
hacer uso de sus habilidades en diferentes escenarios. Este tipo de actividades podrıan
ser una buena opcion para probar este tipo de defensas que no suelen tener validaciones
de este tipo.
A futuro, se quiere medir el tiempo en que la defensa dura instalandose en programas
grandes. La instalacion en tiempo real de la defensa si se vuelve muy alta podrıa afectar
41
su usabilidad desde la perspectiva de un usuario que opta por utilizar la defensa. Pese a
que el tiempo en que dura un programa cargando antes de iniciar no suele ser molesto
para el usuario, si el programa es muy grande este tiempo podrıa ser significativo. Como
trabajo futuro se quiere medir este tiempo en programas reales.
42Bibliografıa[1] Aigner, Gerald y Urs Holzle: Eliminating virtual function calls in C++ programs.
En European conference on object-oriented programming, paginas 142–166. Sprin-ger, 1996.
[2] Aleph, One: Smashing the stack for fun and profit. http://www. shmoo.com/phrack/Phrack49/p49-14, 1996.
[3] ARM: ARM Compiler toolchain Assembler Reference, 2018. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489e/Cihfddaf.html, vi-sitado el 2018-08-11.
[4] Becher, M, FC Freiling, J Hoffmann, T Holz, S Uellenbeck y C Wolf: Mobile securitycatching up. En IEEE S&P, 2011.
[5] Berger, Emery D. y Benjamin G. Zorn: DieHard: Probabilistic Memory Safetyfor Unsafe Languages. paginas 158–168, 2006. http://doi.acm.org/10.1145/
1133981.1134000.
[6] Caballero, Juan, Gustavo Grieco, Mark Marron y Antonio Nappa: Undangle:Early Detection of Dangling Pointers in Use-after-free and Double-free Vulnera-bilities. En Proceedings of the 2012 International Symposium on Software Testingand Analysis, ISSTA 2012, paginas 133–143, New York, NY, USA, 2012. ACM,ISBN 978-1-4503-1454-1. http://doi.acm.org/10.1145/2338965.2336769.
[7] Chen, Gang, Hai Jin, Deqing Zou y Weiqi Dai: On-Demand Proactive Defenseagainst Memory Vulnerabilities, paginas 368–379. Springer Berlin Heidelberg, Ber-lin, Heidelberg, 2013, ISBN 978-3-642-40820-5. http://dx.doi.org/10.1007/
978-3-642-40820-5_31.
[8] Corporation, Google: Bugs Chromium, 2018. https://www.bugs.chromium.org,visitado el 2018-10-24.
[9] Corporation, MITRE: CVE Details, 2018. https://www.cvedetails.com/, visi-tado el 2018-10-24.
[10] Cowan, Crispan, Calton Pu, Dave Maier, Jonathan Walpole, Peat Bakke, SteveBeattie, Aaron Grier, Perry Wagle, Qian Zhang y Heather Hinton: Stackguard:Automatic adaptive detection and prevention of buffer-overflow attacks. En USE-NIX Security Symposium, volumen 98, paginas 63–78. San Antonio, TX, 1998.
[11] Dewey, D., B. Reaves y P. Traynor: Uncovering Use-After-Free Conditions in Com-piled Code. En 2015 10th International Conference on Availability, Reliability andSecurity, paginas 90–99, Aug 2015.
43
[12] Dhurjati, Dinakar, Sumant Kowshik y Vikram Adve: SAFECode: Enforcing AliasAnalysis for Weakly Typed Languages. SIGPLAN Not., 41(6):144–157, Junio 2006,ISSN 0362-1340. http://doi.acm.org/10.1145/1133255.1133999.
[13] Ebert, Christof y Capers Jones: Embedded software: Facts, figures, and future.Computer, 42(4), 2009.
[14] El-Zawawy, Mohamed A.: Detection of Probabilistic Dangling References in Multi-core Programs Using Proof-Supported Tools, paginas 516–530. Springer Berlin Hei-delberg, Berlin, Heidelberg, 2013, ISBN 978-3-642-39640-3. http://dx.doi.org/
10.1007/978-3-642-39640-3_38.
[15] Ernst, Michael D: Static and dynamic analysis: Synergy and duality. En WODA2003: ICSE Workshop on Dynamic Analysis, paginas 24–27, 2003.
[16] Feist, Josselin, Laurent Mounier y Marie Laure Potet: Statically detecting useafter free on binary code. Journal of Computer Virology and Hacking Tech-niques, 10(3):211–217, 2014, ISSN 2263-8733. http://dx.doi.org/10.1007/
s11416-014-0203-1.
[17] Gadaleta, Francesco, Yves Younan y Wouter Joosen: Bubble: A javascript enginelevel countermeasure against heap-spraying attacks. En International Symposiumon Engineering Secure Software and Systems, paginas 1–17. Springer, 2010.
[18] Galea, John y Mark Vella: SUDUTA: Script UAF Detection Using TaintAnalysis, paginas 136–151. Springer International Publishing, Cham, 2015,ISBN 978-3-319-24858-5. http://dx.doi.org/10.1007/978-3-319-24858-5_9.
[19] Gawlik, Robert y Thorsten Holz: Towards Automated Integrity Protection of C++Virtual Function Tables in Binary Programs. En Proceedings of the 30th AnnualComputer Security Applications Conference, ACSAC ’14, paginas 396–405, NewYork, NY, USA, 2014. ACM, ISBN 978-1-4503-3005-3. http://doi.acm.org/10.1145/2664243.2664249.
[20] Gay, Warren: Mastering the raspberry PI. Apress, 2014.
[21] Grimmer, Matthias, Roland Schatz, Chris Seaton, Thomas Wurthinger y Hans-peter Mossenbock: Memory-safe Execution of C on a Java VM. En Pro-ceedings of the 10th ACM Workshop on Programming Languages and Analy-sis for Security, PLAS’15, paginas 16–27, New York, NY, USA, 2015. ACM,ISBN 978-1-4503-3661-1. http://doi.acm.org/10.1145/2786558.2786565.
[22] Heetkamp, R. van den: Heap spraying, 2007. http://www.0x000000.com/index.
php?i=412&bin=110011100, visitado el 2017-08-11.
44
[23] Hiser, Jason D., Clark L. Coleman, Michele Co y Jack W. Davidson: MEDS: TheMemory Error Detection System, paginas 164–179. Springer Berlin Heidelberg,Berlin, Heidelberg, 2009, ISBN 978-3-642-00199-4. http://dx.doi.org/10.1007/978-3-642-00199-4_14.
[24] Intel: A guide to the internet of things, 2018. http://www.intel.com/content/
dam/www/public/us/en/images/iot/guide-to-iot-infographic.png, visitadoel 2018-10-24.
[25] Khazan, Roger, Jesse Rabek, Scott Lewandowski y Robert Cunningham: Techniquefor detecting executable malicious code using a combination of static and dynamicanalyses, Junio 2003. US Patent App. 10/464,828.
[26] Kolias, Constantinos, Georgios Kambourakis, Angelos Stavrou y Jeffrey Voas:DDoS in the IoT: Mirai and other botnets. Computer, 50(7):80–84, 2017.
[27] Kornau, Tim: Return oriented programming for the ARM architecture. Tesis deDoctorado, Master’s thesis, Ruhr-Universitat Bochum, 2010.
[28] Kouwe, Erik van der, Vinod Nigade y Cristiano Giuffrida: DangSan: Scalable Use-after-free Detection. En Proceedings of the Twelfth European Conference on Com-puter Systems, EuroSys ’17, paginas 405–419, New York, NY, USA, 2017. ACM,ISBN 978-1-4503-4938-3. http://doi.acm.org/10.1145/3064176.3064211.
[29] Lee, Byoungyoung, Chengyu Song, Yeongjin Jang, Tielei Wang, Taesoo Kim, LongLu y Wenke Lee: Preventing Use-after-free with Dangling Pointers Nullification.En NDSS, 2015.
[30] Liu, T., C. Curtsinger y E. D. Berger: DoubleTake: Fast and Precise Error Detec-tion via Evidence-Based Dynamic Analysis. En 2016 IEEE/ACM 38th Internatio-nal Conference on Software Engineering (ICSE), paginas 911–922, May 2016.
[31] Ma, R., L. Chen, C. Hu, J. Xue y X. Zhao: A Dynamic Detection Method to C/C++Programs Memory Vulnerabilities Based on Pointer Analysis. En 2013 IEEE 11thInternational Conference on Dependable, Autonomic and Secure Computing, pagi-nas 52–57, Dec 2013.
[32] Mora Rodrıguez, David y Mario Munoz: Tecnicas de ofensa y defensa a los fallospor corrupcion de memoria. Revista Ingenierıas Universidad de Medellın, 10(19),2011.
[33] Morgan, Steve: Cyber Crime Costs Projected To Reach $2 Trillion by2019, 2016. https : / / www . forbes . com / sites / stevemorgan / 2016 / 01 /
17 / cyber-crime-costs-projected-to-reach-2-trillion-by-2019, visitadoel 2017-08-11.
45
[34] Nagarakatte, S., M. M. K. Martin y S. Zdancewic: Hardware-Enforced Comprehen-sive Memory Safety. IEEE Micro, 33(3):38–47, May 2013, ISSN 0272-1732.
[35] Newsham, Tim: Format string attacks, 2000.
[36] Novark, Gene y Emery D. Berger: DieHarder: Securing the Heap. En Proceedingsof the 17th ACM Conference on Computer and Communications Security, CCS’10, paginas 573–584, New York, NY, USA, 2010. ACM, ISBN 978-1-4503-0245-6.http://doi.acm.org/10.1145/1866307.1866371.
[37] Novark, Gene, Emery D. Berger y Benjamin G. Zorn: Exterminator: Automa-tically Correcting Memory Errors with High Probability. En Proceedings ofthe 28th ACM SIGPLAN Conference on Programming Language Design andImplementation, PLDI ’07, paginas 1–11, New York, NY, USA, 2007. ACM,ISBN 978-1-59593-633-2. http://doi.acm.org/10.1145/1250734.1250736.
[38] Oiwa, Yutaka: Implementation of the Memory-safe Full ANSI-C Compiler. SIG-PLAN Not., 44(6):259–269, Junio 2009, ISSN 0362-1340. http://doi.acm.org/
10.1145/1543135.1542505.
[39] Ouyang, Yongji, Qingxian Wang, Qiang Wei y Jie Liu: UAF bug checking model ba-sed on dataflow analysis. En 2010 IEEE International Conference on InformationTheory and Information Security, paginas 534–538, Dec 2010.
[40] Packard, Hewlett: HP Study Reveals 70 Percent of Internet of Things Devices Vul-nerable to Attack, 2018. http://www8.hp.com/in/en/hp-news/press-release.
html?id=1744676#.W6_-rmj0mUl, visitado el 2018-10-24.
[41] Padala, Pradeep: Playing with ptrace, Part I. Linux Journal, 2002(103):5, 2002.
[42] Philippaerts, Pieter, Yves Younan, Stijn Muylle, Frank Piessens, Sven Lach-mund y Thomas Walter: Code Pointer Masking: Hardening Applications againstCode Injection Attacks, paginas 194–213. Springer Berlin Heidelberg, Berlin,Heidelberg, 2011, ISBN 978-3-642-22424-9. http://dx.doi.org/10.1007/
978-3-642-22424-9_12.
[43] Ratanaworabhan, Paruj, V Benjamin Livshits y Benjamin G Zorn: NOZZLE: ADefense Against Heap-spraying Code Injection Attacks. En USENIX Security Sym-posium, paginas 169–186, 2009.
[44] Rouse, Margaret: Embedded system, 2015. http://internetofthingsagenda.
techtarget.com/definition/embedded-system, visitado el 2017-08-11.
46
[45] Russo, A. y A. Sabelfeld: Dynamic vs. Static Flow-Sensitive Security Analysis.En 2010 23rd IEEE Computer Security Foundations Symposium, paginas 186–199,July 2010.
[46] Saito, T., S. Kondo, H. Miyazaki, W. Bing, R. Watanabe, R. Sugawara y M.Yokoyama: Mitigating Use-After-Free Attack with Application Program Loader. En2017 IEEE 31st International Conference on Advanced Information Networkingand Applications (AINA), paginas 919–924, March 2017.
[47] Sarbinowski, Pawel, Vasileios P. Kemerlis, Cristiano Giuffrida y Athanasopoulos:VTPin: Practical VTable Hijacking Protection for Binaries. paginas 448–459, 2016.http://doi.acm.org/10.1145/2991079.2991121.
[48] Shen, Kai: Static Linking. Computer, 3:1, 2012.
[49] Spectrum, IEEE: The 2018 Top Programming Languages,2018. https : / / spectrum . ieee . org / at-work / innovation /
the-2018-top-programming-languages, visitado el 2018-10-24.
[50] Standard, National Institute of y Technology: National Vulnerability Database,2017. https://nvd.nist.gov/, visitado el 2017-08-11.
[51] Stevens, W Richard, Bill Fenner y Andrew M Rudoff: UNIX Network Programming:The Sockets Networking API, volumen 1. Addison-Wesley Professional, 2004.
[52] Systems, Zator: Curso C++: Enlazado, 2016. http://www.zator.com/Cpp/E1_
4_4.htm, visitado el 2017-08-11.
[53] Teixeira, Jose y Tingting Lin: Collaboration in the open-source arena: the web-kit case. En Proceedings of the 52nd ACM conference on Computers and peopleresearch, paginas 121–129. ACM, 2014.
[54] Tlili, Syrine, Zhenrong Yang, Hai Zhou Ling y Mourad Debbabi: A Hybrid Ap-proach for Safe Memory Management in C, paginas 377–391. Springer BerlinHeidelberg, Berlin, Heidelberg, 2008, ISBN 978-3-540-79980-1. http://dx.doi.
org/10.1007/978-3-540-79980-1_28.
[55] Vandewoude, Yves y Yolande Berbers: An overview and assessment of dynamicupdate methods for component-oriented embedded systems. En Proceedings of TheInternational Conference on Software Engineering Research and Practice, paginas521–527, 2002.
[56] Wang, Y., M. Li, H. Yan, Z. Liu, J. Xue y C. Hu: Dynamic Binary InstrumentationBased Defense Solution against Virtual Function Table Hijacking Attacks at C++Binary Programs. paginas 430–434, 2015.
47
[57] Wikipedia: List of web browsers, 2017. https://en.wikipedia.org/wiki/List_
of_web_browsers#WebKit-based, visitado el 2017-08-11.
[58] Yamauchi, Toshihiro y Yuta Ikegami: HeapRevolver: Delaying and Rando-mizing Timing of Release of Freed Memory Area to Prevent Use-After-FreeAttacks, paginas 219–234. Springer International Publishing, Cham, 2016,ISBN 978-3-319-46298-1. http://dx.doi.org/10.1007/978-3-319-46298-1_
15.
[59] Yamauchi, Toshihiro, Yuta Ikegami y Yuya Ban: Mitigating Use-After-Free AttacksUsing Memory-Reuse-Prohibited Library. IEICE Transactions on Information andSystems, 100(10):2295–2306, 2017.
[60] Ye, Jiayi, Chao Zhang y Xinhui Han: POSTER: UAFChecker: Scalable Static De-tection of Use-After-Free Vulnerabilities. En Proceedings of the 2014 ACM SIG-SAC Conference on Computer and Communications Security, CCS ’14, paginas1529–1531, New York, NY, USA, 2014. ACM, ISBN 978-1-4503-2957-6. http:
//doi.acm.org/10.1145/2660267.2662394.
[61] Younan, Yves: FreeSentry: protecting against use-after-free vulnerabilities due todangling pointers. En NDSS, 2015.
[62] Younan, Yves, Wouter Joosen y Frank Piessens: Efficient Protection Against Heap-Based Buffer Overflows Without Resorting to Magic, paginas 379–398. SpringerBerlin Heidelberg, Berlin, Heidelberg, 2006, ISBN 978-3-540-49497-3. http://dx.doi.org/10.1007/11935308_27.
[63] Zhang, Wenzhe: Efficient detection of dangling pointer error for C/C++ programs.En Journal of Physics: Conference Series, volumen 887, pagina 012053. IOP Pu-blishing, 2017.