Printer Friendly

Tecnicas de ofensa y defensa a los fallos por corrupcion de memoria.

MEMORY CORRUPTION FAILURES ATTACK AND DEFENSE TECHNIQUES

INTRODUCCION

La corrupcion de memoria no es un problema reciente. En [1] se hace referencia a un informe desarrollado por la fuerza aerea de los Estados Unidos en 1972. El reporte indicaba que fabricando adecuadamente las entradas de usuario era posible manipular los apuntadores para producir una fuga de informacion.

Posteriormente, en 1988, se libero el gusano "Morris-Worm" (primer programa de autopropagacion liberado en Internet). Este programa introdujo lo que hoy se conoce como ataques por corrupcion de memoria y el codigo malicioso de autopropagacion. Este documento pretende explicar las diferentes tecnicas de ataque a aplicaciones, los mecanismos de seguridad vigentes y la forma en que un atacante puede evadirlos.

La primera parte de este documento presenta las tecnicas de ataque que han demostrado ser efectivas. Posteriormente, se presenta una generalizacion de las tecnicas que permiten determinar el impacto de un fallo de programacion con respecto a la posibilidad de obtener ejecucion de codigo arbitrario. Tambien se presenta una explicacion sobre el motivo de estas vulnerabilidades y las acciones que se pueden tomar para disminuir el riesgo que representan estos fallos. Finalmente, se exponen las tendencias de los ataques modernos para evadir las estrategias de proteccion en los sistemas actuales.

1. ATAQUES CLASICOS POR CORRUPCION DE MEMORIA

Los ataques por corrupcion de memoria permiten manipular la memoria del programa vulnerable para forzar a la aplicacion a comportarse de manera diferente a la que fue programada. Esta seccion presenta tres tipos de ataques: desbordamiento de buffer en la pila [2], cadenas de formato [3], y desbordamiento de buffer en el monticulo (del termino en ingles " heap") [4].

1.1 Desbordamiento de buffer en la pila

En 1996, Levy publico una explicacion detallada sobre la tecnica de desbordamiento de buffer [2]. El documento genero tal impacto que aun hoy continua siendo un marco de referencia para otros autores [1, 5, 6].

Los programas de usuario utilizan una region de memoria llamada la pila, donde se almacena informacion relacionada con el flujo de ejecucion del proceso. Dicha informacion esta compuesta por datos locales a funciones, direcciones de retorno y apuntadores relativos para la direccion de datos (tambien conocidos como apuntadores del marco de la pila).

En las arquitecturas x86 y AMD64, se han reservado dos registros para controlar el funcionamiento de la pila. El primero de estos registros se conoce como el apuntador de la pila ESP (del ingles, stack pointer) y es el responsable de mantener la referencia al final de la pila; el segundo es el apuntador del marco de pila, gobernado por el registro EBP (del ingles, base pointer).

En la figura 1, se muestra un esquema para representar el espacio virtual de direcciones de los procesos en los sistemas Linux. Como puede observarse, el apuntador de pila suele ubicarse al final del espacio de memoria de usuario y el espacio de pila "crece" hacia las direcciones bajas donde residen el monticulo, los datos globales y el codigo.

[FIGURA 1 OMITIR]

Los datos en la pila utilizan direccionamiento relativo. El CODIGO 1 es un ejemplo de la salida de un compilador para un programa escrito en C que defina dos funciones, main y primera_funcion. Las instrucciones 1 y 2 de CODIGO 1 son conocidas como el preludio y su proposito es configurar un nuevo marco de pila para ofrecer la capacidad de direccionamiento relativo en los datos locales. El uso del direccionamiento relativo puede observarse en la instruccion 5 de CODIGO 1, donde se almacena el valor 0x01 (byte) en una ubicacion 256 bytes adelante del EBP. La instruccion 4 de CODIGO 1 se encarga de reservar memoria en el interior de la pila.
CODIGO 1

COMPORTAMIENTO DE LA PILA

1 primera_funcion:

2 pushl %ebp

3 movl %esp,%ebp

4 subl $264,%esp

5 movb $1,-256(%ebp)

6 .L2:

7 leave

8 ret

9 main:

10 pushl %ebp

11 movl %esp,%ebp

15 jmp .L3

16 .L3:

17 leave


El otro segmento de codigo similar en las dos funciones es la forma en que finalizan y se puede observar en las instrucciones 7,8 y 17,18. La responsabilidad de recuperar la pila depende de la convencion utilizada para llamar una funcion. A. Fog en [7] presenta diferentes convenciones para el llamado a funciones.

