Miguel Tarascó Andrés Tarascó
• Rootkits – Que son y su funcionamiento
• Implementaciones de Rootkits – Que hacen – Como lo hacen – Ejemplos prácticos
• Soluciones Genéricas – Rootkits incompletas (duplicidad de información) – Análisis de las estructuras del kernel
• Nuevos enfoques – Deficiencias en los modelos actuales – Atajando el problema de raiz
• ¿ Que son ? – Backdoors de nueva generación – Origenes – Primeras Rootkits – Que entendemos realmente por Rootkit • Ocultación • Acceso anónimo ilimitado
• ¿ Que hacen ? – Ocultación • Procesos • Ficheros y espacio en disco • Conexiones • Claves de registro
– Garantiza su ejecución – Ofrece acceso remoto
• ¿ Como lo hacen ? – Hooks • ¿ Que es un hook ? • Tipos de hooks – System Hooks – IAT Patching » Que es una API – API Patching
– DLL Inyection – Code Inyection
HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId ); BOOL UnhookWindowsHookEx( HHOOK hhk );
– Formas de realizarlo • Con la tradicional DLL • Exportando las funciones en el ejecutable __declspec(dllexport) DWORD WINAPI MyTTYPrint(int ttyDST, char *buffer, int size) { .. } HINSTANCE hExe = GetModuleHandle(NULL); TTYPrint= (TTYPRINT)GetProcAddress((HINSTANCE)hExe,"MyTTYPrint"); if (TTYPrint==NULL) { printf("[-] Critical Error. Unable To Load TTYPrint()\n"); exit(-1); }
– Que es la IAT – Como se localiza • Encabezados de un ejecutable • Como llegar a la IAT • Analizar la IAT typedef PVOID (WINAPI *IMAGEDIRECOTRYENTRYTODATA)( LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size ); pImportDesc =(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData( hInstance,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
if ((hFichero= CreateFile(VProcesos->Selected->SubItems->Strings[0].c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) != INVALID_HANDLE_VALUE) { if ((hMapping = CreateFileMapping(hFichero, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0))) { if ((pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0))) { (IMAGE_DOS_HEADER*) CabeceraDos = (IMAGE_DOS_HEADER*) pBase; if (CabeceraDos->e_magic == IMAGE_DOS_SIGNATURE) { // Encontrado el MZ (_HEADER*) CabeceraPE = (_HEADER *)((char *)CabeceraDos + CabeceraDos->e_lfanew); if (CabeceraPE->signature == IMAGE_NT_SIGNATURE) { // Encontrado PE00 ImageBase=CabeceraPE->opt_head.ImageBase; return(ImageBase );
if (ReadProcessMemory(pHandle,(void*) ImageBase,(void*) &le,sizeof(WORD),&leido)!=0) { if (le==IMAGE_DOS_SIGNATURE) { // Encontrado MZ Donde=ImageBase+0x3c; // e_lfanew if (ReadProcessMemory(pHandle,(void*) Donde,(void*) &le,sizeof(WORD),&leido)!=0) { PEOffset=ImageBase+le; if (ReadProcessMemory(pHandle,(void*) PEOffset,(void*) &le,sizeof(WORD),&leido)!=0) { if (le==IMAGE_NT_SIGNATURE) { // Encontrado PE00 Donde=PEOffset+0x80; if (ReadProcessMemory(pHandle,(void*) Donde,(void*) &lee,sizeof(DWORD),&leido)!=0) { IATOffset=ImageBase+lee;
typedef struct _IMAGE_THUNK_DATA { union { PBYTE ForwarderString; PDWORD Function; DWORD Ordinal; PIMAGE_IMPORT_BY_NAME AddressOfData; } ; }
typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; PIMAGE_THUNK_DATA OriginalFirstThunk; } ; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; PIMAGE_THUNK_DATA FirstThunk; }
Diferencias con IAT Patching • Ventajas • Inconvenientes while (pImportDesc->Name) { import_entry = (IMAGE_THUNK_DATA*) (pImportDesc->FirstThunk + (DWORD)hInstance); while (import_entry->u1.Function) { // Recorro la lista de funciones importadas DWORD direccion = ((DWORD)mapped_entry->u1.Function ); if (direccion==DireccionACambiar) { // direccion de la funcion a modificar . . } import_entry++; BOOL VirtualProtect( } LPVOID lpAddress, pImportDesc++; DWORD dwSize, }
DWORD flNewProtect, PDWORD lpflOldProtect );
– En que consisten – Diferencias – Ventajas – Inconvenientes proceso = OpenProcess(PROCESS_ALL_ACCESS, FALSE,PID ); ruta=VirtualAllocEx(proceso, NULL,sizeof("c:\\midll.DLL"), MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(proceso,ruta,"c:\\midll.DLL",sizeof("c:\\midll.DLL"),escritos); Thread = CreateRemoteThread(proceso, NULL, 0,(DWORD (__stdcall *)( void *)) GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "LoadLibraryA"), ruta, 0, ThreadId);
BOOL WINAPI DllMain(HMODULE hMod, DWORD reason, LPVOID lpvReserved) { switch( reason ) { case DLL_PROCESS_ATTACH: MessageBox(0, "Hola, soy la DLL ejecutando un MessageBox", "Información", 0); break; } }
– Porque se pueden aplicar soluciones genéricas • Fallos en la programación • Ocultación Incompleta (duplicidad)
– Enfoques actuales • • • • • •
Partir de un estado “seguro” Análisis de la IAT (RKDetector - vice) Estructuras del kernel (Klister) Instrucciones de CPU (PatchFinder2) Análisis de resultados (RKDetector) Bugs (RKDetector)
– Fallos de programación • Ventajas (pueden ser comunes) • Inconvenientes (específico de la aplicación)
– Ejemplos - Ocultación Incorrecta: Fallo en el Hook: Ntdll.NtOpenProcess int i=GetCurrentProcessId()+1; if ((rkHandle =OpenProcess( PROCESS_ALL_ACCESS, TRUE,i))==NULL){ // Rootkit... }
– Atacando la ocultación Incompleta de la rootkit • Ocultación incompleta de HANDLES SnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); ProcessList.dwSize=sizeof(PROCESSENTRY32); while(1) { if(Process32Next(SnapShot, &ProcessList) != FALSE) { ... } } for (int pid=0;pid<65535;pid+4 ) { if ( (handle=OpenProcess(pid))!=NULL) && NotListed(pid) ) printf(“Rootkit Process Found with Pid %i\n,pid); }
• Atacando servicios – Consultar HKLM\SYSTEM\CurrentControlSet – Utilizar WMI (RKDetect) – Conectar por registro remoto y enumerar las claves
– Módulos cargados • Análisis de la IAT (DLL Inyection) • Módulos de programas externos (Eternity) • Monitorizar la propia aplicación (trusted dlls) MODULO C:\WINDOWS\system32\ADVAPI32.dll cargado MODULO C:\WINDOWS\system32\RPCRT4.dll cargado MODULO C:\WINDOWS\System32\CRTDLL.DLL cargado MODULO C:\WINDOWS\System32\PSAPI.DLL cargado
• Tráfico de red – Port scanning Vs pAllocateAndGetTcpExTableFromStack() – Respuesta ante determinados paquetes (hxdef) unsigned char masterkey082[] = { //masterkey for hxdef 080 and 081 0x01, 0x1e, 0x3c, 0x6c, 0x6a, 0xff, 0x99, 0xa8, 0x34, 0x83, 0x38, 0x24, 0xa1, 0xa4, 0xf2, 0x11, 0x5a, 0xd3, 0x18, 0x8d, 0xbc, 0xc4, 0x3e, 0x40, 0x07, 0xa4, 0x28, 0xd4, 0x18, 0x48, 0xfe, 0x00 };
– Espacio libre en disco • Primer Enfoque: Duplicidad de información GetDiskFreeSpace (unidad,&a,&b,&c,&d); GetVolumeInformation(unidad,volume,MAX_PATH - 1,&dwSerialNumber, &dwMaxNameLength,&dwFileSystemFlags,tipo,MAX_PATH -1);
• Segundo enfoque: Dependiente del FileSystem unsigned long* FAT; //Estructura de la FAT void read_fat(HANDLE hDevice) { WORD bytesread; unsigned long *p; unsigned int leidos; FAT = (unsigned long*) malloc(boot.BPB_FATSz32*boot.BPB_BytsPerSec); SetFilePointer(hDevice, boot.BPB_BytsPerSec * boot.BPB_ResvdSecCnt, NULL, FILE_BEGIN); for(leidos=0;leidos < (boot.BPB_FATSz32); leidos++) { p=((char*)FAT)+(leidos*boot.BPB_BytsPerSec); if (ReadFile (hDevice, p , boot.BPB_BytsPerSec, &bytesread, NULL)==0) { Fatal( "FATAL: Error reading FAT", "Error", GetLastError()); exit(1); } else { if (bytesread!=boot.BPB_BytsPerSec) { Fatal( "FATAL: Error reading FAT", "Error", GetLastError()); exit(1); } } }
– Deficiencias en los modelos actuales • AV, IDS, integridad, firewalls
– Volvamos a lo básico en una Rootkit • Ocultación – Procesos – Conexiones – Ficheros
– ¿ Porque esto no es fiable ? • Procesos: Driver • Conexiones: Tráfico confiable • Ficheros: Windows me engaña
– ¿ Como se soluciona esto ? • Análisis forense
– Ignoremos las API del sistema – Reprogramemos nuestras funciones • Información fiable
– Centrémonos en el almacenamiento • Acceso a la información
– Acceso a bajo nivel: Almacenamiento • Driver del sistema de archivos
– Acceso a la Información
– Que podemos obtener • Lectura fiable del árbol de directorios – Detección de ficheros ocultos – Escáner de ADS – Acceso total: No afectan las ACLs
• Lectura fiable del registro de Windows – Servicios – Ejecución automática
• Enumeración de usuarios (SAM) • Recuperación de datos • Eliminación de rootkits – Borrado seguro
¿ Preguntas ?