21 noviembre 2014

Probando aplicaciones de auditoría web con Google Web "Firing Range"

Google anunció el pasado martes en su blog Google Online Security la publicación de una aplicación online (con su código fuente correspondiente) en la que se recopilaban diferentes pruebas de concepto relacionadas con vulnerabilidades típicas web, con especial hincapié en todas las variantes posibles para la ejecución de Cross-Site Scriptings. Actualmente Google se encuentra desarrollando una herramienta de auditoría de vulnerabilidades para uso interno (a la que llaman Inquisition) para la cual necesitaban casos reales de vulnerabilidades para probar su eficacia.




Disponemos de páginas preparadas para probar vulnerabilidades de los siguientes tipos hasta el momento (y dentro de cada tipología con multitud de pruebas posibles a realizar):
  • Cross-Site Scripting Address DOM
  • XSS de redirección
  • XSS reflejados
  • XSS basados en Tag
  • Cross-Site Scripting escapados por el servidor
  • XSS de inclusión remota
  • Cross-Site Scripting de DOM
  • Vulnerabilidades relacionadas con CORS (Cross Origin Resource Sharing)
  • Inyección Flash
  • Contenido mixto
  • ClickJacking inverso
Casos de pruebas dentro de la sección "Escape XSS"

Como podréis observar, el diseño no es lo más relevante, ya que lo que prima en este caso es tener un banco de pruebas sobre el que lanzar herramientas de detección de este tipo de vulnerabilidades y probar su eficacia, además de obviamente poder realizar pruebas de manera manual para conseguir el objetivo de un famoso alert() u otros tipos de acciones más interesantes.

Tenéis más información en el post de Google Online Security escrito por Claudio Criscione (Security Engineer en Google), así como en el repositorio de código del proyecto.

[+] Firing Range (Google) https://public-firing-range.appspot.com
Leer más...

20 noviembre 2014

x87 FPU, MMX, SSEs & AVX: primera parte

Tengo la impresión de que algunas personas que hacen ingeniería inversa habitualmente conocen bien la CPU pero no tanto la x87 FPU, MMX, SSEs, AVX y sus posibles aplicaciones. Por eso en esta serie de artículos vamos a explicar como funciona todo esto en x86 y x86_64.

Además se explicará como jugar con todo esto desde el sistema operativo Windows y desde la perspectiva de un depurador.

Introducción:

Ojeando un poco de la wikipedia sobre las extensiones multimedia:

x86 (current):
  • MMX (1996)
  • 3DNow! (1998)
  • Streaming SIMD Extensions (SSE) (1999)
  • SSE2 (2001)
  • SSE3 (2004)
  • Supplemental SSE3 (SSSE3) (2006)
  • SSE4 (2006)
  • SSE5 (2007)
  • Advanced Encryption Standard (AES) (2008)
  • Advanced Vector Extensions (AVX) (2008)
  • F16C (2009 (AMD), 2011 (Intel))
  • XOP (2009)
  • FMA instructions (FMA4: 2011, FMA3: 2012 (AMD), 2013 (Intel))
  • Bit manipulation instructions (ABM: 2007, BMI1: 2012, BMI2: 2013, TBM: 2012)
x86 (planned)  
  • AVX-512 (2015)
Para esta serie de artículos nos vamos a centrar de momento solo en:

x87: es un subconjunto de coma flotante del conjunto de instrucciones de la arquitectura x86. Se originó como una extensión del conjunto de instrucciones del 8086 en la forma de un coprocesador opcional de coma flotante que trabajó en paralelo con el correspondiente CPU x86. Las instrucciones x87 no son estrictamente necesarias para construir programas funcionales, pero proporcionan implementaciones de hardware y microcódigo de tareas numéricas comunes, permitiendo a estas tareas desempeñarse mucho más rápido que las rutinas correspondientes en código máquina. El conjunto de instrucciones x87 incluye instrucciones para operaciones de coma flotante básicas tales como: adición, sustracción y comparación. Así como también para operaciones numéricas más complejas como por ejemplo el cálculo de la función tangente y su inversa. Desde el Intel 80486, la mayoría de los procesadores x86 han tenido estas instrucciones x87 implementadas en el propio CPU. Los registros principales de x87 son un total de 8 registros desde el ST(0) hasta el ST(7). Se puede acceder directamente a estos registros usando un desplazamiento relativo al tope de la pila, así como también se permiten apilados y desapilados en la pila. x87 proporciona aritmética de coma flotante binaria de simple precisión, doble precisión y precisión extendida de 80 bits según el estándar IEEE 754-1985. Por defecto, todos los procesadores x87 usan internamente la precisión extendida de 80 bits.

MMX: es un Conjunto de instrucciones SIMD (Single Instruction, Multiple Data) diseñado por Intel e introducido en 1997 en sus microprocesadores Pentium con tecnología MMX. Fue desarrollado a partir de un set introducido en el Intel i860. Ha sido soportado por la mayoría de fabricantes de microprocesadores x86 desde entonces. MMX define 8 registros desde el MM0 hasta el MM7. Para evitar problemas de compatibilidad con los dispositivos de conmutación contexto en los sistemas operativos existentes, estos registros eran los alias de los registros de pila FPU x87 existentes. Por lo tanto, cualquier operación con los registros que se haga en la FPU x87 también podrá afectar a los registros MMX y viceversa. Sin embargo, a diferencia de los registros internos x87, los registros MMX son directamente accesibles. Cada registro MMX es de 64 bits.

SSE (Streaming SIMD Extensions): es una extensión al grupo de instrucciones MMX para procesadores Pentium III, introducida por Intel en febrero de 1999. Las instrucciones SSE son especialmente adecuadas para decodificación de MPEG2, que es el códec utilizado normalmente en los DVD, procesamiento de gráficos tridimensionales y software de reconocimiento de voz. Con la tecnología SSE, los microprocesadores x86 fueron dotados de setenta nuevas instrucciones y de ocho registros nuevos: del XMM0 al XMM7. Estos registros tienen una extensión de 128 bits. Las extensiones AMD64 de AMD (llamado originalmente x86-64) añaden otros ocho registros desde el XMM8 al XMM15. También hay un nuevo registro de control y estado de 32 bits llamado MXCSR. Los registros del XMM8 al XMM15 son accesibles sólo en modo de 64 bits.

AVX: (extensiones vectoriales avanzadas) es un juego de instrucciones de 256 bits desarrollado por Intel Corporation como una extensión al conjunto de instrucciones x86 utilizado en procesadores de Intel y AMD . Provee nuevas características, instrucciones y un nuevo esquema de codificación. El ancho del registro SIMD es incrementado de 128-bits a 256-bits, y renombrado de XMM0-XMM15 a YMM0-YMM15. En los procesadores que soportan AVX, el juego de instrucciones SSE (que anteriormente operaba en los registros XMM) pasa a operar en los primeros 128-bits de los registros YMM. Los registros del YMM8 al YMM15 son accesibles solo en modo de 64 bits. Además, se espera la inclusión de vectores de 512 (AVX-512) e incluso 1024 bits.

x87 FPU conceptos básicos:

En mi opinión la forma más sencilla de entender la pila de la x87 FPU es pensar en el cañón del revólver. Los registros ST0-ST7 serían los huecos donde se alojan las balas y las balas serían el contenido de los registros.

El registro interno de la FPU que se encuentre ese momento listo para ser disparado sería el registro ST0 y los demás serían relativos a ésta posición (el TOP de la pila). Hemos hecho una imagen que muestra esta idea y con un incremento y un decremento de la pila x87:



A la hora de programar el soporte básico x87 FPU para el x64dbg se me ocurrio que mostrar la representación interna de los registros de la FPU era buena idea para saber en todo momento a qué registro interno corresponde cada ST, el Ollydbg muestra los registros en referencia a su ST, vamos con un par de imágenes de lo que quiero decir:



Como se puede apreciar en el x64dbg se puede ver la relación directa entre los registros internos de la FPU x87r* y que ST tiene asignado en ese momento y se puede ver de una manera más clara (en mi opinión) cosas como que la pila se ha movido de un primer vistazo. Además tiene la ventaja que un registro MMX pertenece siempre a un x87r* correspondiente, por ejemplo la parte baja del registro interno de la FPU x87r0 siempre será MM0, x87r1 siempre será MM1, etc.

