-------------------------------------------------------------[ Vulnerabilities from n00b to n00b ]---------------------------------------------------------
30-11-08 - servidor irc: irc.zonartm.org #rtm ------------------------------------------------------------------------------------ www.zonartm.org

23:14 <+vendetta> Vamos a hablar de las nociones basicas de algunos errores comunes de programacion
23:15 <+vendetta> mostrare algunos ejemplos, si quieren apoyarse en ellos con que tengan a la mano gcc y gdb podran hacerlo
23:15 <+vendetta> oks!
23:15 <+vendetta> Bien... primero que nada... hay que pensar en que es lo que controla a todos los dispositivos de hardware
23:15 <+vendetta> incluidos los dispotivios de red como routers, switches, etc, etc...
23:16 <+vendetta> siempre es software, y este software dado que tiene mogoyon de funcionalidades tiende a hacerse complejo
23:16 <+vendetta> las vulnerabilidades en el software llevan años de estarse encontrando y explotando
23:16 <+vendetta> unas de las mas viejitas son los Stack Buffer Overflows
23:17 <+vendetta> como es el caso de C
23:17 <+vendetta> y por que los afecta?
23:17 <+vendetta> ah! pues bien... para entender esto hay que entender algunos conceptos
23:17 <+vendetta> Primero, como funciona la memoria de un proceso...
23:18 <+vendetta> cuando un usuario ejecuta un proceso, este proceso recibe por parte del S.O. un pedazo de memoria
23:18 <+vendetta> esta memoria se divide en varias secciones, cada una de las cuales tiene ciertas caracteristicas y cumple con
------------------------- un proposito
23:19 <+vendetta> algunas de las secciones son: .text, lugar donde se encuntran las instrucciones del programa que estamos
------------------------- ejecutando; .data, lugar donde se encuentran variables inicializadas como por ejemplo int a=1; .bss, donde se
- ----------------------- encuentran variables no incializadas como int a;; una secciones de memoria para las variables de entorno...
23:20 <+vendetta> y dos secciones mas que son muy importantes...
23:20 <+vendetta> i) la PIla
23:20 <+vendetta> ii) el Heap
23:20 <+vendetta> primero tratare la pila
23:20 <+vendetta> las pilas son estructuras de datos muy usadas dentro del computo, debido a que reflejan la forma mas
------------------------- sencilla de realizar varias tareas
23:21 <+vendetta> imagen la pila como los recipientes en donde los choferes de microbus guardan el dinero
23:21 <+vendetta> es decir, si alguien le paga al tipo este mete la moneda, y si este necesita dar vuelto sacara la ultima
------------------------- moneda que introdujo
23:21 <+vendetta> para que sirve esta forma de funcionar?
23:22 <+vendetta> la pila gracias a esta estrucutra que tiene puede ser utilizada para manejar las funciones de los programas
23:22 <+vendetta> que es una funcion?
23:22 <+vendetta> una funcion, es un pedazo de código que realiza una serie de pasos y que podemos llamar en cualquier
------------------------- momento dentro de nuestro programa, evitando repetir constantemente codigo
23:23 <+vendetta> lo mismo sucede con los metodos en el caso de programas orientados a objetos en donde se usan clases
23:23 <+vendetta> ahora bien, la forma en que se comporta la memoria depende mucho del tipo de hardware que estemos usando..
23:23 <+vendetta> existen dos "filosofias" de manejo de memoria
23:24 <+vendetta> una de ellas es la big-endian
23:24 <+vendetta> este tipo mueve su memoria desde direcciones bajas de memoria hacia direcciones altas de memoria
23:25 <+vendetta> un ejemplo de este tipo de microprocesadores eran los PowerPC de las Mac viejitas
23:25 <+vendetta> el otro es litle-endian que es el que analizaremos mas dado que los micros Intel y compatibles lo usan
23:26 <+vendetta> este mueve su memoria desde direcciones altas hacia direcciones bajas, es decir al revez
23:27 <+vendetta> entonces, en el caso de una pila que este funcionando sobre una arquitectura de este tipo, la memoria se estaria
------------------------- moviendo desde direcciones de memoria altas hacia las bajas, mientras el heap (que trataremos mas adeltante)
------------------------- lo hace de direcciones de memoria bajas hacia altas
23:27 <+vendetta> ahora, como es que las funciones ocupan la pila para funcionar?
23:27 <+vendetta> pues bien, cuando se ejecuta una funcion lo que se hace es colocar en orden inverso los parametros que va a
------------------------- utilizar la funcion sobre la pila
23:27 <+vendetta> y despues se llama a la funcion a ejecutar, de esta forma cuando la funcion se ejecute podra ir sacando
------------------------- parametro por parametro a esto se le llama hace un pop()... y al hecho de meter datos hacer un push()
23:28 <+vendetta> por ejemplo...
23:28 <+vendetta> si tenemos en C algo como:
23:28 <+vendetta> int truculent_function(int param1, int param2, int param3){
23:28 <+vendetta> /algo...
23:28 <+vendetta> }
23:29 <+vendetta> al momento de llamarse se veria algo como:
23:29 <+vendetta> push $param3
23:29 <+vendetta> push $param2
23:29 <+vendetta> push $param1
23:29 <+vendetta> call funcion
23:30 <+vendetta> esto hace que el manejo de funciones visto desde un bajo nivel sea muy sencillo
23:30 <+vendetta> sin embargo da un problema, si se dan cuenta no hay mucho control en cuantos parametros se pasan y cosas
------------------------- de ese estilo esto se manejo directamente por el software
23:30 <+vendetta> e aqui el inicio de los problemas...
23:31 <+vendetta> ahora, cuando se ejecuta una funcion siempre hay algunas cosas que estan presentes, el procedimiento prolog
------------------------- y el procedimiento epilog es decir, cuando ustedes ejecutan una funcion primero hay que generar dentro de la
------------------------- pila que tenemos un nuevo marco de pila, en donde se manejara de forma local la informacion de la funcion actual
23:32 <+vendetta> para ello se utilizan registros especiales, ebp y esp
23:32 <+vendetta> el primero guarda la base del marco de pila, mientras el segundo guarda el tope de la pila
23:33 <+vendetta> entonces.. cuando se llama una funcion el procedimiento prolog haria algo como esto para generar un nuevo
------------------------- marco de pila. push %ebp
23:33 <+vendetta> push %esp, %ebp
23:33 <+vendetta> y despues apartaria la cantindad de memoria que vayamos a necesitar
23:34 <+vendetta> si ven, lo unico que se hace es que el puntero que apunta al marco anterior de la pila apunte a lo que sera el
------------------------- nuevo marco (parentesis)
23:34 <+vendetta> aca me hacen una correccion... me equivoque :P
23:35 <+vendetta> la instruccion no es push es mov
23:35 <+vendetta> thnx rclxor
23:35 <+vendetta> ok!... sigamos
23:35 <+vendetta> cuando se sale de la funcion se lleva a cabo otro procedimiento
23:35 <+vendetta> el procedimiento epilog que tiene por objeto eliminar el marco de pila que ya no se usara y regresar al punto
------------------------- en donde la funcion fue llamada, para ello se utilizan las instrucciones leave y ret
23:36 <+vendetta> si quieren ver esto a detalle pueden programar una pequeña funcion que no haga nada en C
------------------------- y despues utilizar gdb para desensamblar el codigo y se podran dar cuenta de como funciona
23:37 <+vendetta> ok!... ahora, como dije antes el problema de toda sencilles radica en que no hay controles muy fuertes en ello
23:37 <+vendetta> es decir nunca hay forma de saber si se leyo algun dato de la pila mal, si se sobreescribio algo, etc...
23:37 <+vendetta> esto se debe de validar desde el codigo, sin embargo no siempre se hace
23:38 <+vendetta> en lenguajes como C, en donde se tiene un fuerte control sobre la memoria se llega a tener problemas de
------------------------- este tipo... algunas funciones vulnerables son por ejemplo:
23:38 <+vendetta> strcpy() <- clasico cuando se habla de los Stack buffer overflows
23:38 <+vendetta> strcat()
23:38 <+vendetta> gets()
23:38 <+vendetta> scanf()
23:38 <+vendetta> etc...
23:38 <+vendetta> por que estas funciones?
23:39 <+vendetta> por que no tienen mecanismos de control
23:39 <+vendetta> por ejemplo, en el caso de strcpy()
23:39 <+vendetta> si el programador no valida las cadenas origen y destino puede cometer el error de querer copiar algo muy
------------------------- grande en un lugar menor en donde no habia cabida
23:40 <+vendetta> para que lo entiendan mejor les mostrare un ejemplo que pueden descargar de:
23:40 <+vendetta> http://belindofan.com.ar/?module=files&action=download&path=%2Ffiles%2FCode%2Fmeet.c
23:41 <+vendetta> bueno, lo que se tiene en este codigo es un programa sumanete sencillo en donde se leen argumentos
------------------------- desde la linea de comandos y estos argumentos nunca son validados
23:42 <+vendetta> Ojo!... no esperen encontrar en la vida real programas tan vulnerables, en la vida real estos errores se
------------------------- presentan en formas mas complejas, pero el concepto es el mismo y es el que se quiere explicar
23:42 <+vendetta> ahora.. miren en la linea:
23:42 <+vendetta> Ichar name[400];
23:42 <+vendetta> aqui se esta reservevando una cantidad finita de memoria
23:42 <+vendetta> Istrcpy(name, temp2);
23:43 <+vendetta> y en esta linea esa cantidad finita de memoria se ve comprometida, pues no existe un mecanismo que evite
------------------------- que alguien pueda pasar una cadena mas larga
23:43 <+vendetta> ahora, si compilan este codigo podremos ver mas de como funciona este sencillo error...
23:43 * vendetta esperando a que compilen...
23:44 <+vendetta> El funcionamiento del programa es muy sencillo... escriben algo como ./programa Pepe Pecas
23:44 <+vendetta> y les envia un saludo y una despedida a Pepe Pecas
23:44 <+vendetta> La cadena Pecas es menor a 400 caracteres por lo que no tenemos ningun problema,, pero que pasaria
------------------------- si nosotros escribimos una cadena superior a esto
23:45 * vendetta esperando a que escriban ./programa Pepe pecass........sssss....ssss...
23:45 <+vendetta> bueno, si utilizando algo como ./programa pepe `perl -e 'print "A"x400'`
23:45 <&ANNA> Segmentation fault :(
23:46 <+vendetta> ANNA: exacto nena.. tu siempre tan inteligente *muack!*
23:46 <+vendetta> esto por que es... bueno,, quienes tengan a la mano gdb ejecutenlo
23:46 <+vendetta> gdb ./programa
23:46 <+vendetta> en gdb escriban run pepe `perl -e 'print "A"x400'`
23:47 <+vendetta> enviara un error... este error es causado por que el programa detecta un fallo en un registro
23:47 <+vendetta> el registro es eip... este registro se encarga de tener guardada la direccion de la siguiente instruccion a ejecutar
23:47 <&ANNA> (gdb) run pepe `perl -e 'print "A"x400'`
23:47 <+vendetta> aqui viene el famosos 0x414141 que veran en muchos lugares
23:48 <&ANNA> Program received signal SIGSEGV, Segmentation fault.
23:48 <+vendetta> 0x41 es la representacion hexadecimal de la letra A
23:48 <+vendetta> y lo que esta sucediento aqui es que el programa desparramo (como la cerveza cuando las mujeres la sirven)
------------------------- los datos y estos se salieron de su marco de pila
23:48 <+vendetta> sobreescribiendo el registro EIP
23:49 <+vendetta> ahora el registro EIP tiene una direccion posiblemente 0xAABB4141 o algo asi...
23:49 <+vendetta> ahora, los compiladores hacen cosas raras para evitar este tipo de errores...
23:50 <+vendetta> la primera cosa que hara es mandarles un warning
23:50 <+vendetta> pero tambien da mas holgura para menejar estos errores.. he alli la razon que a algunos no les aparesca
------------------------- el famosos 0x41414141 que es el que buscamos, es decir la direccion del EIP totalmente sobreescrita
23:50 <+vendetta> para ello bastante con ir aumentando poco a poco el numero de letras A que hemos intruducido al programa
23:51 <+vendetta> desde gdb: run pepe `perl -e 'print "A"x401...2....3.....'`, etc...
23:51 <+vendetta> para poder visualizar cuando ya hemos sobreescrito el registro usaremos:
23:51 <+vendetta> info reg eip
23:52 <+vendetta> esta instruccion nos mostrara la direccion que almacena el registro eip
23:52 <+vendetta> ahora, cual es la trasendencia de esto
23:52 <+vendetta> en la vida real no estaremos escribiendo letras A... en la vida real intentaremos sobreescribir con direcciones
------------------------- validas el registro EIP para que una vez que una direccion valida sea colocada en el, el programa continue su
------------------------- flujo a la direccion que nosotros hayamos decidido
23:53 * vendetta pregunta: ¿alguien tiene alguna duda en esta parte?
23:53 <+vendetta> comentarios?
23:56 <+vendetta> Bueno... los BOF's como mencione al principio son errores muy viejos
23:57 <+vendetta> al rededor de 25 años llevan entre nosotros, pero siguen apareciendo, cada vez en menor medida, pero alli estan
23:57 <+vendetta> se hicieron populares por un paper publicado en Prack
23:57 <+vendetta> sin embargo... hay otros errores que llevan al mismo lugar
23:57 <+vendetta> unos de ellos son los format string bugs
23:58 <+vendetta> estos errores estan presentes en las cadenas de formato, como prinft(), vprintf(), etc, etc...
23:58 <+vendetta> por que??
23:58 <+vendetta> bueno,, si han programado algo en C sabran que estas se usan de la sig forma:
23:58 <+vendetta> printf("Hola");
23:58 <+vendetta> printf("%d", 8);
23:58 <+vendetta> etc.
23:59 <+vendetta> es decir, hay una forma en la que ustedes le dicen directamente a la funcion que quieren poner en pantalla
------------------------- y otra en la que mediante testigos esperan a que estos se sustituya
23:59 <+vendetta> el problema de estas funciones es que no saben si tiene el numero correcto de parametros
23:59 <+vendetta> por ejemplo, podeos tener un printf("%d");
00:00 <+vendetta> si compilamos eso nos puede lanzar o no un warning, sin embargo compilara... pero cuando llegue el
------------------------- programa a esa parte a pesar de que no tiene el parametro a ser sustituido la funcion lo intentara leer
00:00 <+vendetta> y al intentar leerlo leera algun dato que este contenido en la pila
00:01 <+vendetta> ademas, si no se valida la entrada de datos tambien es posible pasarle a un programa testigos
00:02 <+vendetta> si tienes un programa vulnerable que imprima la cadena que recoge directamente de la linea de comandos,
------------------------- se podrian insertar testigos %08x para leer las direcciones de memoria de la pila
00:02 <+vendetta> esto nos ayudaria a diseñar de cierta forma nuestra pila sin debugguear o desensamblar y ver mas o
------------------------- menos a que distancia debemos de sobreescribir datos
00:02 <+vendetta> Sin embargo la sencillez de este error hace que tienda a ser detectado muy facil
00:03 <+vendetta> y las correcciones son igual de sencillas
00:03 <+vendetta> los format string bugs tambien son viejitos...
00:03 <+vendetta> ahora veremos un error que sigue siendo viejito pero actualmente es de los que provocan mas fallos
00:03 <+vendetta> los Heap Overflows
00:04 <+vendetta> si recuerdan al principio mencione que la otra seccion muy importante de memoria era el heap
00:04 <+vendetta> el heap se utiliza la memoria dinamica, por ejemplo cuando se hace uso de funciones como malloc,
------------------------- calloc, etc... se esta pidiendo memoria del heap
00:04 <+vendetta> la estructura del heap se basa en segmentos de memoria
00:05 <+vendetta> hagan de cuenta una barrita en donde pueden tener dos pedacitos de memoria contigua ocupada, pero no
------------------------- dos pedacitos vacios contiguos
00:05 <+vendetta> pueden ir intercalados ocupados y vacios y la seccion libre se llama wilderness
00:06 <+vendetta> la idea basica del HOF es que, al igual que la pila, no hay mecanismo que evite que uno puede sobreescribir
------------------------- un fragment por ejemplo...
00:06 <+vendetta> en este codigo -> http://belindofan.com.ar/?module=files&action=download&path=%2Ffiles%2FCode%2Fheap1.c
00:06 * vendetta esperando a que descarguen...
00:07 <+vendetta> en este codigo se tiene un ejemplo sencillo de HOF
00:07 <+vendetta> mediante la funcion malloc se asignan dos buffers de memoria iguales
00:07 <+vendetta> a uno de los buffer se llena de A
00:07 <+vendetta> Istrcat(buf2, "AAAAAAAAAA");
00:08 <+vendetta> se calculo el offset para poder sobreescribir el buffer contiguo
00:08 <+vendetta> Imemset(buf1, 'B', (u_int)(diff+OVERSIZE));
00:08 <+vendetta> y a partir del buffer 1 se llega a escribir en el buffer 2
00:09 <+vendetta> si compilan este programa y lo corren se daran cuenta que antes de que se lleve acabo la sobreescritura
------------------------- se tienen AAAAAAAAAA y al termino tienen BBBBBAAAAA
00:09 <+vendetta> esto quiere decir que han sido capaces de sobreescribir memoria y no hubo mecanismo alguno para que se evitara
00:09 <+vendetta> en los tres tipos de error tratados se ha hablado de sobreescribir memoria
00:10 <+vendetta> sin embargo sobreescribir direcciones con letras A no sirve de nada
00:10 <+vendetta> mas que para que el programa se pasme
00:10 <+vendetta> para ello debemos de hacer que el programa apunte a otra cosa y esa otra cosa se ejecute en lugar del flujo
------------------------- normal del programa alli es donde entra algo llamado payload, que muchas veces es conocido como shellcode,
------------------------- aunque no es lo mismo ya que puede haber otros tipos de payloads mas avanzados
00:11 <+vendetta> pero aca como estamos de n00b a n00b solo veremos los shellcodes
00:12 <+vendetta> los shellcodes son programas en si, pero a diferencia de los programas que tiene diferentes secciones de
------------------------- memoria, los shellcodes estan autontenidos en una sola seccion
00:12 <+vendetta> por que?... por que el shellcode va a ser forzado a insertarse en el flujo del programa para realizar cierta
------------------------- accion, la que quereamos algunas personas desmeritan los shellcodes, pues creen que todo esta en
------------------------- generar el error, sobreescribir y una vez hecho esto que algo se ejecute.. que?.. pues lo que sea, una
------------------------- Shell, una conexion, etc... sin embargo los shellcodes al ser programas no estan tan limitados, si no que
------------------------- pueden hacer lo mismo que cualquier programa lo que puede hacer que tengamos shellcodes realmente
------------------------- muy complejas que realicen muchas acciones pero bien... regresando al tema
00:14 <+vendetta> los shellcodes nosotros los encontramos como representaciones hexadecimales de codigo binario
00:14 <+vendetta> los shellcodes pueden escribirse de tres formas principales
00:14 <+vendetta> 1) en C, y una vez echo en C desensamblando el programa y reduciendolo a sus partes sencillas
00:14 <+vendetta> 2) en ensamblador que es la forma mas comun
00:15 <+vendetta> 3) directamente escribiendo los opcodes (solo gurus como zodman)
00:15 <+vendetta> por ejemplo, aca tengo un ejemplo:
0:15 <+vendetta> http://belindofan.com.ar/?module=files&action=download&path=%2Ffiles%2FCode%2F1st_shellcode.c
00:15 <+vendetta> este es un shellcode que ejecuta /bin/sh
00:16 <+vendetta> este fue hecho en ensamblador, en donde solo se guardo la direccion de una cadena, y se ejecuto execve
------------------------- para ejecutar la shell esto tiene que ver con syscalls y otras cosas que salen del tema, pero que en el foro se
------------------------- pueden tratar si alguien asi lo desea... por alli nitr0us y crypkey tienen papers sobre syscalls que han escrito
00:17 <+vendetta> si ustedes compilan el programa y lo ejecutan veran como cambia su shell de bash (supongo que tienen bash)
------------------------- al de sh ahora, lo que se tiene que hacer es alojar este shellcode en algun lugar de memoria y la direccion en
------------------------- donde este usarla para sobreescribir algun error que hayamos encontrado
00:18 <+vendetta> mirphak me pasa un link de otro ejemplo de shellcode: http://vlan7.blogspot.com/2008/11/dsfjkl.html
00:18 <+vendetta> para que puedan ver mas
00:18 -!- surf3r [~nahual@24655D2C.8D4B5C36.8A606D7A.IP] has joined #rtm
00:19 <+vendetta> ok!... el shellcode puede ser alocado en diferentes partes
00:19 -!- surf3r [~nahual@24655D2C.8D4B5C36.8A606D7A.IP] has quit [RTM Network IRC Leaving]
00:19 <+vendetta> tradicionalmente en caso de buffers de memoeria grandes, se puede colocar dentro del mismo programa,
------------------------- acompan~ado de algo denominado NOP-Sled que incluye instrucciones que no hacen nada pero ocupan
------------------------- espacio y direcciones de memoria repetidas del shellcode
00:20 <+vendetta> tambien se puede colocar en variables de entorno o archivos temporales, etc...
00:20 -!- surf3r2 [~surf3r@24655D2C.8D4B5C36.8A606D7A.IP] has joined #rtm
00:20 <+vendetta> dado que quedan 2min :P....
00:20 <+vendetta> hay solucion a estos errores?
00:20 <+vendetta> sip!
00:20 <+vendetta> de hecho janux me comento uno
00:20 <+vendetta> en su microprocesador no funciono, por que?
00:21 <+vendetta> por que esta usando un microprocesador que regresa los datos a registros distintos que no pueden
------------------------- ser sobreescritos existen otras formas
00:21 <+vendetta> una de ellas es implementada por Apple en OS X
00:21 <+vendetta> la llamada pila no ejecutable
00:22 <+vendetta> en este tipo de pilas ustedes podrian desbordar un buffer, pero no podrian colocar su shellcode alli, les
------------------------- generaria un error hay parches para el kernel como es el caso de GRSecurity
00:22 <+vendetta> ramdomizadores de memoria como PaX que evitan la entrega de memoria contigua de pueda ser manipulada
00:22 <+vendetta> fstack se pueden usar como opcion en gcc... aunque no todos los programas son compatibles
00:23 <+vendetta> sin embargo, la mejor solucion viene desde la parte del programador quien debe de tomar las medidas
------------------------- necesarias de validacion, realizar algunas pruebas como puede ser el fuzzeo que consiste en la entrada de
------------------------- datos pseudoaletorios con el fin de hayar errores, etc...
00:24 <+vendetta> tambien existen algunas bibliotecas que han reescrito funciones vulnerables, como libsafe que incluye una
------------------------- version de strcpy() que si valida el tamaño destino con respecto al origen, etc...
nomac:---------------- Si quieren saber poco m?s sobre eso y como evitar, prevenir ese tipo de ataques, no se olviden de
------------------------- organizaciones como OWASP http://www.owasp.org/index.php/Buffer_overflow y en NIST ahi encontraran
------------------------- mas info, asi como escaners que buscan ese tipo de vulnerabilidades en el source code.

Road Technology Minds - Security Group 2008