Ataque a la base de datos del controlador de dominio (NTDS.DIT)

[post-views]
mayo 10, 2016 · 7 min de lectura
Ataque a la base de datos del controlador de dominio (NTDS.DIT)

Entonces, como he prometido, comenzamos el proceso de analizar las etapas separadas del Cyber Kill Chain del ataque descrito anteriormente. Hoy revisaremos uno de los vectores de ataque en la infraestructura de la Empresa, que podemos contar como dos etapas: «Acciones sobre los Objetivos» y «Reconocimiento». Nuestros objetivos son:

  • Lograr un punto de apoyo utilizando las cuentas obtenidas;
  • Obtener la máxima información sobre la Empresa (correo electrónico, nombres de departamentos, números de teléfono, títulos funcionales, etc.) para ataques posteriores o incluso vender acceso a su infraestructura.

SYSTEM y NTDS.DIT

Los adversarios, una vez que están en la red corporativa, intentarán acceder a uno de los pedazos más «apetitosos» de la información de ActiveDirectory, que son los archivos SYSTEM y NTDS.DIT. Estos archivos son bases de datos que contienen todos los datos de ActiveDirectory. NTDS.DIT contiene información sobre todos los usuarios en el dominio, incluyendo los hashes de contraseñas. El archivo SYSTEM es necesario para desencriptar los datos de NTDS.DIT.

No describiré los métodos de obtención de hashes en este artículo, porque ya se han escrito muchos artículos sobre ese tema. Me centraré en el método que muestra la vulnerabilidad de la infraestructura por la exposición de contraseñas (si los hashes LM están disponibles), y la automatización del proceso de búsqueda que lo hace extremadamente rápido.

Así que solo necesitamos hashes LM y NTLM:ntds_dit_2Después de recibir los hashes comenzamos con el hash LM.

Sobre el LM-hash

Alguna información sobre el hash LM.

Está basado en el DES cifrado por bloques y puede ser atacado fácilmente para el crackeo de contraseñas debido a dos vulnerabilidades en su realización. Primero, las contraseñas que tienen más de 7 caracteres se dividen en dos partes y cada parte se cifra por separado, permitiendo atacar cada parte por separado. Segundo, todos los caracteres en minúsculas se convierten en mayúsculas.

Por lo tanto, tenemos:

El hash LM, que, como hemos descubierto antes, tiene dos partes.9196B21FEF3C8906AAD3B435B51404EE

AAD3B435B51404EE– este hash es de una contraseña vacía (tal secuencia de números significa que una mitad del hash es una contraseña vacía).

Concluimos que la contraseña consiste en menos de siete caracteres, porque la segunda parte del hash coincide con el conjunto de caracteres vacío.

Ahora para atacar la primera parte

Para ese propósito usamos hashcat, que permite fuerza bruta en paralelo con GPU. Usando las siguientes claves:

-a => modo de ataque

-m => tipo de hash

?d = todos los números (0–9).

?l = caracteres en minúscula (a–z).

?u = caracteres en mayúscula (A–Z).

?s = símbolos.

ntds_dit_3Recibimos la contraseña en 24 segundos.ntds_dit_4Ahora es el turno de NTLM1BC10704ED604747D7D827FC7A43D555Es mucho más fácil forzarlo, porque sabemos la siguiente información:

  1. Qué caracteres se utilizan en la contraseña;
  2. Orden de estos caracteres.

Solo tenemos que verificar si un carácter está en mayúscula o minúscula.ntds_dit_5

ntds_dit_6Así que, porque tenemos un hash LM todo el trabajo nos tomó poco más de 32 segundos.

Complicaremos aún más la tarea:

Supongamos que tenemos una contraseña de 14 caracteres con el tercer nivel de dificultad (contraseña corporativa clásica):29355BC0D45C341B51ACD8D3923F7C21Usamos el mismo truco:ntds_dit_7La fuerza bruta nos dio la primera aproximación (contraseña en caracteres en mayúscula) en 31 segundos.29355BC0D45C341B51ACD8D3923F7C21