Además de los 8 registros de 80 bits en la x87 FPU también se encuentran tres registros de 16 bits: Control Word, Status Word y Tag Word. En este apartado de conceptos básicos vamos a explicar que es cada uno de estos registros y sus bits correspondientes.


Control Word: se utiliza para seleccionar entre los distintos modos de cálculo disponible en la FPU y para definir qué excepciones deben ser manejadas por la FPU o por un manejador propio de excepciones.

A continuación vamos a explicar todos los campos:

El campo X (tambien se puede encontrar como IC) corresponde al bit 12, se le denomina Infinity Control y permite dos tipos de aritmética infinita los valores que puede tener son:
  • 0: -infinity y +infinity son tratados como "unsigned infinity" (estado inicializado).
  • 1: -infinity y +infinity
Nota: este campo se mantiene para guardar la compatibilidad con 287 y las FPU anteriores. En las FPU "modernas" este bit se ignora.

El campo RC corresponde a los bits 10 y 11, se le denomina Round Control y sirve para indicar como debe la FPU redondear los resultados. Los valores que puede tener son:
  • 00: Redondeo al más cercano (or to even if equidistant). Este es el estado inicializado.
  • 01: Redondeo al infinito negativo (toward -infinity)
  • 10: Redondeo al infinito positivo (toward +infinity)
  • 11: Truncar (toward 0)
El campo PC corresponde a los bits 8 y 9, se le denomina Precision Control y sirve para determinar a qué precision se deben redondear los resultados después de cada instrucción aritmética. Los valores que puede tener son:
  • 00: 24 bits (REAL4)
  • 01: Not used
  • 10: 53 bits (REAL8)
  • 11: 64 bits (REAL10). Este es el estado inicializado.
El campo IEM corresponde al bit 7, se le denomina Interrupt Enable Mask y sirve para determinar si alguna de las "interrupt masks" se activarán o no. Este es otro de los bits que se guardan por compatibilidad con las FPUs antiguas y no se usa. Los valores que puede tener son:
  • 1: Las "interrupt masks" están activadas. Este también es el estado inicializado.
  • 0: Todas las "interrupt masks" están desactivadas.
Los bits que van del 0 al 5 son las llamadas "interrupt masks". En el estado inicializado todas valen 1, esto quiere decir que la FPU manejará todas las excepciones. Cuando alguno de estos bits tiene el valor 0 la FPU generará una interrupción cuando la excepción se detecta y el programa podrá ejecutar el código deseado antes de devolver el control a la FPU. De momento no vamos a entrar en más detalles sobre este tema. Las "interrupt masks" que hay son:
  • IM (bit 0) también llamado Invalid operation Mask.
  • DM (bit 1) también llamado Denormalized operand Mask.
  • ZM (bit 2) también llamado Zero divide Mask.
  • OM (bit 3) también llamado Overflow Mask.
  • UM (bit 4) también llamado Underflow Mask.
  • PM (bit 5) también llamado Precision Mask.
Status Word: almacena el estado actual de la FPU. Así que muchas de de las instrucciones van modificando los bits de éste registro al igual que ocurre con los FLAGS de la CPU.

A continuación vamos a explicar los campos de este registro:

El campo B corresponde al bit 15 y se pone a 1 cuando la FPU está ocupada o a 0 si está en espera (idle).

Los campos C3 (bit 14), C2 (bit 10), C1 (bit 9), C0 (bit 8) son flags condicionales que se usan por ejemplo para comprobar el resultado de una comparación. De momento no se explicará más sobre esto.

El campo TOP corresponde a los bits 11, 12 y 13 y almacena que registro interno de la FPU es el ST0 actual, es decir qué registro interno está en el TOP de la pila.

Nota: un ejemplo del uso y explicación de este campo se puede encontrar en el apartado "Obteniendo y entendiendo el CONTEXT en Windows: I".

El campo ES también llamado IR o Interrupt Request corresponde al bit 7 y tiene el valor 1 si una excepción está siendo manejada y tiene el valor 0 cuando se ha acabado de manejar.

Los bits del 0 al 6 son flags que son manejados por la FPU cuando detecta una excepción.

El campo SF corresponde al bit 6, tambien es llamado Stack Fault Flag y se pone a 1 cuando se intenta cargar un valor en un registro que no está libre.

El campo PE corresponde al bit 5, también es llamado Precision Exception Flag y se pone a 1 cuando la precisión se ha perdido en alguna instrucción aritmética.

El campo UE corresponde al bit 4, también es llamado Underflow Exception Flag y se pone a 1 cuando un valor es demasiado pequeño para poder ser representado.

El campo OE corresponde al bit 3, también es llamado Overflow Exception Flag y se pone a 1 cuando un valor es demasiado grande para poder se representado.

El campo ZE corresponde al bit 2, también es llamado Zero Divide Exception Flag y se pone a 1 cuando se intenta dividir por 0.

El campo DE corresponde al bit 1, también es llamado Denormalized Exception Flag  y se pone a 1 cuando se intenta operar en un "denormalized number" o el resultado de una operación es un "denormalized number".

El campo IE corresponde al bit 0, también es llamado Invalid Operation Exception Flag se pone a 1 cuando se realiza una operación inválida para FPU.

Tag Word: contiene información sobre cada registro de 80 bits de la FPU. Hay 3 bits para indicar el estado de cada registro de 80 bits de la FPU. Y estos corresponden a la posición fija del registro NO al ST(n) actual. Es decir TAG(0) siempre se referirá al registro interno 0 de la FPU independientemente de que ese registro sea actualmente ST0 o ST5.
Cada TAG puede tener los siguientes valores:
  • 00: También llamado valid: el registro contiene un valor que no es 0.
  • 01: También llamado zero: el registro contiene un valor 0.
  • 10: También llamado special: el registro contiene un valor especial (NAN, infinity...).
  • 11: Tambien llamado empty: el registro está vacío.

MxCsr

Este registro de 32 bits tiene una función parecida al registro Control Word y al Status Word de la x87 FPU: mantiene toda la información de enmascaramiento y flags para su uso con operaciones de coma flotante SSE. Los bits del 16 al 31 están reservados y causarán una excepción #GP si se intentan activar.


A continuación vamos a explicar los campos del MxCsr:

El campo FZ también llamado Flush to Zero corresponde al bit 15 activa el modo en el que todas las operaciones donde ocurra un underflow valdrán 0. Esto hace que el tiempo de procesado sea más rápido pero se pierde precisión.

El campo RC corresponde a los bits 13 y 14, se le denomina Round Control y sirve para indicar como deben redondear los resultados. Los valores que puede tener son:
  • 00: Redondeo al más cercano
  • 01: Redondeo al infinito negativo (toward -infinity)
  • 10: Redondeo al infinito positivo (toward +infinity)
  • 11: Redondea a 0 (toward 0)
Los bits que van del 7 al 12 son las llamadas "interrupt masks". En el estado inicializado todas valen 1, esto quiere decir que el programa no manejará las excepciones. Cuando alguno de estos bits tiene el valor 0 se generará una interrupción cuando la excepción se detecta y el programa podrá hacer lo necesario antes de devolver el control. En esta parte del post no vamos a entrar en más detalles sobre este tema. Las "interrupt masks" son:
  • IM (bit 7) también llamado Invalid Operation Mask.
  • DM (bit 8) también llamado Denormalized Operand Mask.
  • ZM (bit 9) también llamado Zero Divide Mask.
  • OM (bit 10) también llamado Overflow Mask.
  • UM (bit 11) también llamado Underflow Mask.
  • PM (bit 12) también llamado Precision Mask.
El campo DAZ corresponde al bit 6, también es llamado Denormals Are Zeros, este campo no estaba disponible en la primera versión de SSE. Al igual que el modo Flush To Zero (FZ) el modo DAZ es más rápido pero también pierde precisión. Si el bit 6 está activado el modo DAZ es soportado.

