jueves, 30 de julio de 2009

Se puede crackear la password de un usuario oracle?

Cualquier usuario con privilegios para ver la vista de catálogo DBA_USERS puede obtener el hash de la password de cualquier usuario. La diferencia entre encriptar y hashear es que el hashing no tiene vuelta atrás, no tiene función inversa. El algoritmo utilizado por Oracle para hashear se conoce y el metodo para obtener la password consiste en aplicar dicho algoritmo al string compuesto por el nombre del user concatenado con la password plana. La probabilidad de que de dos string de entrada distintos se obtenga el mismo valor hash es muy muy baja pero no imposible. Dado el nombre del usuario, el valor hash y el algoritmo lo que hacen la mayoria de los crackers es hashing probando con todas las combinaciones posibles para generar el valor hash y luego comparar con el valor de hash de la columna password de la vista dba_users. Algunos programas muy optimizados generan mas de un millón de posibilidades por segundo. Una persona no muy tecnica a priori pensaría que generando 1 millon de combinaciones por segundo se podrian crackear todas las passwords. Mas abajo, usando la funcion f_get_duration
vamos a ver que tan sorprendente pueden ser los tiempos en "romper" una contraseña de n caracteres.

Googleando se pueden conseguir muchos programas que usan diccionario o fuerza bruta. Algunos usan una combinación, y primero verifican si por ejemplo la password coincide con el nombre del user, si se usó como password una palabra del diccionario español, ingles, etc, y si no tienen exito comienza a generar combinaciones y probar, en la siguiente pagina hay un listado de utilitarios para crackear: Oracle Password Cracker

Voy a mostrarles como usar uno de los programas mas rapidos que encontré en la web, es gratis y pueden bajarselo y conocer mas en: ToolCrypt.

Primero veamos las opciones que tenemos para generar las permutaciones:



C:\Dwn\orabf-v0.7.6>orabf.exe

orabf v0.7.6, (C)2005 orm@toolcrypt.org
---------------------------------------

usage: orabf [hash]:[username] [options]