ntds_dit_8Ahora todo lo que tenemos que hacer es

NTLM:E06E777CD11F495E9B9098B5576A4343

ntds_dit_9

Aumentar la complejidad de la contraseña incluso hasta 14 caracteres no dificulta nuestra tarea – ¡si tenemos el hash LM, el crackeo solo toma 40 segundos!Procesamos un hash. Si necesitábamos procesar una gran cantidad de hashes, construir máscaras para cada contraseña sería demasiado laborioso. Es por eso que desarrollé una herramienta que haría el siguiente trabajo por nosotros – ntlm_mask_gen.exe (puedes descargarlo aquí tut, MD5: c2a9dac79c51e14c84f35febd72d05ba o tomar el código python en Anexo 1) :

  1. Forma listas de palabras para cada contraseña;
  2. Forma máscara para cada contraseña incluyendo las listas de palabras formadas;
  3. Forma un único archivo con cadenas para cada hash separado, máscara y lista de palabras.

Todo lo que tienes que hacer entonces es ejecutar este archivo y ver hashcat las contraseñas descifradas en segundos.

Demostración de la metodología descrita

Llevemos a cabo un experimento más para demostrar la técnica descrita:

Usaremos 10 contraseñas con 10 caracteres, cuarto nivel de dificultad con las siguientes configuraciones (requisitos tradicionales para cuentas tecnológicas/administrativas/sistémicas de la política de contraseñas corporativas):ntds_dit_10

  1. Creamos un archivo con hashes csv:
    ntds_dit_11
  1. Luego creamos un archivo para crackeo cmd:ntds_dit_12
  1. Y ahora recibimos resultados (dividido en dos partes):ntds_dit_13
  1. Entonces emparejamos contraseñas de las dos mitades usando la clave –show:ntds_dit_14
    test_lm_full.result:ntds_dit_15
  1. Luego creamos un archivo para nuestra herramienta, que generará listas de palabras y máscaras para nosotros. Tomamos el hash NTLM y contraseña para hackear LM, por ejemplo test_ntlm_input.txt:
    ntds_dit_16
  1. Ejecutamos nuestra herramienta:ntds_dit_17
    Inmediatamente recibimos un archivo que está listo para la búsqueda de contraseñas por máscaras y listas de palabras formadas automáticamente:

    ntds_dit_18

  1. Ejecutamos este archivo y conseguimos nuestras contraseñas en 14 segundos:ntds_dit_19

ntds_dit_20Eso es todo.

Aclaración

Como saben, a partir de la versión 2008, el almacenamiento de hashes LM está deshabilitado por defecto, pero en caso de migración desde la versión 2003 (o inferior), las cuentas que no han cambiado sus contraseñas después de la migración, se quedan con el hash LM en la base de datos. Por lo general, estas son cuentas tecnológicas con contraseñas que no se cambian por varias razones, por ejemplo, pueden causar la caída de algunos servicios críticos, etc. Tales cuentas son una amenaza seria porque sus contraseñas a menudo son «Nunca Expiran», su acceso no se monitorea y frecuentemente tienen privilegios altos hasta acceso administrativo. Como resultado, usar tales cuentas para entrar será lo más discreto.

Conclusión

Es críticamente importante dejar los dominios basados en 2003 o inferior y usar versiones más nuevas. En caso de migración tienes que asegurar que todas las cuentas han cambiado sus contraseñas y que no hay hashes LM en la base de datos. Y un consejo más para los administradores de dominios y expertos en seguridad de la información, ¡deben trabajar proactivamente y forzar sus contraseñas al menos una vez por trimestre! Deben controlar el acceso a AD especialmente vigilando operaciones con los archivos SYSTEM y NTDS.DIT.

Espero que este artículo sea útil para los expertos en seguridad de la información, quienes pueden usar las técnicas descritas como argumentos al comunicarse con especialistas en TI. O será útil para los administradores con el propósito de entender más ampliamente los riesgos relacionados con ataques a ActiveDirectory.

