05 abril 2012

Mitigaciones de seguridad en EMETv2.1 (II de III)

SEHOP

Excepciones en Windows

Primero de todo aclarar que una excepción es un evento que ocurre durante la ejecución de un programa. Para gestionar este evento es preciso hacer uso de código externo al flujo del programa que se estaba ejecutando. Existen dos tipos de excepciones: hardware y software. Las primeras son inciadas por la CPU, como una división por cero o acceso a una posición de memoria inválida; y las software son provocadas por aplicaciones o el operativo. Mediante el manejo de excepciones (SEH en Windows) es posible trabajar tanto con las de tipo hardware como software.

Un registro de excepción es una estructura que se compone de dos campos: un puntero al siguiente registro y un puntero al manejador de la excepción. Mediante el primer registro se consigue una lista enlazada de los registros de excepción, por lo tanto next SEH apunta al siguiente campo next SEH. El segundo campo es una dirección que apunta a la posición de memoria que contiene el código a ejecutar cuando se produce una cierta excepción.


Los registros de excepción se almacenan en la pila del hilo. Por lo tanto mediante un desbordamiento de pila el atacante puede sobreescribirla para modificar el puntero al manejador de excepción y next SEH.

Es importante tener en cuenta que cuando se salta al código del manejador de excepción se crea un marco de pila propio (Exception Dispatcher Stack). En este marco se almacena una estructura que entre otros datos contiene EstablisherFrame. Éste apunta al registro SE de la pila del programa, concretamente al campo next para poder seguir recorriendo la cadena.

En cada marco de pila correspondiente a una función sólo constan los punteros a manejadores de las excepciones de esa función. Por lo tanto los punteros al código de los manejadores de excepción están enlazados, pero siempre que sean los de la misma función.

Posición dentro del marco de pila de una función:


FS:[0], presente en Thread Information Block (TIB), apunta al principio de la cadena SEH, posición en la cual hay un registro SEH con sus dos punteros. El último registro de la cadena apunta a FFFFFFFF. Por lo tanto cuando una excepción ocurre, Windows mira en el Thread Environment Block (TEB) el comienzo de la cadena y la recorre hasta encontrar el manejador correspondiente. Si no existe se ejecuta el por defecto propio de Windows (UnhandledExceptionFilter). Éste pregunta al usuario si desea enviar un informe de error a Microsoft.

Cuando se produce una excepción el operativo recorre la cadena SEH. Dentro del código de excepción, filter_expression indica si se puede encargar de esa excepción o no. En el primer caso se ejecuta el código correspondiente, y si no se pasa al siguiente registro SE. En resumen, es dentro del código del manejador donde se decide si se puede manejar la excepción gracias a filter_expression.

El registro y eliminación de manejadores de excepción ocurre en tiempo de ejecución. Si en una función se declara un manejador, éste se añade al principio de la lista (LIFO) cuando se llame a la función; no antes. Previo a la invocación de la función, en la cadena sólo constará el manejador por defecto de Windows. De la misma manera, cuando se sale de una función se elimina el registro SEH correspondiente a la excepción o excepciones declaradas dentro de ella. Es decir, dependiendo de donde estemos en el código varían los registros SEH presentes en la lista.


Exploiting

Hay que sobreescribir el puntero al manejador que se va a utilizar para tratar una excepción. Esto hará que podamos saltar a nuestra shellcode en vez de al manejador de excepción correspondiente. Para esto vamos a utilizar la serie de instrucciones pop/pop/ret. El payload debe hacer lo siguiente:

  • lanzar una excepción.

  • sobreescribir next SEH con un jumpcode para saltar a la shellcode.

  • sobreescribir SE Handler con la dirección de una instrucción que haga que lleguemos a next SEH (pop/pop/ret en un módulo sin SAFESEH).

  • la shellcode tiene que estar situado después de SE Handler.


Mitigaciones

Para explotar una desbordamiento de pila mediante SEH, no podemos llegar a la shellcode simplemente saltando a lo que apunta un registro. Como medida de protección desde Windows XP SP1 se hace XOR de los mismos antes de que el manejador de excepción tome control, por lo tanto su contenido es 0. Es necesario llamar a un serie de instrucciones en una DLL (pop/pop/ret).

Existen dos formas de mitigar la sobreescritura de SEH:

  • recompilar el código de forma que los ejecutables compilados contengan metadatos útiles para la mitigación (flag /SAFESEH). A esta mitigación Microsoft le da el nombre de software DEP, ya que previene la ejecución de código. En este caso la CPU puede no implementar DEP, y por lo tanto no se hace uso del bit NX. No tiene nada que ver con la prevención de código en páginas de memoria; se basa en una técnica totalmente diferente.

  • SEHOP: trabaja de forma dinámica y no utiliza metadatos. Revisa que la lista de manejadores de excepción de un hilo sigue intacta hasta invocar al manejador. Cuando un atacante sobreescribe el puntero del manejador en la pila, suele sobreescribir previamente el campo next del registro SEH. Por lo tanto la lista enlazada se rompe y con ella la integridad de la cadena.

La mitigación SEHOP tiene lugar mediante dos pasos:

  • inserta un registro SEH simbólico al final de la lista de manejadores cuando el hilo se empieza a ejecutar. Debido a que los registros SEH se introducen siempre al comienzo de la cadena garantiza que el simbólico siempre estará al final.

  • cuando un manejador se va a ejecutar, se comprueba que se puede alcanzar el registro simbólico introducido. Si es así, se salta a la rutina de excepción. Si no se puede, se asume que la lista ha sido corrompida debido a una sobreescritura SEH y por lo tanto se finaliza la ejecución del proceso sin llamar al manejador.
Artículo cortesía de David Montero 

2 comments :

Ezequiel dijo...

Felicitaciones por la entradas es un poco complicado encontrar esta informacion bien explicada y en castellano.Gracias!

damontero dijo...

Si, sí que lo es. ¡Que me lo digan a mí! :)
Gracias por las felicitaciones.

Saludos