El campo PE corresponde al bit 5, también es llamado Precision Exception Flag y se pone a 1 cuando la precisión se ha perdido en alguna instrucción aritmética.

El campo UE corresponde al bit 4, también es llamado Underflow Exception Flag y se pone a 1 cuando un valor es demasiado pequeño para poder ser representado.

El campo OE corresponde al bit 3, también es llamado Overflow Exception Flag y se pone a 1 cuando un valor es demasiado grande para poder ser representado.

El campo ZE corresponde al bit 2, también es llamado Zero Divide Exception Flag y se pone a 1 cuando se intenta dividir por 0.

El campo DE corresponde al bit 1, también es llamado Denormalized Exception Flag y se pone a 1 cuando se intenta operar en un "denormalized number" o el resultado de una operación es un "denormalized number".

El campo IE corresponde al bit 0, también es llamado Invalid Operation Exception Flag se pone a 1 cuando se realiza una operación inválida para FPU.

Obteniendo y entendiendo el CONTEXT en Windows: I

Para el código de esta parte del artículo voy a basarme en el soporte FPU XMM, MMX, x87 & AVX programado para el x64dbg (An open-source x64/x32 debugger for windows). Actualmente x64dbg usa por debajo como debugger el proyecto Open Source Titanengine Community Edition y es en este donde realmente se encuentra la parte de código que nos interesa.

Para obtener el contexto de un hilo en Windows se usa la API GetThreadContext:
    BOOL WINAPI GetThreadContext(
    _In_     HANDLE hThread,
    _Inout_  LPCONTEXT lpContext
    );
Para simplificar usaremos un CONTEXT_ALL para obtener toda la información del hilo. Hay que suspender el hilo antes de obtener el contexto con la API SuspendThread, un ejemplo de código sin comprobar errores de las llamadas a las APIs podría ser:
    SuspendThread(hThread);
    CONTEXT Context;
    memset(&Context, 0, sizeof(Context));
    DBGContext.ContextFlags = CONTEXT_ALL;
    GetThreadContext(hThread, &Context);
    ResumeThread(hThread);

Nota: Para acceder a Intel AVX hay otras APIs.

CONTEXT_ALL tiene la siguiente pinta (recomiendo leer en la msdn más sobre el tema si se tienen dudas):
    
    #define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | 
            CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) 
 
Para saber si una característica está disponible se puede usar la API IsProcessorFeaturePresent con la característica a comprobar. Si retorna 0 la característica no está disponible:
  • PF_MMX_INSTRUCTIONS_AVAILABLE: disponible MMX.
  • PF_XMMI_INSTRUCTIONS_AVAILABLE: disponible XMM.
  • PF_XMMI64_INSTRUCTIONS_AVAILABLE: set de instrucciones SSE2 disponible.
  • PF_SSE3_INSTRUCTIONS_AVAILABLE: set de instrucciones SSE3 disponible (Característica no disponible en Windows Server 2003 and Windows XP/2000).
  • PF_3DNOW_INSTRUCTIONS_AVAILABLE está disponible 3DNOW.
  • PF_XSAVE_ENABLED el procesador implementa las instrucciones XSAVE y XRSTOR.
Para obtener los registros MMX de la estructura CONTEXT de Windows hay que tener en cuenta que vienen desordenados y además vienen dentro de los registros x87 (80 bits). Así que hay acceder a la parte baja del registro x87 para obtener los 64 bits de cada registro MMX.

El orden en el que vienen los registros MMX es el que hay en la pila FPU x87 en el momento de obtener el CONTEXT. Para calcular a qué MMX se está accediendo es necesario obtener el campo TOP del registro StatusWord de x87.

El campo TOP ocupa 3 bits y corresponde a las posiciones 11, 12 y 13 y almacena qué registro x87 se encuentra primero en la pila, por ejemplo si el TOP es 3, quiere decir que en el TOP de la pila está el registro 3 de x87, así que el registro MMX que obtendremos en la parte baja del primer registro x87 del stack será MM3.

De tal forma que los registros MMX vendrían en la estructura CONTEXT en el siguiente orden: MM3, MM4, MM5, MM6, MM7, MM0, MM1 & MM2. Como los registros ST vienen siempre en orden de ST0 a ST7, en este caso, la correspondencia de los registros ST con los MMX sería: ST0: MM3, ST1: MM4, ST2: MM5, ST3: MM6, ST4: MM7, ST5: MM0, ST6: MM1 & ST7: MM2.

El principal problema es que en las versiones de 32 bits de Windows se accede a través del campo FloatSave y ExtendedRegisters de la estructura CONTEXT y en 64 bits se debe usar el campo
FltSave.

Además Microsoft a partir de Windows 7 SP1 ha añadido una nueva forma de acceder al contexto para obtener los registros AVX: XState functions.

A continuación vamos a explicar como acceder a los diferentes CONTEXT:

Para obtener los registros AVX YMM de 256 bits será neceserario obtener las funciones en tiempo de ejecución con GetModuleHandle y GetProcAddress ya que no existe SDK para Windows 7 con SP1. Para ello lo primero será crear los punteros a funciones e inicializarlos al valor correspondiente. Hay que tener en cuenta que esto solo funcionará desde Windows 7 SP1:
    typedef DWORD64 (WINAPI *PGETENABLEDXSTATEFEATURES)();
    typedef BOOL (WINAPI *PINITIALIZECONTEXT)(PVOID Buffer, DWORD ContextFlags, 
        PCONTEXT* Context, PDWORD ContextLength);
    typedef BOOL (WINAPI *PGETXSTATEFEATURESMASK)(PCONTEXT Context, PDWORD64 FeatureMask);
    typedef PVOID (WINAPI *LOCATEXSTATEFEATURE)(PCONTEXT Context, DWORD FeatureId, 
        PDWORD Length);
    typedef BOOL (WINAPI *SETXSTATEFEATURESMASK)(PCONTEXT Context, DWORD64 FeatureMask);

    PGETENABLEDXSTATEFEATURES pGetEnabledXStateFeatures;
    PINITIALIZECONTEXT pInitializeContext;
    PGETXSTATEFEATURESMASK pGetXStateFeaturesMask;
    LOCATEXSTATEFEATURE pLocateXStateFeature;
    SETXSTATEFEATURESMASK pSetXStateFeaturesMask;

    kernel32h = GetModuleHandleA("kernel32.dll");

    pGetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(kernel32h, 
        "GetEnabledXStateFeatures");
    pInitializeContext = (PINITIALIZECONTEXT)GetProcAddress(kernel32h, 
        "InitializeContext");
    pGetXStateFeaturesMask = (PGETXSTATEFEATURESMASK)GetProcAddress(kernel32h, 
        "GetXStateFeaturesMask");
    pLocateXStateFeature = (LOCATEXSTATEFEATURE)GetProcAddress(kernel32h,         
        "LocateXStateFeature");
    pSetXStateFeaturesMask = (SETXSTATEFEATURESMASK)GetProcAddress(kernel32h, 
        "SetXStateFeaturesMask");
Otro de los problemas que se nos presentan es que el valor para CONTEXT_XSTATE cambió de Windows 7 a Windows 7 SP1. Así que para evitar problemas si usamos un SDK u otro añadimos el código directamente, además también añadiremos otras constantes que pueden no estar presentes en nuestro SDK y necesitaremos XSTATE_AVX y XSTATE_MASK_AVX:
    #undef CONTEXT_XSTATE
    #if defined(_M_X64)
    #define CONTEXT_XSTATE                      (0x00100040)
    #else
    #define CONTEXT_XSTATE                      (0x00010040)
    #endif
    #define XSTATE_AVX                          (XSTATE_GSSE)
    #define XSTATE_MASK_AVX                     (XSTATE_MASK_GSSE)
Una vez obtenidos los punteros a las funciones que usaremos en tiempo de ejecución y hemos comprobado que hemos podido obtener todas, es el momento de obtener el CONTEXT. Para ello primero necesitamos saber el tamaño llamando a la API InitializeContext de la siguiente manera:
    DWORD ContextSize = 0;
    BOOL Success = pInitializeContext(NULL, CONTEXT_ALL | CONTEXT_XSTATE, NULL,
         &ContextSize);