Anexo 1

importar math

alfabeto = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'excepción = ' &%{}<>^|"'nombre_del_archivo = abrir('D:hashcatkd_input.new','r')main_len = len(nombre_del_archivo.readlines())nombre_del_archivo.cerrar()nombre_del_archivo = abrir('D:hashcatkd_input.new','r')file_name_out = abrir('D:hashcatkd_input.cmd','w')hashes = []contraseñas = []máscaras = [[] for i in rango(main_len)]dictados = []char_sets_count = 0conjuntos_caracteres = [[] for i in rango(main_len)]ind_main = 0
ch1 = []
ch2 = []
ch3 = []
ch4 = []ch_sets = [ch1, ch2, ch3, ch4]


def new_init(pass_letter):
    for ind_0 in rango(4):ch_sets[ind_0] = []
    retorno predict(pass_letter)


def predict(nueva_contraseña):pass_letter = ''
    for let in nueva_contraseña:
        if let in alfabeto and not (let in pass_letter):pass_letter += let
    retorno dict_generator(pass_letter)


def dict_generator(pass_letter):
    global char_sets_count

    dict_new = ''pass_len = len(pass_letter)
    if pass_len < 4:
        for ind1 in rango(pass_len):ch_sets[ind1].adjuntar(pass_letter[ind1])ch_sets[ind1].adjuntar(pass_letter[ind1].bajo())
    otro:relleno(pass_letter, spread(pass_len))
    for ind2 in rango(4):
        if len(ch_sets[ind2]) > 0:dict_new += '-' + str(ind2+1) + ' ' + ''.unir(ch_sets[ind2]) + ' 'conjuntos_caracteres[char_sets_count] = [ch_sets[0], ch_sets[1], ch_sets[2], ch_sets[3]]char_sets_count += 1
    retorno dict_newdef spread(letter_num):spread_counter = [0, 0, 0, 0]
    for ind3 in rango(4):spread_counter[ind3] = int(math.ceil(letter_num/flotar(4-ind3)))letter_num -= spread_counter[ind3]
    retorno spread_counterdef relleno(pass_letter, counter_letter):contar_l = 0
    for ind_ch in rango(4):
        for ind_set in rango(counter_letter[ind_ch]):ch_sets[ind_ch].adjuntar(pass_letter[contar_l])ch_sets[ind_ch].adjuntar(pass_letter[contar_l].bajo())contar_l += 1


def mask_generator(contraseña,pwd_idx):mascara_nueva = ''
    for pw_let in contraseña:
        if pw_let in alfabeto:
            for ind_array in rango(4):
                if pw_let in conjuntos_caracteres[pwd_idx][ind_array]:mascara_nueva += '?'+str(ind_array+1)
        elif pw_let in excepción:mascara_nueva += '?s'
        otro:mascara_nueva += pw_let

    máscaras[pwd_idx] = mascara_nueva# ---------------------- Principal --------------------------------

for línea in nombre_del_archivo:hashes.adjuntar(línea[:32])contraseñas.adjuntar(línea[33:len(línea)-1])dictados.adjuntar(new_init(contraseñas[ind_main]))ind_main += 1

for pwd_idx in rango(len(contraseñas)):mask_generator(contraseñas[pwd_idx],pwd_idx)


for índice in rango(len(hashes)):texto = 'cudaHashcat64.exe -m 1000 -a 3 -o ntlm_tesult.hash ' + str(hashes[índice]) + ' ' + str(dictados[índice]) + ' ' + str(máscaras[índice]) + 'n'file_name_out.escribe(texto)nombre_del_archivo.cerrar()file_name_out.cerrar()

Tabla de Contenidos

¿Fue útil este artículo?

Dale me gusta y compártelo con tus compañeros.
Únase a la plataforma Detection as Code de SOC Prime para mejorar la visibilidad de las amenazas más relevantes para su negocio. Para ayudarle a comenzar y obtener un valor inmediato, reserve una reunión ahora con los expertos de SOC Prime.