El uso de la pila para almacenar datos locales genera una debilidad importante: el hecho de almacenar los datos de usuario contiguos a los datos de control de la pila, permite que un error de programacion sobrescriba la informacion de control con datos de usuario. El CODIGO 2 muestra un ejemplo de esta situacion.
CODIGO 2

PROGRAMA VULNERABLE A DESBORDAMIENTO
DE BUFFER EN LA PILA

1 #include <iostream.h>

2 int main() {

3 char buffer[128];

4 cin>> buffer;

5 return 0;

6 }


En el CODIGO 2, los datos locales a main (los elementos del arreglo llamado "buffer") se encuentran almacenados en la pila. El operador (">>") sobrecargado en istream no hace una validacion de limites sobre la variable de destino. Por lo tanto, si el usuario ingresa una cantidad de datos superior a 128 bytes comenzara a sobrescribir datos en la pila, por ejemplo, el apuntador base de la pila de la funcion anterior y la direccion de retorno almacenada por la instruccion CALL.

Un usuario puede fabricar la entrada del programa de manera que se escriba en la direccion de retorno almacenada, una direccion con las instrucciones que se desea ejecutar. De este modo, cuando la funcion main ejecute la instruccion "ret" se cargara en EIP una direccion controlada por el usuario forzando la ejecucion de codigo arbitrario.

1.2 Cadenas de formato

El CODIGO 3 muestra un programa vulnerable que utiliza cadenas de formato.
CODIGO 3

PROGRAMA VULNERABLE POR CADENAS DE
FORMATO MAL UTILIZADAS

1. #include <stdio.h>
2. int main(int arc, char ** argv) {
3. printf(<<Este programa imprime el primer
   argumento ingresado por el usuario\n>>);
4.
5.   if (argc != 2)
6. return -1;
7. printf(argv[1]);
8. printf(<<\n>>);
9. return 0;
10. }


El problema del CODIGO 3 radica en que la cadena de formato de la linea 7 puede ser controlada por el usuario. En 1999, Tymm Twillman envio un correo al equipo de desarrollo de la biblioteca estandar de C [3] ilustrando como se puede aprovechar este tipo de vulnerabilidades para obtener ejecucion de codigo arbitrario. Para obtener ejecucion de codigo arbitrario, se utiliza el modificador de formato "%n". En [8], se presenta la tecnica de como se puede obtener ejecucion de codigo arbitrario de este modo.

1.3 Desbordamientos en el monticulo

El asignador de memoria ofrecido por la biblioteca estandar de C ofrece su interfaz a traves de las funciones calloc(), malloc(), free() y realloc(). Cada desarrollador de esta biblioteca implementa de manera diferente las estructuras de datos y los mecanismos que utiliza para administrar el monticulo. La biblioteca estandar de C de GNU, utiliza un asignador de memoria conocido como ptmalloc, cuyo codigo esta basado en el asignador de memoria desarrollado por Doug Lea [9].

Los pedazos del asignador de memoria desarrollado por Doug Lea llevan consigo informacion, antes y despues de los datos. El principal objetivo es permitir que dos pedazos sin utilizar puedan unirse en un pedazo mas largo, reduciendo la fragmentacion.

Cuando se realiza un desbordamiento en el monticulo, se pueden modificar los datos de control de los pedazos. Estos datos de control contienen apuntadores para la inclusion de pedazos libres en listas doblemente enlazadas. Cuando se hace un llamado a free() utilizando un pedazo que tiene un pedazo adyacente P libre, el algoritmo de la funcion hace un llamado al macro del CODIGO 4.
CODIGO 4

MACRO UNLINK

1 #define unlink( P, BK, FD ) {
2 BK = P->bk;
3 FD = P->fd;
4 FD->bk = BK;
5 BK->fd = FD;
6 }


Si el pedazo contiguo P ha sido malformado, se puede escribir en posiciones arbitrarias de memoria y obtener ejecucion de codigo arbitrario.

La tecnica del macro unlink no tiene una aplicacion en las versiones posteriores a 2004 de la biblioteca estandar de C de GNU. Sin embargo, presenta un precedente de que la escritura en posiciones arbitrarias de memoria puede resultar en ejecucion de codigo arbitrario. En [10] se presentan cinco tecnicas aplicables al asignador de memoria actual.