Si ha ocurrido algún error obtendremos en Success un valor TRUE o el Last Error será
ERROR_INSUFFICIENT_BUFFER.

En caso de que todo vaya bien reservaremos la memoria para el CONTEXT y lo inicializaremos:
    PCONTEXT Context;
    void * buffer = malloc(ContextSize);
    if buffer != NULL)
    {
        Success = pInitializeContext(buffer, CONTEXT_ALL | CONTEXT_XSTATE, &Context, 
                &ContextSize);
    }
Si todo ha ido bien Success tendrá el valor TRUE y será necesario llamar a SetXStateFeaturesMask. Antes de obtener el contexto de un hilo con la API GetThreadContext (según Microsoft) debemos usar SetXStateFeaturesMask para verificar que tipo de funcionalidad queremos obtener o cambiar.
    Success = pfnSetXStateFeaturesMask(Context, XSTATE_MASK_AVX);
Si todo ha ido bien Success tendrá el valor TRUE y será necesario suspender el hilo con la API SuspendThread y obtener el contexto con la API GetThreadContext:
    if ( SuspendThread(hThread) != (DWORD) -1)
    {
        Success = GetThreadContext(hThread, Context);
    }

Si todo ha ido bien Success tendrá el valor TRUE y será necesario llamar a la API GetXStateFeaturesMask para obtener la máscara de las características válidas en el contexto especificado.

Hay que tener en cuenta que si un bit en particular no está activado quiere decir que se está en un estado inicializado y el contenido obtenido con la API LocateXStateFeature no está definido.
    DWORD64 FeatureMask;
    Success = pGetXStateFeaturesMask(Context, &FeatureMask);
Si todo ha ido bien Success tendrá el valor TRUE y ya solo tenemos que llamar a la API LocateXStateFeature para obtener los registros YMM. Para saber si estamos en 32 bits (podemos obtener del registro YMM0 al YMM7) o en 64 bits (podemos obtener del registro YMM0 al YMM15) usaremos el tercer parámetro de la API para obtener el tamaño:
    PM128A Xmm;
    PM128A Ymm;
    DWORD FeatureLength;
    Xmm = (PM128A)pLocateXStateFeature(Context, XSTATE_LEGACY_SSE, &FeatureLength);
    Ymm = (PM128A)pLocateXStateFeature(Context, XSTATE_AVX, NULL);
Y ahora con un simple
for (i = 0; i < (FeatureLength / sizeof(*Ymm)); i++)
Podemos acceder a la parte alta y baja de los primeros 128 bits de YMM y a la parte alta y baja de los últimos 128 bits de YMM que corresponden con los registros XMM:
    Ymm[Index].High 
    Ymm[Index].Low
    Xmm[Index].High 
    Xmm[Index].Low
Actualmente el ollydbg no tiene soporte para Intel AVX, así que se puede ir usando la versión básica del soporte AVX del x64dbg:



A continuación vamos a ver como obtener el CONTEXT de x87 FPU, MMX, SSE, XMM en las versiones de 32 bits y de 64 bits:

Win32: La estructura CONTEXT en Win32 tiene la siguiente pinta:
    typedef struct _CONTEXT {
        ...
        // This section is specified/returned if the
        // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
        FLOATING_SAVE_AREA FloatSave;
        ...
        // This section is specified/returned if the ContextFlags word
        // contains the flag CONTEXT_EXTENDED_REGISTERS.
        // The format and contexts are processor specific
        BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
    } CONTEXT;

    #define SIZE_OF_80387_REGISTERS      80
    typedef struct _FLOATING_SAVE_AREA {
        DWORD   ControlWord;
        DWORD   StatusWord;
        DWORD   TagWord;
        DWORD   ErrorOffset;
        DWORD   ErrorSelector;
        DWORD   DataOffset;
        DWORD   DataSelector;
        BYTE    RegisterArea[SIZE_OF_80387_REGISTERS];
        DWORD   Cr0NpxState;
    } FLOATING_SAVE_AREA;
Acceder a los 3 registros de 16 bits de la x87 FPU:
    ControlWord: Context.FloatSave.ControlWord;
    StatusWord: Context.FloatSave.StatusWord;
    TagWord: Context.FloatSave.TagWord;
Para obtener los registros ST0-ST7 (80 bytes ocupan todos los registros) se usa el campo Context.FloatSave.RegisterArea:
    BYTE RegisterArea[80];
    memcpy(RegisterArea, Context.FloatSave.RegisterArea, 80);
Obtener MMX desordenados:
    uint64_t mmx[8];
    for(i = 0; i < 8; i++)
    {
        memcpy( &(mmx[i]), & (Context.FloatSave.RegisterArea[i*10]), sizeof(mmx[i]));
    }
MxCsr: el registro MxCsr se encuentra en Context.ExtendedRegisters[24]:
    DWORD MxCsr;
    memcpy(&MxCsr, & (Context.ExtendedRegisters[24]), sizeof(MxCsr));
XMM: Para acceder a los 8 registros XMM disponibles en 32 bits se usa el campo ExtendedRegisters de la siguiente forma Context.ExtendedRegisters[(10 + indice) * 16]:
    M128A XmmRegisters[8];
    for(i = 0; i < 8; i++)
    {
        memcpy(&(XmmRegisters[i]),  & (Context.ExtendedRegisters[(10 + i) * 16]), 16);
    }
Win64: La estructura CONTEXT en Win64 y otras estructuras que nos interesan tienen la siguiente pinta:
    typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
    ...
    // Floating point state.
    union {
    XMM_SAVE_AREA32 FltSave;
    struct {
        M128A Header[2];
        M128A Legacy[8];
        M128A Xmm0;
        M128A Xmm1;
        M128A Xmm2;
        M128A Xmm3;
        M128A Xmm4;
        M128A Xmm5;
        M128A Xmm6;
        M128A Xmm7;
        M128A Xmm8;
        M128A Xmm9;
        M128A Xmm10;
        M128A Xmm11;
        M128A Xmm12;
        M128A Xmm13
        M128A Xmm14;
        M128A Xmm15;
        } DUMMYSTRUCTNAME;
    } DUMMYUNIONNAME;

    // Vector registers.
    M128A VectorRegister[26];
    DWORD64 VectorControl;
    ...
    }

    typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32;

    // Format of data for (F)XSAVE/(F)XRSTOR instruction
    typedef struct DECLSPEC_ALIGN(16) _XSAVE_FORMAT {
        WORD   ControlWord;
        WORD   StatusWord;
        BYTE  TagWord;
        BYTE  Reserved1;
        WORD   ErrorOpcode;
        DWORD ErrorOffset;
        WORD   ErrorSelector;
        WORD   Reserved2;
        DWORD DataOffset;
        WORD   DataSelector;
        WORD   Reserved3;
        DWORD MxCsr;
        DWORD MxCsr_Mask;
        M128A FloatRegisters[8];
        #if defined(_WIN64)
            M128A XmmRegisters[16];
            BYTE  Reserved4[96];
        #else
            M128A XmmRegisters[8];
            BYTE  Reserved4[192];
        ...
    }
Acceder a los 3 registros de 16 bits de la x87 FPU:
    ControlWord: Context.FltSave.ControlWord;
    StatusWord: Context.FltSave.StatusWord;
    TagWord: Context.FltSave.TagWord;
Para obtener los registros ST0-ST7 (80 bytes ocupan todos los registros) se debe obtener la parte baja (10 bytes) de cada entrada de 128 bits del campo Context.FltSave.FloatRegisters:
    BYTE RegisterArea[80];
    for(i = 0; i < 8; i++)
    {
        memcpy(&(RegisterArea[i * 10]), & (Context.FltSave.FloatRegisters[i]), 10);
    }
Para obtener los MMX desordenados se debe obtener la parte baja (64 bits) de cada entrada de 128 bits (M128A FloatRegisters[8]) del campo Context.FltSave.FloatRegisters:  
    uint64_t mmx[8];
    for(i = 0; i < 8; i++)
    {
        memcpy(&(MMX[i]), & (Context.FltSave.FloatRegisters[i]), sizeof(MMX[i]));
    }
