viernes, 17 de mayo de 2013

Vulnerabilidad en el kernel Linux permite elevación de privilegios.


Vulnerabilidad en el kernel Linux permite elevación de privilegios.



Casualidad que acabo de comentar como la falsa creencia de muchos que piensan que su marca de equipo o su sistema operativo son muy seguros y los hace invulnerables a ataques informáticos es un error que aprovechan los ciberdelincuentes para vulnerar los sistemas. Pues bien, como les comentaba hace poco, ningún sistema es 100% seguro y siempre existirán fallos o vulnerabilidades que se puedan explotar.
 
El pasado mes de abril, un mensaje en la lista del kernel Linux alertaba de un fallo de seguridad en la función 'sw_perf_event_destroy' de kernel/events/core.c. Su autor, Tommi Rantala, comentaba que lo había encontrado ejecutando una versión de Trinity modificada por él mismo. Se trata de una herramienta para emplear técnicas de fuzzing en las llamadas al sistema que proporciona el kernel Linux.

El fallo se encuentra en el subsistema 'perf' que permite obtener métricas de rendimiento del hardware. Al ejecutar un conjunto de llamadas con parámetros aleatorios, Rantala consiguió provocar un "kernel Oops" (una especie de excepción en el kernel). En la salida de registro de Trinity podían observarse las líneas que contenían la sospecha de un problema de seguridad:

[114607.069257] BUG: unable to handle kernel paging request at 0000000383c35328
[114607.070003] IP: [<ffffffff811a7200>] sw_perf_event_destroy+0x30/0x90

Básicamente, antes de la llamada a 'sw_perf_event_destroy' existe una llamada a 'perf_swevent_init', donde se inicializa un entero con signo al valor de event->attr.config, procedente del puntero a la estructura *event:

static int perf_swevent_init(struct perf_event *event)
{
int event_id = event->attr.config;

if (event->attr.type != PERF_TYPE_SOFTWARE)
return -ENOENT;

Posteriormente, se hace una llamada a 'sw_perf_event_destroy' y aquí ese valor entero con signo es tratado como un entero sin signo de 64 bits:

static void sw_perf_event_destroy(struct perf_event *event)
{
u64 event_id = event->attr.config;

WARN_ON(event->parent);

static_key_slow_dec(&perf_swevent_enabled[event_id]);
swevent_hlist_put(event);
}

Como en 'perf_swevent_init' el entero es tratado con signo, solo es comprobado en su límite superior, dejando abierta la posibilidad de que se introduzca un entero negativo que posteriormente en 'sw_perf_event_destroy', al ser "convertido" en u64, nos dará un entero positivo.

Debido a que el valor de event->attr.config es controlable por el usuario, cuando se efectua la llamada al sistema correspondiente mediante la estructura 'perf_event_attr', es posible mapear una zona de memoria y obtener el control de la misma haciendo que se apunte a esa dirección. Si se llega a ejecutar nuestra zona de memoria con un shellcode instalado allí, este se ejecutaría con permisos de root.

Petr Matousek da una explicación completa y de recomendable estudio en la lista de bugzilla de Red Hat.

El parche fue añadido al repositorio del kernel el mismo mes. Básicamente consiste en promover la variable 'event_id' al tipo 'u64', evitando así la falta de una comprobación apropiada:

static int perf_swevent_init(struct perf_event *event)
{
- - int event_id = event->attr.config;
+ u64 event_id = event->attr.config;

if (event->attr.type != PERF_TYPE_SOFTWARE)
return -ENOENT;

El fallo fue reportado en abril, y pasó un poco de puntillas por la lista de desarrolladores, sin levantar demasiado revuelo. Pero parece que no pasó tan desapercibido para todo el mundo. Un poco más tarde, en mayo, un tercero hizo público un exploit para aprovechar la vulnerabilidad. Este hecho es el que realmente ha sacado a la luz que el fallo, es en realidad un grave problema de seguridad.

El CVE asignado es el CVE-2013-2094. Afectaría a todos los kernels (de 64 bits) desde la versión 2.6.37 a la 3.8.8 que hayan sido compilados con la opción CONFIG_PERF_EVENTS.

Más información:

Trinity
http://codemonkey.org.uk/projects/trinity/

Linux kernel oopshttp://en.wikipedia.org/wiki/Linux_kernel_oops

Performance counter subsystemhttps://perf.wiki.kernel.org/index.php/Main_Page

CVE-2013-2094 kernel: perf_swevent_enabled array out-of-bound accesshttps://bugzilla.redhat.com/show_bug.cgi?id=962792#c16

Commit del parche en el repositorio del kernel Linuxhttp://bit.ly/1833rsM

Exploithttp://fucksheep.org/~sd/warez/semtex.c

No hay comentarios:

Publicar un comentario