2. MECANISMOS DE PROTECCION A ATAQUES POR CORRUPCION DE MEMORIA

Existen dos alternativas para mitigar el riesgo que representan los fallos por corrupcion de memoria. El primer enfoque consiste en utilizar mecanismos en el lado del programador para evitar que las vulnerabilidades existan. El segundo enfoque consiste en otorgar protecciones adicionales desde el sistema operativo, el compilador y las bibliotecas.

Esta seccion introduce los mecanismos de defensa utilizados para responder a los ataques por corrupcion de memoria. Las protecciones presentadas en esta seccion no son exhaustivas; sin embargo, se presentan las tecnicas mas relevantes y comunes de los sistemas modernos.

2.1 Defensa al lado del programador

Las entradas de usuario comunican las decisiones que este ha tomado. Se debe prestar especial atencion al tamano, la naturaleza y la validez contextual de la entrada. Muchos sistemas almacenan informacion de control en lugares adyacentes a los datos, por lo que un fallo en el control de la memoria puede permitir la modificacion de estos datos de control. Tal es el caso de las direcciones de retorno almacenadas en la pila [2], los datos de control del monticulo [4], los apuntadores virtuales [11], apuntadores a otras estructuras [12], entre otros.

Algunos lenguajes son mas susceptibles a los ataques por corrupcion de memoria. La mayoria de los lenguajes interpretados ofrecen control de limites y deteccion de desbordamientos en tiempo de ejecucion; algunos ofrecen deteccion de estas situaciones en tiempo de compilacion (PERL, JAVASCRIPT). Otros lenguajes (JAVA, .NET, LISP, OCAML) ofrecen una capa de abstraccion entre la administracion de la memoria de usuario y el programador; esta capa de abstraccion puede detectar y prevenir las vulnerabilidades que permiten la corrupcion de la memoria.

Es importante anotar que los mecanismos de deteccion y prevencion que ofrecen estos lenguajes tienen un impacto significativo en el rendimiento de las aplicaciones. Esto puede ser tolerable dependiendo de los requerimientos; la decision final es una pregunta abierta de ingenieria de software. Sin embargo, los programas deben usar las mismas reglas para ejecutar su codigo; esto quiere decir que pueden existir vulnerabilidades en los interpretes o los mecanismos que utilizan estos programas. Burch [13] presenta un escenario de ataque por cadenas de formato aplicado al lenguaje PERL, y Shahin [14] presenta una vulnerabilidad por corrupcion de memoria de una biblioteca en la maquina virtual JAVA.

Aun en lenguajes que exponen la administracion de la memoria, el uso de apuntadores dinamicos [15] puede reducir el riesgo de experimentar corrupcion de memoria. La biblioteca estandar de C++ incluye algo conocido como "smart pointers" que facilita el control de datos en el monticulo.

Es importante incluir pruebas relacionadas con el comportamiento seguro de la aplicacion en el proceso de desarrollo. Las pruebas relacionadas con los fallos por corrupcion de memoria fueron clasificadas por Sutton et al. [16] como pruebas de caja blanca, caja gris y caja negra. Las pruebas de caja blanca consisten en la revision del codigo fuente para buscar instrucciones que lleven a fallos de seguridad. Las pruebas de caja gris consisten en la revision del programa utilizando herramientas de ingenieria inversa. Las pruebas de caja negra, tambien conocidas como "fuzzing" consisten en someter la aplicacion a entradas pseudoaleatorias para detectar comportamientos anomalos de la aplicacion.

2.2 Defensa del sistema operativo

Aunque existen muchos mecanismos de defensa, este documento presenta dos de las tecnicas mas importantes para prevenir la ejecucion de codigo arbitrario.

La primera tecnica fue introducida por AMD con un bit de seguridad conocido como NX (del ingles, No eXecute), que posteriormente Intel comercializo como XD en su procesador pentium 4 (del ingles, eXecuteDisable).

Sin importar el nombre que se de a esta tecnologia, se trata de un bit en las entradas de la tabla de paginas del proceso que, una vez habilitado, hace que el procesador genere excepciones para prevenir la ejecucion de instrucciones en ese espacio de memoria.

El bit NX/XD es una modificacion importante al sistema operativo y, por lo tanto, algunos programas no estan disenados para trabajar con esta tecnologia.

La segunda tecnica es conocida como distribucion aleatoria del espacio de direcciones (del ingles, Adress Space Layout Randomization ASLR); obtuvo su nombre en 2001, cuando el equipo PAX libero la primera implementacion como un parche del nucleo de Linux.