MxCsr:
DWORD MxCsr = Context.FltSave.MxCsr;
XMM: acceder a los 16 registros XMM disponibles en 64 bits es mucho más fácil, se debe usar el campo Context.FltSave.XmmRegisters.
    M128A XmmRegisters[16];
    for(i = 0; i < 16; i++)
    {
        memcpy(& (XmmRegisters[i]), & (Context.FltSave.XmmRegisters[i]), 16);
    }

Petición & Agradecimientos

En primer lugar, gracias al equipo de Security By Default y Buguroo por su apoyo y en segundo lugar me gustaría que la gente que haya trabajado y/o experimentado se animara y escribiera más sobre este tema.

David Reguera Garcia aka Dreg @fr33project - Senior Malware Analyst en Buguroo

Revolver barrel images by Jorge Martinez Taboada @jmtaboada - Senior UX Consultant en Buguroo
Leer más...

17 noviembre 2014

Bluebox-ng HowTo (I)

Más de un año después de publicar aquí la versión alpha de Bluebox-ng, por fin liberamos la primera estable esta semana en el Arsenal de la Black Hat Europa. Así que más o menos vamos a contaros lo mismo que explicábamos allí, ya que nos interesan mucho las opiniones de esta, nuestra comunidad.

Finalmente decidimos definir el proyecto como un escáner de vulnerabilidades VoIP/UC (Unified Communications).

Pero la idea es la misma, necesitábamos algo para automatizar todos los pasos manuales que seguíamos durante los test de intrusión específico en este tipo de entornos. Como sabemos, en otros como la web sí disponemos de multitud de opciones libres y de pago para este cometido. Pero no era así en nuestro caso, las escasas opciones no eran suficientes para nuestro fin (además de prohibitivas).

Antes de meternos en materia, comentar que está reescrito desde 0 en JavaScript, ya que el proyecto comenzó como un conjunto de scripts (en CoffeeScript), que "no escalaban". Ahora, a parte de el cliente de consola, se puede utilizar como una librería más de Node.js y es sencillo añadir nuevos módulos. Además ahora somos dos, estamos centrados en probarlo en entornos reales y, al mismo tiempo, empezando a añadir nuevas funcionalidades (ie: vectores para el protocolo DNS).

Para instalarla simplemente hay que tener Node (una versión actual por favor ;) y luego la forma más sencilla es utilizar el gestor de paquetes Npm como para cualquier otra librería/herramienta de este ecosistema:

npm i -g bluebox-ng

En Kali el script oficial para instalar node desde el repositorio de paquetes (y tenerlo actualizado de una forma cómoda) no funciona, así que dejo uno colgado para ahorraros trabajo, podéis usar el siguiente comando y listo:
curl -sL https://raw.githubusercontent.com/jesusprubio/bluebox-ng/master/artifacts/installScripts/kali.sh | sudo bash -

Como en todas las utilidades de este tipo disponemos de la opción de realizar un test de intrusión automático (del que hablaremos más adelante) o manual, lanzando los módulos y jugando con los distintos parámetros. Debemos aclarar que actualmente tenemos implementado un conjunto de vectores de ataque que consideramos "suficiente por ahora", pero nos queda mucho trabajo. Sabemos que la VoIP incluye a muchos más protocolos que SIP, y hay vectores muy interesantes que involucran a otros, como RTP. E incluso a distintos tipos de señalización como IAX, H323 o Skinny se siguen utilizando y también habría que contemplarlos. Aunque esto último nos preocupa menos, ya que SIP está "ganando la batalla" en estos últimos años.

En el artículo de la versión alpha hay algunos ejemplos cuya ejecución es muy similar, así que no los voy a repetir. Para ver uno actualizado, el siguiente muestra un escaneo SIP típico (lo mismo que el "svmap" del SIPVicious, para entendernos).

Podéis consultar todos los comandos podéis usar el tabulador o el comando "help". Con este mismo acompañando al nombre de un módulo nos ofrece la descripción del mismo. Entre ellos nos encontramos de distintos tipos:

  • Típicas herramientas de red: TCP ping, Whois, DNS resolve/reverse, Traceroute, Geolocation, Nmap ...
  • Vectores de ataque al protocolo SIP: Escáner, fuerza bruta de extensiones y contraseñas, llamadas sin autenticar, tests de stress, DoS, etc.
  • Fuerza bruta y explotación de la AMI (Asterisk Manager Interface) de Asterisk.
  • Seguridad: SHODAN, Exploitsearch, etc.
  • Fuerza bruta de protocolos comunes en estas infraestructuras: TFTP, SSH, MYSQL, SNMP, FTP, LDAP, etc.
  • Pijadas varias: Google Dorks y contraseñas por defecto de paneles de gestión web, un "dumb fuzzer" ...

shoot4.png

shoot5.png
Ayuda general

helpScan.png
Ayuda módulo "sipScan"

sipScan.png

sipScan2.png
Uso módulo "sipScan"

Como comentamos, la principal novedad es el modulo "auto", que hace el trabajo por nosotros. Los parámetros que recibe son los siguientes:

  • "targets": Pues eso, se le puede pasar una dirección IP o un rango en formato CIDR. Actualmente estamos añadiendo soporte para dominios SIP y DNS.
  • "srcHost": En la capa de aplicación el protocolo SIP incluye la dirección IP de origen, por lo cual debemos de indicarla de alguna forma. Por defecto se pasa el nombre de la interfaz de red y la herramienta será capaz de obtenerla de ahí. Si se decide "spoofearla" (útil en algunos casos) debemos de ser conscientes de que algunos servidores (según la configuración) van a enviar las respuestas a esta dirección en vez de a la nuestra. Si haces una auditoría fuera de tu red, a parte de redirigir los puertos, deberías utilizar "external" en este parámetro para que obtenga tu dirección IP utilizando icanhazip.com y la incluya en las peticiones.
  • "srcPort": Lo mismo pero para el puerto, en este caso por defecto usa el "real" (el mismo que a nivel de transporte).
  • "sipDomain": Si no se le especifica usará la dirección IP del objetivo, una configuración ampliamente usada. Pero existen casos en los que hace falta pasarlo, así que permitimos la opción.
  • "timeout"
  • "nmapLocation": En algún paso, que comentaremos más adelante, se utiliza el Nmap  por lo que necesitamos pasarle la ruta.
  • "profile": Típico perfil en una herramienta de este tipo, podemos elegir uno de los disponibles o utilizar el nuestro. Para una auditoría real deberíamos utilizar el "aggressive" evitando de esta forma dejarnos casos posibles sin probar.
  • "reportPath": Ruta para guardar el fichero ".html" generado con el informe.

Uso módulo "auto" (perfil "demo")

¿Qué hace todo esto? A parte de no disponer de herramientas adecuadas tampoco existe una metodología de facto, estilo OWASP, simplementes algunos apuntes incluidos entre otras más genéricas. Nuestra solución para esto fue revisar las vulnerabilidades conocidas y las secciones de seguridad de la documentación de los principales servidores libres y alguno propietario. De esa forma conseguimos especificar un conjunto de pasos para cubrir los casos más comunes, pero de momento no se le puede llamar metodología (estamos en ello ;). En el siguiente post lo explicaremos con calma y veremos cómo usar Bluebox-ng como una librería para implementar, por ejemplo, un sistema de "pentesting" continuo para nuestros servidores de voz.

Informe

Artículo cortesía de Jesús Pérez y Sergio García
Leer más...

16 noviembre 2014

Enlaces de la SECmana - 250


Leer más...

15 noviembre 2014

Mi experiencia en 8.8 y Ekoparty 2014 #eko10




Que este año ha sido extenuante la cantidad de eventos de seguridad, tanto públicos como privados, en los que he dado conferencias, es algo que los que seguís mi actividad en mi twitter como en el blog de Securízame, o en el propio Security By Default, ya es algo que os cansáis, sólo de leerlo. Incluso en una ocasión, un alegre anónimo me llegó a calificar como “feriante de la seguridad”

