Resultados 1 al 3 de 3

Protección del código con las defensas de Visual C++

  1. #1 Protección del código con las defensas de Visual C++ 
    HH Administrator Avatar de LUK
    Fecha de ingreso
    Oct 2001
    Ubicación
    SpaÑa
    Mensajes
    5.284
    Descargas
    223
    Uploads
    250
    Protección del código con las defensas de Visual C++
    Michael Howard


    Gran parte del código está escrito en C y C++ y desgraciadamente una gran parte de este código tiene vulnerabilidades de seguridad que muchos desarrolladores no conocen.

    Los programas escritos en cualquier lenguaje pueden tener vulnerabilidades que dejan a sus usuarios abiertos a un ataque, pero los lenguajes C y C++ ocupan un lugar especial en la historia de Internet porque muchas de sus vulnerabilidades de seguridad se deben al mismo motivo por el que estos dos lenguajes de programación son tan populares: el acceso sin restricciones al hardware del equipo y el rendimiento que esto conlleva. Cuando lee acerca de la seguridad y surge C o C++, las palabras "búfer" y "saturación" suelen aparecer muy cerca la una de la otra, ya que los búferes son un ejemplo muy común del acceso directo a la memoria. Este tipo de acceso directo es muy eficaz, pero también muy, muy peligroso.

    Existen varias razones por las que se producen saturaciones de búfer en la producción de código C y C++. La primera ya la he mencionado: estos lenguajes proporcionan acceso directo a la memoria vulnerable. Segundo, los desarrolladores cometen errores. Y tercero, normalmente los compiladores no ofrecen defensas. Es posible proporcionar un remedio para el primer problema, pero entonces C y C++ comenzarían a transformarse en lenguajes distintos.
    El que los desarrolladores cometan errores se puede resolver en parte mediante métodos educativos, pero realmente no veo ningún paso adelante de las instituciones pertinentes. Seguro que hay un lugar en la industria para la educación en materia de seguridad, pero todos somos parte de la solución o parte del problema y me encantaría que las universidades dedicaran más esfuerzos a la educación de sus alumnos en cuestiones de seguridad de software. Probablemente se estará preguntando, "¿por qué las instituciones educativas no intentan formar a los alumnos en esta materia tan crucial?" Francamente, no tengo la menor idea. Es algo deprimente, la verdad.
    Finalmente, aún con una educación excelente, algunos problemas de seguridad son tan complejos que incluso los ingenieros más punteros no podrían resolverlos en su totalidad. Nosotros, los humanos, no somos perfectos.

    La necesidad de crear más defensas en los compiladores es algo en lo que el equipo de Microsoft Visual C++ ha estado trabajando y, aunque lentamente, se han conseguido algunas mejoras con el paso de los años y la ayuda de nuestro equipo de la seguridad. Esta columna resume algunas de las defensas frente a la saturación del búfer disponibles en Visual C++® 2005 y versiones superiores. Tenga en cuenta que algunos compiladores ofrecen defensas, pero Visual C++ tiene dos ventajas muy importantes frente a los compiladores estilo gcc. Primero, todas estas defensas están en el conjunto de herramientas de forma predeterminada; no hay necesidad de descargar ningún complemento extraño. Segundo, las opciones son fáciles de usar.
    Si ningún orden particular, las defensas ofrecidas por el conjunto de herramientas de Visual C++ son:
    • Detección de la saturación del búfer basada en pilas (/GS)
    • Controlador seguro de excepciones (/SafeSEH)
    • Compatibilidad de prevención de ejecución de datos (DEP) (/NXCompat)
    • Selección aleatoria de imágenes (/DynamicBase)
    • Uso automático de llamadas de función más seguras
    • C++ operator::new

    Antes de tratar cada una de estas opciones en detalle quiero dejar claro que estas defensas no compensan la existencia de un código inseguro. Debe esforzarse siempre para crear el código más seguro posible, y si no sabe cómo hacerlo, entonces vaya corriendo a leer alguno de los excelentes libros que tratan sobre esta materia.

    Pila típica comparada con una compilada con /GS (Hacer clic en la imagen para ampliarla)

    También quiero señalar que todo esto es parte de los requisitos del Ciclo de vida de desarrollo de seguridad (SDL, Security Development Lifecycle) en Microsoft, lo que significa que los códigos C y C++ deben usar estas opciones para salir al mercado. Hay excepciones puntuales, pero se producen con poca frecuencia, así que no voy a hablar de ellas aquí.
    Finalmente, debe tener presente un punto importante: Es posible, dependiendo del código en cuestión, sortear estas defensas tan elaboradas. Cuantas más defensas use el código, más difícil será evitarlas, pero ninguna defensa es perfecta. Todas ellas son obstáculos para reducir la posibilidad de éxito de una vulnerabilidad. ¡Queda advertido! La única variante es el uso de llamadas de función más seguras, que son verdaderas defensas y pueden eliminar vulnerabilidades. Observemos cada defensa en detalle.


    Detección de la saturación del búfer basada en pilas (/GS)
    La detección de la saturación del búfer basada en pilas es la defensa más antigua y más conocida disponible en Visual C++. El objetivo del marcador del compilador /GS es sencillo: reducir la oportunidad de que el código malintencionado se ejecute correctamente. La opción /GS está activada de forma predeterminada en Visual C++ 2003 y versiones posteriores, y detecta ciertas clases de desbordamiento de pila en tiempo de ejecución. Se trata de hacer esto incluyendo un número aleatorio en la pila de una función justo antes de la dirección de devolución de la pila. Cuando vuelva la función, el código de epílogo de función comprueba este valor para asegurarse de que no ha cambiado. Si la cookie, como así se llama, ha cambiado, la ejecución se detiene.
    El código de prólogo de la función que establece la cookie se parece a esto:
    Código:
    sub esp, 8
    mov eax, DWORD PTR ___security_cookie
    xor eax, esp
    mov DWORD PTR __$ArrayPad$[esp+8], eax
    mov eax, DWORD PTR _input$[esp+4
    ]

    Y aquí se muestra el código de epílogo de función que comprueba la cookie:
    Código:
    mov ecx, DWORD PTR __$ArrayPad$[esp+12]
    add esp, 4
    xor ecx, esp
    call @__security_check_cookie@4
    add esp, 8

    Visual C++ 2005 también mueve los datos alrededor de la pila para que sea más difícil dañar los datos. Uno de los ejemplos sería el desplazamiento de los búferes a una memoria superior que los no búfer. Por ejemplo, este paso puede ayudar a proteger los punteros de función que residen en la pila. De manera alternativa, al desplazar los argumentos de puntero y búfer a una memoria inferior en el tiempo de ejecución se mitigan varios ataques de saturación del búfer. Consulte el diagrama para comparar una pila típica con una pila /GS.
    La opción de compilador /GS no se aplica en ninguna de las situaciones siguientes:
    • --Las funciones no contienen un búfer.
    • --Las optimizaciones no están habilitadas.
    • --Las funciones se han definido para tener una lista de argumentos variable.
    • --Las funciones se han marcado con la palabra clave sencilla (C++).
    • --Las funciones contienen código ensamblador en línea en la primera instrucción.
    • --El búfer no es del tipo de 8 bytes y tiene un tamaño inferior a 4 bytes.

    Se ha agregado una opción a Visual C++ 2005 SP1 para hacer la heurística de /GS mucho más agresiva y proteger así más funciones. Microsoft agregó esta opción porque se publicó un pequeño número de boletines de seguridad con código que tenía saturación del búfer basada en pilas y el código, a pesar de estar compilado con /GS, no estaba protegido por una cookie. Esta nueva opción aumenta el número de funciones protegidas de manera significativa.
    Use esta opción colocando la línea siguiente en módulos en los que desee protección adicional, como el código que administra datos de Internet:
    #pragma strict_gs_check(on)

    Esta pragma es sólo un ejemplo de cómo Microsoft evoluciona constantemente la capacidad /GS. La versión original en Visual C++ 2003 era bastante sencilla, después se actualizó en Visual C++ 2005 SP1 y una vez más en Visual C++ 2008, ya que tuvimos conocimiento de nuevos ataques y maneras para sortear los ataques existentes. En nuestro análisis, hemos descubierto que /GS no causa problemas de compatibilidad ni de rendimiento.



    Controlador seguro de excepciones (/SafeSEH)
    El gusano CodeRed que afectó a Internet Information Server (IIS) 4.0 fue causado por una saturación del búfer basado en pilas. Curiosamente, /GS no habría detectado el problema explotado por el gusano porque el código no saturó la dirección de devolución de la función afectada, sino que dañó un controlador de excepciones de la pila. Este es un buen ejemplo de por qué usted debe centrarse constantemente en escribir código seguro y no confiar únicamente en estos tipos de defensas basadas en el compilador.
    Un controlador de excepciones es un código que se ejecuta cuando ocurre una condición excepcional, como la división entre cero. La dirección del controlador se conserva en el marco de pila de la función y, por lo tanto, está sujeto a daños. El vinculador que se incluye con Visual Studio® 2003 y sus versiones posteriores incluye una opción que permite almacenar la lista de controladores de excepciones válidos en el encabezado PE de la imagen en el tiempo de compilación. Cuando se genera una excepción en tiempo de ejecución, el sistema operativo comprueba el encabezado de la imagen para determinar si la dirección de controlador de excepciones es correcta. Si no lo es, la aplicación finaliza. Esto habría evitado la acción de CodeRed si hubiera existido la tecnología en el momento en que se vinculó el código. La opción /SafeSEH no causa ningún tipo de descenso del rendimiento, salvo que cuando se genera una excepción, siempre debe vincularse a esta opción.

    Compatibilidad de DEP (/NXCompat)
    Prácticamente todas las CPU que se fabrican hoy en día son compatibles con la capacidad de no ejecución (NX), lo que significa que la CPU no ejecutará páginas sin código. Piense por un momento en las implicaciones de esto: casi todas las vulnerabilidades de saturación del búfer son errores de datos. Entonces, el atacante inserta los datos en el proceso mediante la saturación del búfer y continúa la ejecución dentro del búfer de datos malintencionados. ¿Por qué ejecuta la CPU los datos?
    Al vincular con la opción de /NXCompat su archivo ejecutable estará protegido por la capacidad de no ejecución de la CPU. Según nuestra experiencia, el equipo de seguridad de Microsoft ha tenido muy pocos problemas de compatibilidad debidos a esta opción y, hasta ahora, no ha habido degradación del rendimiento.
    Windows Vista SP1 agrega también una nueva API que habilita DEP para su proceso de ejecución y que una vez establecido, no se puede desactivar:
    SetProcessDEPPolicy(PROCESS_DEP_ENABLE);


    Selección aleatoria de imágenes (/DynamicBase)
    Windows Vista y Windows Server® 2008 son compatibles con la selección aleatoria de imágenes. Esto significa que cuando se arranca el sistema, éste distribuye el orden aleatorio de las imágenes de sistema operativo en la memoria. El propósito de esta característica es simplemente eliminar parte de la capacidad de previsión de los atacantes. Esto se conoce también como selección aleatoria de la distribución del espacio de direcciones (ASLR, Address Space Layout Randomization). Tenga en cuenta que para que la ASLR sea útil, debe tener también DEP habilitado.
    De manera predeterminada, Windows® sólo se permitirá mover los componentes del sistema. Si desea que su imagen circule por el sistema operativo (altamente recomendado), debe vincular con la opción /DynamicBase. Esta opción está disponible en Visual Studio 2005 SP1 y los conjuntos de herramientas posteriores. También se produce un efecto secundario interesante al vincular con /DynamicBase, que consiste en que el sistema operativo distribuye el orden aleatorio de la pila, lo que a su vez reduce la capacidad de previsión y dificulta que los atacantes pongan en peligro un sistema. Tenga en cuenta que también se distribuye el orden aleatorio del montón en Windows Vista y Windows Server 2008. No obstante, esto ocurre de forma predeterminada, por lo que no es necesario compilar ni vincular con ninguna opción especial.

    Llamadas de función más seguras
    Observe las siguientes líneas de código:
    Código:
    void func(char *p) { char d[20]; strcpy(d,p); // etc}
    Suponiendo que *p contiene los datos que no son de confianza, este código representa una vulnerabilidad de seguridad. El aspecto más negativo de este código es que el compilador podría haber trasladado la llamada a strcpy a una llamada de función más segura que enlazara la operación de copia al tamaño del búfer de destino. ¿Por qué? Porque el tamaño del búfer es estático y conocido a la hora de compilar
    Con Visual C++ puede agregar la siguiente línea a su archivo de encabezado stdafx.h:
    #define _CRT_SECURE_COPP_OVERLOAD_STANDARD_NAMES 1

    El compilador entonces seguirá adelante y emitirá el siguiente código desde la función inicial no segura:
    Código:
    void func(char *p) {
    char d[20];
    strcpy_s(d,__countof(d), p);
    // etc}
    Como puede ver, ahora el código es seguro, y el desarrollador sólo ha agregado un #define. Esta es una de mis adiciones favoritas a Visual C++, porque cerca del 50 por ciento de las llamadas de función no seguras pueden ascender a llamadas más seguras automáticamente.


    C++ Operator::new
    Finalmente, Visual C++ 2005 y las versiones posteriores agregan una defensa que detecta el desbordamiento de enteros al llamar a operator::new. Puede empezar con código de esta manera:
    CFoo *p = new CFoo[count];

    Visual C++ lo compila a:
    Código:
    00004 33 c9 xor ecx, ecx
    00006 8b c6 mov eax, esi
    00008 ba 04 00 00 00 mov edx, 4
    0000d f7 e2 mul edx
    0000f 0f 90 c1 seto cl
    00012 f7 d9 neg ecx
    00014 0b c8 or ecx, eax
    00016 51 push ecx
    00017 e8 00 00 00 00 call ??2@YAPAXI@Z ; operator new
    Una vez calculada la cantidad de memoria para asignar (mul edx), se establece o no el registro de CL dependiendo del valor del indicador de desbordamiento después de la multiplicación, de modo que ECX será 0x00000000 o 0xFFFFFFFF. A causa de la operación siguiente (o ecx), el registro ECX será 0xFFFFFFFF o el valor incluido en EAX, que es el resultado de la multiplicación inicial. Esto entonces pasa a operator::new, que generará un error en el caso de la asignación 2^N-1.
    Esta defensa es gratuita. No hay modificador de compilador; esto es simplemente lo que el compilador hace.


    ¿Qué ocurre si hay errores?
    ¡Ah! ¡Esa es la cuestión espinosa! Si cualquiera de las defensas enumeradas se activa, se produce un resultado bastante desagradable: la aplicación finaliza. Esto no es ideal, pero es mucho mejor que ejecutar el código malintencionado del atacante.
    El SDL obliga a que el código nuevo use todas estas opciones defensivas, ya que hay tantos ataques que nunca puede comprobar que su código esté totalmente libre de vulnerabilidades. Una de las frases clásicas del SDL es "asuma que su código tendrá errores... ¿ahora qué?" En el mundo verdadero, "ahora que" significa oponer resistencia. No le ponga las cosas fáciles al código del atacante. Al contrario, vaya un paso por delante para que no consiga sus objetivos. ¡No se rinda!
    Así que compile con la última versión del compilador C++ para obtener un mejor /GS y vincule con el último vinculador para beneficiarse de las defensas de CPU y sistemas operativos.

    Envíe sus preguntas y comentarios a [email protected].
    Michael Howard es administrador principal de programas de seguridad en Microsoft y se encarga de mejorar los procesos seguros y las prácticas recomendadas. Es coautor de cinco libros sobre seguridad, incluidos Writing Secure Code for Windows Vista, The Security Development Lifecycle, Writing Secure Code y 19 Deadly Sins of Software Security.
    Consulte su blog en blogs.msdn.com/michael_howard


    Via msdn2.microsoft.com
    [][][] LUK [][][]
    hackhispano.com
    Citar  
     

  2. #2  
    Moderador Global Avatar de hystd
    Fecha de ingreso
    Jul 2005
    Ubicación
    1, 11, 21, 1211...
    Mensajes
    1.596
    Descargas
    58
    Uploads
    0
    Buen post! es cierto que es necesaria la seguridad en un compilador (enlazador), y no sólo eso sino la eficiencia por supuesto, pero hablando en temas de seguridad, interesa más que si se produce por ejemplo una excepción en tiempo de ejecución de un programa, sea el Sistema Operativo quien sepa responder adecuadamente. Esta forma de trabajar de Microsoft hace pensar que sus Sistemas operativos son robustos, y que el fallo es de los programas que diseñan los usuarios... y haciendo un compilador seguro se evitará que los programadores "universitarios no preparados" hagan un Software robusto...

    Pues bien mi respuesta es que esto que se pretende hacer es como querer construir un edificio en arenas mojadas... Está muy bien que el edificio se construya con los mejores materiales, con los mejores constructores, sea lo más resistente posible, etc... pero que a la primera de cambio no venga una ola y derrumba por completo todo el trabajo por estar construido encima de la arena...

    Personalmente, he visto el software desde dos puntos de vista: atacante y defensor. En ambos puntos siempre he visto y he utilizado numerosas de sus funciones de la API para lograr los objetivos deseados (casi siempre). ¿Cabe hablar de un compilador bueno o malo, si al final se puede conseguir que un proceso acceda al espacio de direcciones de memoria de otro proceso? ¿Cabe hablar de un buen compilador o malo si al final si se quiere, se puede desbordar la pila o provocar una excepción y ejecutar código en modo kernel? No le echemos toda la culpa a los compiladores, y si no, probemos ejecutar dos códigos vulnerables compilados con Visual Studio por ejemplo para Windows y GCC para Linux. Veamos que tal reaccionan...

    Soy universitario, mi cuarto año, en la universidad de Sevilla, y bueno en parte lleva algo de razon en cuanto a lo de no tratar temas de seguridad del Software. No sé en otras universidades, pero en la ETSII de Sevilla este año han quitado C en una asignatura de primero para dar Java en su lugar (supongo que para preparar más al personal en el mundo laboral), pero miedo me da cuando este alumno llegue a asignaturas de próximos cursos sin saber lo que es un puntero...

    Pero si es cierto, por lo menos desde el año en el que yo entré, que en la universidad te proporcionan las bases necesarias para que cada uno se especialice en el tema que quiere. (Te dan una casa vacia y tu la amueblas como quieres).

    Resumiendo, me parece muy bien que se trate temas de seguridad en compiladores, pero más importante es tratar dichos temas en la plataforma que se va a ejecutar...

    Un saludo
    El optimista tiene ideas, el pesimista... excusas

    Citar  
     

  3. #3  
    Moderador Global
    Fecha de ingreso
    Aug 2005
    Mensajes
    6.279
    Descargas
    7
    Uploads
    0
    Estoy totalmente de acuerdo, hystd, de hecho yo creo que _siempre_ debe ser el sistema operativo quien se responsabilize de separar las zonas de memoria.

    OpenBSD, por ejemplo, implementa un sistema por el que el mismo programa compilado una sola vez, sobreescribirá una zona de memoria diferente cada vez ante un desbordamiento de buffer, lo que complica enormente la elaboración de un exploit válido.

    Pienso que se trata de una estrategia más de monopolización, llegando en un futuro a un punto en que que sólo se admitan ciertos compiladores ( que por supuesto no cumplirán con el estándar como lo pueda hacer gcc) para formar los binarios en determinadas plataformas y/o sistemas operativos.

    Salu2


    Keep on Rollin'

    . . . . . . . . . . . . . . . . . . . .
    [[ NORMAS DEL FORO ]]
    . . . . . . . . . . . . . . . . . . . .
    __________
    Citar  
     

Temas similares

  1. Respuestas: 0
    Último mensaje: 12-02-2015, 19:58
  2. Defensas frente a ataques DHCP
    Por LUK en el foro GENERAL
    Respuestas: 1
    Último mensaje: 13-06-2012, 15:47
  3. Defensas contra nmap
    Por LUK en el foro GENERAL
    Respuestas: 0
    Último mensaje: 25-05-2012, 13:40
  4. Codigo de Barras en Visual Basic
    Por chupitron en el foro PROGRAMACION DESKTOP
    Respuestas: 0
    Último mensaje: 26-04-2005, 19:51
  5. Código fuente de programas Visual Basic
    Por gspinze en el foro GENERAL
    Respuestas: 0
    Último mensaje: 05-12-2001, 17:15

Marcadores

Marcadores