La tecnica se basa en el hecho de que un atacante utiliza direcciones de memoria fijas para lograr la ejecucion de codigo arbitrario. La idea principal es responder a esta estrategia distribuyendo aleatoriamente el espacio de direcciones virtuales de los procesos. Con esta medida, un atacante no puede determinar de manera confiable las regiones del espacio de direcciones del proceso.

Existen diferentes implementaciones de esta tecnologia para diferentes sistemas operativos y en algunas situaciones la relacion es muchos a uno (diferentes implementaciones para el mismo sistema operativo).

3. OFENSA DE APLICACIONES EN LOS SISTEMAS OPERATIVOS MODERNOS

La tecnica de "retorno a biblioteca" [17] es el concepto general que utilizan los atacantes para evadir las restricciones de los privilegios de ejecucion en las regiones de datos. Esta tecnica es mas conocida como "retorno a libc" (del ingles, "returntolibc"), aunque no es necesario que la biblioteca sea libc. La estrategia aprovecha la capacidad de escribir en la pila del proceso para forzar el programa a ejecutar funciones arbitrarias (ubicadas en paginas que no tienen habilitado el bit NX/XD) [17].

Un atacante puede configurar la pila como se muestra en la figura 2, para invocar a mprotect y modificar los privilegios del codigo inyectado.

[FIGURA 2 OMITIR]

La estrategia de mprotect puede implementarse en otros sistemas con funciones similares. Sin embargo, Le [5] y Buchanan et al. [18] presentan una estrategia para reutilizar las instrucciones de la aplicacion y construir codigo arbitrario. La tecnica es conocida como programacion orientada a retornos (del ingles, Return Oriented Porgramming ROP).

Para evadir la distribucion aleatoria del espacio de direcciones pueden emplearse diferentes estrategias. Muller [19] hace una recopilacion sobre algunas de estas tecnicas. Una alternativa consiste en burlar el mecanismo de aleatoriedad utilizando fuerza bruta; esta estrategia tiene como desventaja que puede ser facilmente detectada y requiere que la aplicacion vulnerable pueda recuperarse de un fallo de segmentacion.

Las implementaciones deben evitar consumir la entropia del sistema operativo, por lo tanto es posible que existan debilidades estadisticas en la implementacion. Whitehouse [20] muestra debilidades importantes de la implementacion del sistema operativo Microsoft Windows Vista.

Por la forma en que algunos procesadores manejan la memoria, es posible modificar unicamente los bytes menos significativos de las direcciones. Dependiendo de donde se encuentre el fallo de seguridad, se puede aprovechar esto para reducir la cantidad de bytes desconocidos y mejorar las posibilidades del atacante. En algunos casos, es posible utilizar esta tecnica para tener un ataque determinista. Algunas bibliotecas pueden ser excluidas de esta medida de seguridad. En este caso, es posible utilizar retornos a biblioteca para lograr ejecucion de codigo arbitrario. En las versiones del kernel inferiores a 2.6.20, la biblioteca Linux-gate no era distribuida aleatoriamente y, por lo tanto, un atacante podia utilizarla para lograr su objetivo.

En los sistemas Microsoft, es usual que algunos modulos no sean incluidos en el proceso de distribucion aleatoria.

Aunque algunas implementaciones pueden hacer aleatoria la ubicacion del codigo principal del programa, esto no es usual. Para que esto sea posible, el codigo del programa debe ser compilado con posicion independiente. Esto significa que se deben recompilar las aplicaciones para soportar esta caracteristica. Una primera observacion podria indicar que siempre se pueden utilizar direcciones en el codigo del programa; sin embargo, las instrucciones utiles en dicho codigo suelen ser escasas, debido a que gran parte de la funcionalidad de las aplicaciones se encuentra almacenada en las bibliotecas [19].

Algunos espacios de memoria de la pila pueden contener direcciones de memoria que referencian la pila. En estos casos, puede utilizarse una estrategia de retornar a instrucciones "RET" multiples veces de manera que se pueda forzar el programa a saltar al codigo inyectado (utilizando las instrucciones almacenadas en la region de codigo del programa). La figura 3 muestra la pila con un ataque del tipo retorno a retorno.

La direccion de retorno almacenada en la pila se encuentra en el lugar donde aparece por primera vez 0x08049654 que es una direccion usual para la region del codigo del programa. En el cuadro de la izquierda se puede observar que la instruccion en dicha direccion es "RET". Por lo tanto, el programa comenzara a retornar hasta que EIP sea sobrescrito con 0xBFFFFA09 que es una direccion en el medio de la region con NOPS.