Reconozco que ir a eventos es algo que me encanta, y si además doy una charla, sea o no repetida, pues aún más… Quien es feliz haciendo lo que le gusta, creo que tiene bastante ganado, y no vive amargado teniendo que trollear quienes así lo hacen. Al menos en esto, me considero afortunado.

Uno de los grandes tours que me tocó hacer este año fue la última quincena de Octubre, en la que me pegué 15 días en mi querida Latinoamérica, en concreto en Chile y en Argentina.

Ya desde el año pasado, que tuve la oportunidad de debutar en el 8.8, sabía que dicho evento iba a ser uno de mis favoritos. Así que este año, envié un paper y afortunadamente me lo aceptaron. Asimismo me propusieron, que ya que estaba por allí, iba a organizarse en esa misma semana, la primera edición del BSides Chile, por lo que si quería, enviase propuesta para dar una charla allí también. Así que 2x1, aproveché a contar “APT: Anatomía de un Ataque” en BSides.cl y “CSI Madrid S13E37” en la 8.8.


La experiencia en Chile fue genial e hice buenos nuevos amigos como Julián Zarate de Argentina, que dio una charla francamente interesante sobre telefonía móvil en el cuál mostró una vulnerabilidad de un operador de telefonía local “que no se puede decir” ;D.

Igualmente, y como siempre, tuve la oportunidad de volver a ver a mis compañeros habituales: Jaime Restrepo @dragonjar, que desveló la investigación que hizo sobre el software de control remoto de vehículos de una famosa marca americana, y su total compromiso de cualquier coche de esa marca, que implemente ese sistema, en países de LATAM, Claudio Caracciolo que entre Latch y Latch, tuvo a bien juguetear conmigo y dedicarme una foto trolleada en su charla (sin calcular que la semana siguiente en Argentina, ejecutaría mi particular vendetta!) Matias Katz, que explicó cómo añadir una backdoor a X11 con muy poquitas líneas de código Python utilizando el jack de los auriculares, como mecanismo de unlock del PC (fue muy grande esta charla), César Cerrudo que detalló su investigación en diferentes ciudades del mundo para identificar la comunicación entre ciertos sensores que se encuentran en las calles, para hacer que los semáforos asociados, modifiquen la luz al color deseado a voluntad de César. 

Además, en esta ocasión, incluso no fui el único español que se va a las Américas, puesto que compartí cartel con Pablo González y David Melendez. A David le tengo especial admiración por haber sido capaz de diseñar, construir y programar un dron con materiales reciclados: un crack este tío!


De Santiago de Chile viajé a Buenos Aires, donde asistiría como ponente a la décima edición de Ekoparty, el congreso más grande y veterano de toda Latinoamérica. Sin duda alguna, me perdonen los demás organizadores de congresos, el evento del que más orgulloso y contento me siento de haber podido estar, y en el que ya fui ponente en 2012 con “Welcome to your secure /home, $user” (del que me han prometido que han encontrado la cinta con el video y que “próximamente”, publicarán en su web). En esta ocasión, y nada más llegar a Buenos Aires, ya tenía una agenda curiosa con compromisos en el país Argento. Nos encontramos en las oficinas de Mkit con Jaime Restrepo y Jacobo Tibaquira, dispuestos a participar (y “boludear”) en la edición de esa semana de #radiohack, en el que entre cervezas y risas, se nos pasaron más de dos horas y media como si hubiésemos sido trasladados a otra dimensión. 




De ahí, y tras una visita al hotel, para dejar varios regalos que me dieron, fuimos Jaime y yo al bar 1745 con el resto de los speakers y organizadores del CTF de Ekoparty. Tras un montón de cervezas, el amigo Claudio Caracciolo pasó a buscarme para invitarme a una excelente cena en Puerto Madero, basada en carnes argentinas (estoy como el perro de Paulov mientras escribo esto), en compañía de su encantadora esposa e hijos. 

Al día siguiente comenzó oficialmente la Ekoparty. Hasta 2013, y en las últimas ediciones, el lugar elegido para acoger al público de la Eko era KONEX, un centro ambientado en lo que parece una nave industrial abandonada, en el centro de Buenos Aires. Sin embargo, este año, aprovechando la celebración de la décima edición, y teniendo previsión de que la cantidad de público iba a ser aún mayor, decidieron cambiar la ubicación a Punta Carrasco, una zona al lado del río, en el que se celebran eventos como bodas y bautizos. Para el auditorio principal, se utilizó una carpa que acotó un recinto en un escenario en el que se suelen dar conciertos, por lo que esta vez se querían asegurar que no se quedaban cortos de sitio… y así fue. Según los registros indicados, hubo 1800 asistentes!

Por la mañana del primer día, hubo un desayuno previo con un panel de discusión, sobre delitos informáticos, en el que participé junto a Cristian Borguello, Marcelo Temperini (dos de los tres impulsores de la iniciativa ODILA, proyecto que pretende ayudar a realizar denuncias por ciberdelitos en Argentina) y Domingo Montanaro


Tras la mesa redonda, me acerqué al auditorio principal donde dio comienzo el panel de inauguración de la Eko, donde participaron, hackers de la vieja escuela del panorama nacional Argentino, como Fernando Bosembiante, redactor de la revista Virus Report (a la que estuve echando posteriormente un vistazo a algunos números y recordando tiempos pasados… mode nostalgia=ON en la que se detallaba el funcionamiento de virus como Michelangelo, Flip, Barrotes, etc,…), Hernán Ochoa e Iván Arce, entre otros,…



Tras la hora de comida, me tocaba dar un workshop de un par de horas. Recuerdo que en 2012, dí en un área pequeñita del KONEX un workshop de “Buenas Prácticas de Seguridad Perimetral”, en el que empezaron habiendo unas 20 personas sentadas en sillas alrededor de un televisor en el que se publicaban las slides, y al final había unas 200 personas. En esta ocasión, el lugar donde tuve que dar el workshop era el auditorio principal, donde habían dispuesto sillas para que cupiesen unas mil personas, para los workshops. Si iba con algún tipo de nervio para el día siguiente, os aseguro que fue un buen entrenamiento.



Esta vez, hablé sobre peritaje informático forense. El título fue “Memorias de un perito informático forense Vol. I” en el que detallé cuatro casos reales en los que me he visto involucrado como perito, que me parecieron más relevantes para contar qué me encontré, los pasos que seguí y cómo llegué a emitir mi dictamen. Por supuesto, anonimicé convenientemente todo lo relacionado con las personas y empresas involucradas en cada caso, para mantener la confidencialidad de los clientes. Tras dos horas de charla, en las que hubo risas, dudas y espero que moraleja y buenos consejos para los que se encuentran en fase de aprendizaje de las artes forenses, aún me faltó tiempo para contar el cuarto caso preparado.



Por la tarde, nos fuimos con unos cuantos amigos y otros asistentes al evento a disfrutar de uno de los grandes atractivos gastronómicos de Buenos Aires: la pizza!!! Tras volver al hotel con el mexicano Luis Colunga, nos dimos una vuelta y partimos a la fiesta de speakers. Si bien otros años, alquilaban un chalet en el que se hacía un asado, regado por un sinfin de cervezas, en esta ocasión se hizo un cocktail en Punta Carrasco. El ambiente inmejorable igualmente, con Nico Waisman, César Cerrudo y otros “grossos” del panorama argentino. Bien entrada la noche, uno de los organizadores de Ekoparty, mi amigo Leonardo Pigner, me acercó de vuelta al hotel.

Al día siguiente, a media mañana, me fuí con todo el campamento a Punta Carrasco. Aproveché para ver la parte de los sponsors. Había cosas muy chulas: La gente de Sysarmy tenían un maniquí hecho de un material que creo que era silicona, al que tenías que pegarle un puñetazo a una distancia mínima y, en base a unos sensores que llevaba incorporaba, daba una puntuación… El reto se titulaba “No soporto más…”.