options:
-c [num] complexity: a number in [1..6] or a filename
- read words from stdin
[file] read words from file
1 numbers
2 alpha
3 alphanum
4 standard oracle (alpha)(alpha,num,_,#,$)... (default)
5 entire keyspace (' '..'~')
6 custom (charset read from first line of file: charset.orabf)
-m [num] max pwd len: must be in the interval [1..14] (default: 14)
-n [num] min pwd len: must be in the interval [1..14] (default: 1)
-r resume: tries to resume a previous session

Por default se usan 39 caracteres, incluidas letras, numeros y caracteres comunes como $, #, etc. Se puede definir largo minimo y maximo de passwords, tipo de caracteres (alpanumericos, numericos y combinaciones) y se puede resumir una busqueda. Presionado cualquier tecla se muestra la cantidad de permutaciones x seg y la ultima combinación probada.

Ahora les voy a mostrar como usarlo. Primero voy a crear un usuario TEST_USR cuya
password es mi nombre: PABLO.


rop@DESA10G> drop user test_usr;

Usuario borrado.

rop@DESA10G> create user test_usr identified by pablo;

Usuario creado.

rop@DESA10G> select password from dba_users where username = 'TEST_USR';

PASSWORD
------------------------------
8ADE17EF4E4AF7F0

rop@DESA10G>

Una vez obtenido el password hasheado, probamos cto demora en encontrar la password
desde el valor hash.



C:\Dwn\orabf-v0.7.6>orabf 8ADE17EF4E4AF7F0:test_usr

orabf v0.7.6, (C)2005 orm@toolcrypt.org
---------------------------------------
Trying default passwords...done

Starting brute force session using charset:
#$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_

press 'q' to quit. any other key to see status

current password: P2THP
36569699 passwords tried. elapsed time 00:00:58. t/s:628649

password found: TEST_USR:PABLO

37017020 passwords tried. elapsed time 00:00:58. t/s:628572


Demoró tan solo 58 segundos. Utilizó fuerza bruta, ya que si bien orabf primero prueba usando diccionario, este es muy pequeño y trivial. Existen otras herramientas que usan diccionarios muy completos y para este caso, dado que usé un nombre propio, se podria haber obtenido el resultado mas rápido.
Voy a cambiar la password agregandole el signo $ al final y pruebo nuevamente:


rop@DESA10G> alter user test_usr identified by pablo$;

Usuario modificado.

rop@DESA10G> select password from dba_users where username = 'TEST_USR';

PASSWORD
------------------------------
561AB3687A5DBD44

rop@DESA10G>

C:\Dwn\orabf-v0.7.6>orabf 561AB3687A5DBD44:test_usr

orabf v0.7.6, (C)2005 orm@toolcrypt.org
---------------------------------------
Trying default passwords...done

Starting brute force session using charset:
#$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_

press 'q' to quit. any other key to see status

current password: B3YKNE
165693702 passwords tried. elapsed time 00:04:02. t/s:684420

current password: EAHT1_
451564805 passwords tried. elapsed time 00:10:42. t/s:703149

current password: IDIZEX
819470880 passwords tried. elapsed time 00:19:15. t/s:709335

current password: K9IAAT
990627331 passwords tried. elapsed time 00:23:14. t/s:710231

current password: MQW0LR
1211219907 passwords tried. elapsed time 00:28:28. t/s:708795

current password: P#SDCG
1416898294 passwords tried. elapsed time 00:33:17. t/s:709419

password found: TEST_USR:PABLO$

1443663769 passwords tried. elapsed time 00:33:54. t/s:709542


C:\Dwn\orabf-v0.7.6>

Ahora tardó 33 minutos. Mi maquina no es muy rapida y genera alrededor de 700 mil casos por segundo. Solo agregué un caracter adicional y los tiempos aumentaron considerablemente. Abajo calculé aproximadamente cto se tardaria en realizar todas las combinaciones posibles de acuerdo a la cantidad de caracteres de password a testear. Para la prueba se tomó como hipotesis que se generan 1 millón de combinaciones por segundo y se permuta entre 39 caracteres posibles:


rop@DESA10G> select rownum+4 "Caracteres",f_get_duration(power(39,rownum+4)/1000000) "YY MN DD HH MI SS"
2 from dual
3 connect by rownum <= 6;


Caracteres YYYY MN DD HH MI SS
--------------------------------------------------------------
5 0000 00 000 00 01 30
6 0000 00 000 00 58 39
7 0000 00 001 14 07 11
8 0000 02 000 22 40 09
9 0006 07 010 20 06 01
10 0257 11 015 15 54 45


6 filas seleccionadas.

rop@DESA10G>


Se puede observar, con cierta sorpresa, que por ejemplo, para obtener todas las combinaciones de 10 caracteres demoraría 257 años!. Como podemos apreciar, se podria crackear cualquier password (ya que en general no tienen mas de 10 caracteres) pero en un tiempo abismal. Podemos pensar en correr en paralelo en maquinas mas poderosas, etc, pero dudo que se pueda crackear una password de 10 caracteres en menos de 1 dia por ejemplo.
Como se suele decir, es siempre mejor prevenir que curar, por algo en 11g la vista dba_users no muestra mas la password hasheada. Sin hash no puedo comparar, asi que no hay metodo sistematico, sumado a que en 11g se pueden crear password case-sensitives lo que hace mucho mayor el universo de caracteres posibles a permutar.


rop@DESA11G> drop user test_usr;

Usuario borrado.

rop@DESA11G> create user test_usr identified by pablo;

Usuario creado.

rop@DESA11G> select password from dba_users where username = 'TEST_USR';

PASSWORD
------------------------------


rop@DESA11G>


Retorna null. La primera vez que descubrí eso pensé en los scripts que por ejemplo migran los usuarios de base de datos usando la info de la columna password para armar las ddl de la siguiente forma:


create user test_usr identified by values '8ADE17EF4E4AF7F0';

Buscando en la documentación leí que usando el paquete dbms_metadata se puede tomar el valor hasheado:


rop@DESA11G> select dbms_metadata.get_ddl('USER','TEST_USR') from dual;

DBMS_METADATA.GET_DDL('USER','TEST_USR')
--------------------------------------------------------------------------------

CREATE USER "TEST_USR" IDENTIFIED BY VALUES '8ADE17EF4E4AF7F0'
DEFAULT TABLESPACE "USERS"
TEMPORARY TABLESPACE "TEMP"


Si creo el user normalmente, sin setear el hash con values:


rop@DESA11G> drop user test_usr;

Usuario borrado.

rop@DESA11G> create user test_usr identified by pablo;

Usuario creado.

rop@DESA11G> select dbms_metadata.get_ddl('USER','TEST_USR') from dual;

DBMS_METADATA.GET_DDL('USER','TEST_USR')
--------------------------------------------------------------------------------

CREATE USER "TEST_USR" IDENTIFIED BY VALUES 'S:6E936D6C63B34E82D889412A4C30D5
9D49735F4945805E808446AFC9EA2C;8ADE17EF4E4AF7F0'
DEFAULT TABLESPACE "USERS"
TEMPORARY TABLESPACE "TEMP"
rop@DESA11G>

La password hasheada es distinta y mucho mas larga, ya que a partir de 11g cambia el algoritmo a SHA-1 ( SHA-1), además no usa solo como valor adicional el username sino que agrega otra información no documentada para generar el hash.
Si miramos la tabla interna SYS.USER$, que es base para la vista DBA_USERS pero solo accesible con sys, vemos que se sigue almacenando el antiguo hash en la columna PASSWORD y que se guarda en la columna SPARE4 el nuevo hash.


SQL> select password,spare4 from user$ where name = 'TEST_USR';
PASSWORD
------------------------------
SPARE4
--------------------------------------------------------------------------------
8ADE17EF4E4AF7F0
S:EF6450476A2C84EC1E012A0FD4D93E4B0EDF698150DE2A510FB66E4F429D

Por lo tanto vemos que se siguen guardando los hash a la antigua y de la nueva forma, pero ahora no se pueden ver desde vistas de catalogo.

Como moraleja, aunque para muchos es algo obvio, nunca creen password de menos de 8 caracteres y usen siempre combinación entre caracteres (mayúsculas o minúsculas si estan en 11g y tienen habilitado "sec_case_sensitive_logon=TRUE"), números y signos de puntuación. Lo ideal seria habilitar en la base funciones de control de complejidad de password para directamente evitar el uso de password cortas o triviales. Desde 11g se avanzó en la segurización de ambientes Oracle ya que en esa versión se introdujeron muchas caracteristicas que ayudan y promueven el uso de contraseñas mas complejas que minimizan su hackeo.

2 comentarios:

  1. Como siempre, un excelente artículo. Interesante y clarísimo.

    ResponderEliminar
  2. Me ha entantado la explicación sobre todo de los hash, que desconocía hasta ahora.

    Lvgstark

    ResponderEliminar