[FIGURA 3 OMITIR]

Algunas aplicaciones permiten al atacante asignar grandes bloques de datos en el monticulo (esto es usual en ataques al lado del cliente, donde se pueden utilizar lenguajes que utilizan compiladores que permiten este proposito); en estas situaciones se puede forzar la aplicacion a utilizar una direccion del monticulo que tenga altas posibilidades de contener los datos inyectados. Para mejorar la posibilidad de exito, se suelen asignar datos con la forma de la figura 4.

[FIGURA 4 OMITIR]

4. TRABAJOS FUTUROS

Los adelantos de los mecanismos de proteccion han demostrado ser importantes elementos para mitigar el riesgo. Existen diferentes formas de implementar estas protecciones. La forma en que se implementan los mecanismos de defensa puede disminuir la efectividad de estas tecnologias.

Existen alternativas para determinar la existencia de los mecanismos de proteccion presentados en este documento. De manera aislada se han realizado mediciones para evaluar la efectividad de algunas de estas medidas de seguridad. Sin embargo, no existe un metodo que permita evaluar o comparar diferentes implementaciones en las medidas de seguridad de manera objetiva.

Los adelantes en los mecanismos de defensas de los sistemas operativos de proposito general han creado la pregunta de si estas medidas son aplicables en el contexto de sistemas embebidos y si en dichas arquitecturas se cuenta con la seguridad adecuada para el contexto que representan.

Las medidas de proteccion afectan principalmente a las aplicaciones de usuario y esto ha generado que muchos atacantes comiencen a evaluar los fallos de seguridad del nucleo del sistema operativo. Se deberian incluir mecanismos de defensa adecuados para disminuir el riesgo que experimentan los programas en modo supervisor, ya que el interes por atacar los componentes del sistema operativo cada vez es mayor.

5. CONCLUSIONES

Los fallos por corrupcion de memoria, al igual que otro tipo de debilidades, son causados por errores humanos que pueden existir en cualquier etapa del proceso de desarrollo de los sistemas computacionales. Es importante concientizar a los ingenieros de los requerimientos no funcionales y las buenas practicas de programacion que ayudan a disminuir el riesgo de experimentar vulnerabilidades en los sistemas. La primera linea de defensa en las aplicaciones es un buen proceso de desarrollo. El analisis de requerimientos de seguridad, las buenas practicas de diseno e implementacion y un adecuado control de calidad con un conjunto de pruebas adecuado, es fundamental para reducir el riesgo de experimentar este tipo de fallos.

Aunque esta linea de proteccion deberia ser suficiente para detener los ataques, se prefieren los enfoques de proteccion en diferentes capas. Para ayudar a mitigar los riesgos, los sistemas operativos han incluido diferentes mecanismos de proteccion. Dos de los mecanismos mas representativos son: hacer aleatorio el espacio virtual de direcciones y los privilegios de ejecucion en las regiones de memoria. Sin embargo, estos mecanismos no evitan que la vulnerabilidad exista; por el contrario, hacen que el proceso de un atacante para aprovechar una vulnerabilidad sea mas complicado. Es importante mencionar que estos mecanismos de proteccion no son perfectos y que los atacantes han desarrollado tecnicas para evadir su funcionamiento. Esto no quiere decir que las medidas de proteccion no sean efectivas o que sean obsoletas; simplemente, es una manifestacion de la teoria del riesgo residual.

Recibido: 18/11/2010

Aceptado: 19/10/2011

REFERENCIAS

[1] H. Meer, "Memory Corruption Attacks The (Almost) Complete History," presentado en Black Hat USA, Las Vegas, 2010.

[2] E. Levy. <<Smashing the stack for fun and profit, PhrackInc,>> [En linea], acceso octubre 2010; Disponible: http://www.phrack.com/issues.html?issue=49&id=14, 1996.

[3] T. Twillman. "Exploitforproftpd 1.2.0pre6," [En linea], acceso octubre 2010; Disponible: http://seclists.org/ bugtraq/1999/Sep/328, 1999.

[4] M. Kaempf. "VudoMallocTricks,PhrackInc," [En linea], acceso octubre 2010; Disponible: http://www.phrack. org/issues.html?issue=57&id=8, 2001.