Había diversos stands con cosas de lo más freak, ejemplares de equipos de radioaficionado (estuve intentando que el tipo que estaba allí capturase las frecuencias del aeropuerto que estaba cerca del evento, pero no coló…), uno sobre Bitcoins, en el que tenían un ATM que convertía pesos argentinos en Bitcoins, hecho con un tablet Android como GUI y diferentes componentes a los que no tuve acceso. Por supuesto, estaba el ya clásico puesto de palomitas (dulces) de ESET, en el que pude saludar al amigo Sebastian Bortnik así como participar en un pequeño monólogo ante una cámara en la que pedían a la gente que diese la definición sobre lo que era un hacker en realidad, todo esto por la reciente definición de Hacker por parte de la RAE, como "Pirata Informático” en la que Chema Alonso ha organizado una recogida de firmas en change.org para que esa definición sea retirada, o al menos modificada por otro significado, que de verdad exprese lo que es un hacker. 



Aparte, estuve recorriendo con mi amiga criminalista Laura Quiñones los diversos stands. Vimos algunos relacionados con talleres de Python así como empresas patrocinadoras del evento que buscaban una visibilidad de sus productos con un fin más comercial.



Uno de los stands en el que me quedé con ganas de participar era el de Base4. Por lo que me contó Leo Pigner, la idea era un concurso por equipos, en el que te dan una estructura de red y te proporcionan switches, firewalls, IPSs, balanceadores, etc,… y te piden que lo conectes y configures de la forma más segura posible.     

A mediodía, como con una hora de retraso, el momento que reconozco que me tenía nervioso, había llegado: Tocaba subirse al escenario de nuevo a dar la charla para la que había ido a la Ekoparty. En esta ocasión, la conferencia era: “Cooking an APT in the paranoid way”. En una hora, expliqué un experimento que hice en verano, creando un perfil de LinkedIN con una foto de una chica guapa y añadiendo a diferentes empleados públicos de Ministerios Españoles. La experiencia consistía en ver cuánta gente buscaba más información sobre la chica, interactuando con ella, y haciendo click en diferentes enlaces. Los destinos hacían un fingerprint de las versiones de navegador y complementos que tiene instalados la víctima, a fin de poder realizar un ataque más personalizado con una efectividad segura posteriormente. Una de las partes más importantes del APT, era que dado el sector al que iba dirigido, y el tipo de contactos que hice, quise tomar mis precauciones para lograrlo con un nivel de anonimato casi extremo. Para ello, expliqué como blanquear dinero en bitcoins, de una forma muy difiícil de tracear, así como diferentes servicios de privacidad que se pueden comprar con esta moneda, y que me permitieron ser invisible a lo largo del experimento. Aproveché, como prometí, para ejecutar mi “vendetta” a Claudio Caracciolo en la charla que dí. Obviamente, fueron bromas con todo el aprecio y el fair play que tenemos entre ambos.



La crónica del evento fue llevada a cabo de una forma ejemplar por la gente de ESET Latinoamérica, publicando varios posts relacionados en el blog www.welivesecurity.com. Entre otros, podéis ver la crónica que hicieron de mi charla en este enlace: http://www.welivesecurity.com/la-es/2014/10/30/cocinando-un-apt-de-forma-paranoica/.

Para este año, y aunque no sé si por estar el recinto pegado a la pista de aterrizaje del aeropuerto AEROPARQUE, la Eko estaba ambientada en entorno aeronáutico… Y si el objetivo era acordarnos de los aviones, se puede decir que se logró, porque cada pocos minutos, despegaba un avión que pasaba bastante cerca de la carpa, haciendo que fuese bastante complicado mantener la concentración a los ponentes y asistentes. Por lo demás, la experiencia del workshop y la charla desde ahí arriba (recordad que es un escenario donde se dan conciertos) fue indescriptible y por el feedback que recibí, las preguntas que me hicieron tras el workshop y la charla, así como la cantidad de fotos que me hice con un montón de asistentes argentinos al evento, me hacen sentirme muy contento, con la sensación del deber cumplido y de sentirme bienvenido en Argentina.
Sólo espero que esta vez, las charlas queden grabadas y puedan ser publicadas. De verdad que me gustaría volverla a ver y añadirla al Canal Youtube de charlas que hemos creado en Securízame.


Por ser la décima edición de Ekoparty, inauguraron los EkoAwards, que si bien dieron cierta polémica al principio, en concreto una de las categorías, finalmente tuvieron su momento de fama. De hecho, aún queda un premio por votar. Este año han solicitado, mediante un Google Form, que se vote la mejor charla de 2014. Puedes hacerlo desde este enlace: http://bit.ly/besteko10

No pude quedarme al evento completo, puesto que esa noche partí desde Buenos Aires, con rumbo a Barcelona, para participar al día siguiente en el Congreso NoConName, otro de los que tengo en gran estima, y en el que nunca había dado una charla aún. 

Tuve que conformarme con seguir la cuenta de twitter de ekoparty o el hashtag #eko10, así como diferentes medios de comunicación online argentinos en los que tuvo gran repercusión como el Diario Clarin o El Cronista.


Bueno che, ¿y ahora qué? 

Si estás en tierras gauchas, para hacer amena la espera hasta una nueva edición de Ekoparty, te dejo una amplia lista de eventos de seguridad para este mes de noviembre.

Posiblemente ya sabrás que tras la Ekoparty se celebró en la ciudad de Rosario, la primera edición de RiseCon, que la semana que viene, el 21 y 22 de Noviembre, arranca en Santa Rosa el evento Pampaseg, el 23 de Noviembre la primera edición de Pwnconf, un evento relacionado con seguridad informática, sysadmin y networking,  en la ciudad de Mar de Plata, y a finales de mes, el 29 de Noviembre, en Buenos Aires, la tercera edición de AndSec 


Greetings: A los componentes de la organización de los tres eventos, por cuadrarlo todo en fechas y tratar a los ponentes con tanto cariño. A Lucía, proveedora de muchas de las fotos que he publicado en este post. A los aficionados por la seguridad, chilenos y argentinos, con los que tuve la oportunidad de compartir grandes momentos durante la temporada relatada. A todos vosotros: Gracias! 

Leer más...

13 noviembre 2014

Cifrando los logs de Apache con libCryptoLog

En muchas ocasiones sucede que es necesario tener una política de cifrado de logs y no siempre es fácil 'convencer' a los servidores para que guarden la información cifrada.

Para abordar ese tipo de escenarios he liberado la versión 0.1 (mini-beta?) de libCryptoLog que permite manipular 'al vuelo' la forma en la que cualquier servidor guarda los logs. Y digo cualquiera porque en realidad, si bien este post va de Apache, el método que voy a explicar sirve para cualquier otro servicio (Postfix, Nginx ...).

De lo que se trata es de 'convencer' al servidor en cuestión de que toda información que vuelque al fichero que nos interese cifrar se almacene cifrada desde el minuto 0.

Después de pensar y re-pensar una forma que me convenciese para abordar este problema, programé libCryptoLog con la idea de que fuese 'plugeable', es decir, en vez de hardcodear en la librería las rutinas de cifrado, he decidido que eso caiga en un 'helper' externo para que cualquiera pueda adaptarlo fácilmente a sus requerimientos.

El funcionamiento es fácil: Por lo general, cuando Apache o cualquier otro servidor van a escribir a disco, suelen emplear dos funciones: fprintf() o write(), en el caso de Apache el 'meollo' está en write().

Como muchos de vosotros en este punto ya habréis deducido, lo que estoy haciendo es 'hookear' ambas funciones y alterar la forma en la que procesan los datos que van a almacenar a fichero.

El procedimiento es muy fácil de entender:

1- fprintf() y write() toman una cadena y la vuelcan a un fichero

2- libCryptoLog intercepta esas llamadas y extrae la cadena de texto

3- Esa cadena de texto se le pasa a un programa externo para que la cifre, le ponga colores o lo que sea

4- libCryptoLog toma el resultado de ese programa y ES ESO lo que almacena empleando fprintf o write

De esa forma los logs, antes de que 'toquen disco' ya están cifrados.

Este modelo permite que cualquiera, en cualquier lenguaje, programe sus propios helpers para decidir como transformar la cadena de texto. Junto con la librería van unos cuantos helpers para cifrar logs con RSA.

Vamos a ver un ejemplo con Apache en Centos 6.5:

Lo primero es descargar la librería desde aquí y descomprimirla con:

# tar -xvzf libCryptoLog.tgz

Para usar los helpers escritos en Perl, es necesario tener disponible la librería perl-Crypt-RSA, la instalamos

# yum -y install perl-Crypt-RSA

Una vez instalada, ya podemos generar nuestras claves publica y privada, es MUY CONVENIENTE que la clave privada no esté en el sitio donde vamos a cifrar por razones más que obvias. Esa clave es la llave para acceder al contenido de los logs por lo que se ha de guardar en un sitio externo donde se vayan a descifrar los logs.

Ejecutando:

# perl rsacreate.pl

Vemos que en el directorio han aparecido dos nuevos ficheros: key.public y key.private

Copiamos key.public a /usr/local/etc/

# cp key.public /usr/local/etc/

Igualmente copiamos el 'helper' a /usr/local/bin

# cp rsacrypt.pl /usr/local/bin/

Este es el script que se encargará de cifrar los logs 'al vuelo' usando la clave pública.

Con esto hecho, toca compilar la librería. Aquí hay una parte que se debe configurar. La función write() toma un ID como parámetro para saber en que descriptor debe escribir. No se puede manipular todas las llamadas a write() porque esa función se usa para muchas cosas, es necesario determinar los IDs que corresponden a los ficheros que vamos a cifrar.

Para obtener esta información debemos buscar un PID de Apache y consultar con lsof los IDs de los ficheros que tiene abiertos.

# ps aux | grep -i httpd

root      1508  0.0  1.6 135832 17328 ?        Ss   09:26   0:00 /usr/sbin/httpd
apache    1540  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1541  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1542  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1543  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1544  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1545  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1546  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1547  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd

Y luego

# lsof -p 1508

httpd   1508 root    0r   CHR    1,3      0t0   3903 /dev/null
httpd   1508 root    1w   CHR    1,3      0t0   3903 /dev/null
httpd   1508 root    2w   REG  253,0     3522 398650 /var/log/httpd/error_log
httpd   1508 root    3r   CHR    1,9      0t0   3908 /dev/urandom
httpd   1508 root    4u  sock    0,6      0t0  10395 can't identify protocol
httpd   1508 root    5u  IPv6  10396      0t0    TCP *:http (LISTEN)
httpd   1508 root    6r  FIFO    0,8      0t0  10489 pipe
httpd   1508 root    7w  FIFO    0,8      0t0  10489 pipe
httpd   1508 root    8w   REG  253,0   265970 398649 /var/log/httpd/access_log

Justo al final podemos ver qué /var/log/httpd/error_log y
/var/log/httpd/access_log tienen asociados los IDs 2 y 8. Esto se puede ver en la cuarta columna en formato numero+w, en este caso 2w y 8w

Como solo queremos que estos dos ficheros queden cifrados (son los que guardan la información sensible ...) editamos el fichero libCryptoLog.c y en la parte de:

int filedesyes[2] = {3, 10};

La cambiamos a 

int filedesyes[2] = {2, 8};

Para que la librería sepa cuales llamadas a write debe modificar y cuales simplemente las debe dejar pasar sin hacer nada.

Una vez hecho eso, compilamos:

# gcc -Wall -fPIC -shared -o libCryptoLog.so libCryptoLog.c -ldl -lssl

Y copiamos nuestra flamante nueva librería en /usr/local/lib

# cp libCryptoLog.so /usr/local/lib/

¡¡ Ya casi casi estamos !!

Ahora, para que se produzca el 'hooking' tenemos que instruir al fichero de arranque de Apache para que defina la variable LD_PRELOAD correctamente en los procesos que genere.

# vi /etc/init.d/httpd

En la parte de start localizamos algo como

start() {
        echo -n $"Starting $prog: "
        LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && touch ${lockfile}
        return $RETVAL
}

Y debemos modificarla para que quede algo así (he puesto en negrita lo que he añadido)

start() {
        echo -n $"Starting $prog: "
        LD_PRELOAD=/usr/local/lib/libCryptoLog.so LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && touch ${lockfile}
        return $RETVAL
}

Y si todo ha ido bien, en cuanto hagamos un stop / start nuestros ficheros de log pasarían a quedar cifrados.

# service httpd stop
# service httpd start

Si hacemos un tail a /var/log/http/error.log ya podemos ver que Apache está guardando la información cifrada:

BEGINCRYPTO
gRNmfi/yS9Vaya37VJ7sM+iZtoYDG976SWPa4XTLnPGccBTd56J8Bk0uLZyK86vopcjdKp2JPDr7
oHWk/TKA00IStIgvTofUH9DeZGepqikIkjJg9wylAJ0ROjpcerozOX1LQWuj+ZoOxRu7K+UIeQmc
389SjDAyqNs/U8UHc75ntbVHy/A1e95fWUAHnkcD/1au463ugNHQmCJoSHA4NgwhDmwUJLafWSKr
T/L6BaOsruxDtkUqu0gBfROadVuc9oALSdRSc5WqA3T5HuS10a49szZ5zedqtQJiQFjikJCRo/v6
tzYHHs3Es+8yfpZti/l3pChW8+zHCxuPRKNccg==
ENDCRYPTO
BEGINCRYPTO
VB68V3MyG7yNHfYc8UR69ZbaC4ztBkOigWnKZzlKTMiXNdSBFEJ++TPKQXUFo4j8AfrgQPL6DQQ8
nd0yoMSaA3ojq+MvBY5cSLstVeEGaIJSXRboZMGyq6UpfOAqvWLvd48w63ND9cKKDBkEQcfUM3a7
S5KPss/qqSKYcsSHsqk=
ENDCRYPTO
BEGINCRYPTO
DN0d0oa8DJrVj7GGuiGUuhRMc8bDIPGUL39Ae51YFwZl1mRoq5EgipcTxyPThTngw7rOobUGrCaS
YY/MlO4FV4HGAsBWsQksfqYzsgbC7Lv+Ek4oe+01rhJ2L70BKPWPiRdr9oQHsWcL8aTDtLj8X/H4
R3XJ76mvNUSOPAPjijE2WZiAIRYmU+0fzTrbJTYaV3GrGYm2rWkoFQu7aImQHqWRsnSs9k9RmLij
3KoX/MpBBd+a0hOhBsZQmLf915VJgp5E2zrqXMwutdyS3+UJ7o+lesK8LfC2jl40aYvVZXZXNPv+
uDsNbkPJIRzXpfmwnR5KtMFcNOdEJ+1378BRrQ==
ENDCRYPTO

 
Ahora queda la parte final ¿y como revierto el cifrado para tener el log original? Para eso, hay un script llamado rsadecrypt.pl que toma como parámetro un fichero entrada y otro salida, en este caso entrada sería error.log y salida error2.log, quedando en este último el formato descifrado.

# perl rsadecrypt.pl /var/log/httpd/error_log error2.log

Si hacemos un tail en error2.log

[Fri Jun 06 09:55:34 2014] [notice] suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
[Fri Jun 06 09:55:34 2014] [notice] Digest: generating secret for digest authentication ...
[Fri Jun 06 09:55:34 2014] [notice] Digest: done
[Fri Jun 06 09:55:34 2014] [notice] Apache/2.2.15 (Unix) DAV/2 PHP/5.3.3 mod_perl/2.0.4 Perl/v5.10.1 configured -- resuming normal operations

Vemos que lo que antes era base64 cifrada, ahora es plain text :)

Evidentemente no todo es gratis, el añadir este 'extra' de cifrado penaliza bastante el rendimiento porque las operaciones RSA son 'pesadas' y además desde un script aun más. 

Hay que tener mucho cuidado en qué servidores se activa esta medida de seguridad y si tienen la capacidad adecuada para soportar el cambio.

Como última cosa, reiterar que en este ejemplo se están usando mis scripts para tratar los logs, en el código de la librería se puede ver el comando definido 

char *command = "perl /usr/local/bin/rsacrypt.pl \"";

Pero ahí puede ir cualquier cosa que trate el texto de los logs.
Leer más...