[5] L. Le, "Payload Already Inside: Data Reuse ForRop Exploits," presentado en Black Hat USA, Las Vegas, 2010.

[6] J. Pincus, y B. Baker, "Beyond stack smashing: recent advances in exploiting buffer overruns," IEEE Security & Privacy, vol. 2, no. 4, pp. 20-27, 2004.

[7] A. Fog. "Calling conventions for different C++ compilers and operating systems, Copenhagen University College of Engineering," [En linea], acceso septiembre 2010; Disponible: http://www.agner.org/optimize/ calling conventions.pdf, 2010.

[8] R. Gera. "Advances in format string exploitation, PhrackInc," [En linea], acceso septiembre 2010; Disponible: http://www.phrack.org/issues. html?issue=57&id=9#article, 2002.

[9] D. Lea. "The design of the basis of the glibc allocator," [En linea], acceso septiembre 2010; Disponible: http:// gee.cs.oswego.edu/dl/html/malloc.html, 1996.

[10] P. Phantasmagoria. "The Malloc Maleficarum. Glibc Malloc Exploitation Techniques, Security Focus," [En linea], acceso septiembre 2010; Disponible: http:// www.securityfocus.com/archive/1/413007/30/0/ threaded, 2005.

[11] J. Afek, y A. Sharabani, "Dangling Pointers Smashing the pointer for fun and profit," presentado en Black Hat USA, Las Vegas, 2007.

[12] M. Conover. "Double Free Vulnerabilities, Symantec," [En linea],

acceso octubre 2010; Disponible: http:// www.symantec.com/connect/blogs/double-free-vulnerabilities-part-1, 2007.

[13] H. Burch. "Vulnerability Note VU#946969, US CERT," [En linea], acceso septiembre 2010; Disponible: http://www.kb.cert.org/vuls/id/946969, 2005. [14] Shahin. "Java CMM readMabCurveData stack overflow, abysssec," [En linea], acceso agosto 2010; Disponible: http://www.exploit-db.com/exploits/15056/ 2010.

[15] S. M. Pike et al., "Checkmate: Cornering C++ Dynamic Memory Errors With Checked Pointers," presentado en 31st SIGCSE Technical Symposium on Computer Science Education: ACM Press, 2000.

[16] M. Sutton et al., Fuzzing: Brute Force Vulnerability Discovery, Indiana: Addison-Wesley Professional, 2007, p.

[17] Nergal. "The advanced return-into-lib(c) exploits, PhrackInc," [En linea], acceso septiembre 2010; Disponible: http://www.phrack.org/issues.html?issue=58&id=4, 2001.

[18] E. E. Buchanan et al., "Return-oriented Programming: Exploitation without Code Injection," presentado en Black Hat USA, Las Vegas, 2008.

[19] T. Muller, "ASLR Smack & Laugh Reference," presentado en Seminar on Advanced Exploitation Techniques, Germany, 2008.

[20] O. Whitehouse. "An Analysis of Address Space Layout Randomization on Windows Vista, SYMANTEC," [En linea], acceso octubre 2010; Disponible: http://www. symantec.com/avcenter/reference/Address Space Layout Randomization.pdf, 2007. w

David Mora Rodriguez, Mg. Seguridad de la Informacion (Universitat Oberta de Catalunya), Estudiante de Maestria en Ingenieria (Universidad de Antioquia), Direccion Calle 67 Numero 53 - 108, Telefono 2195560, dmora@udea.edu.co

Mario Munoz, M. Sc. Ingenieria Electrica (Universidade de Sao Paulo, Brasil), aspirante a doctorado (Universidade de Sao Paulo, Brasil), profesor en Ingenieria Electronica (Universidad de Antioquia), Telefono 2198565, mamunoz@udea.edu.co
COPYRIGHT 2011 Universidad de Medellin
No portion of this article can be reproduced without the express written permission from the copyright holder.
Copyright 2011 Gale, Cengage Learning. All rights reserved.

Article Details
Printer friendly Cite/link Email Feedback
Author:Mora Rodriguez, David; Munoz, Mario
Publication:Revista Ingenierias
Date:Jul 1, 2011
Words:4170
Previous Article:Herramienta de logica difusa para definir rasgos de la personalidad de un individuo.
Next Article:Dinamica de la bifurcacion de Hopf en una clase de modelos de competencia que exhiben la bifurcacion zip.
Topics:

Terms of use | Privacy policy | Copyright © 2019 Farlex, Inc. | Feedback | For webmasters