Page cover

HTB Sink

10.10.10.225 | 50 pts

PART 1 : INITIAL RECON

1.1 MACHINE INFORMATION

1.2 NMAP SCAN

PART 2 : INFORMATION GATHERING

2.1 TCP PORT 22 (OpenSSH)

The SSH client supports either publickey or password authentication for regular users.

2.2 TCP PORT 3000 (HTTP)

A Gitea page opens up when you access the service via a web browser:

There are no public repositories in the Explore > Repositories section but a list of accounts were revealed under the Explore > Users as well as the group, Sink_Solutions, under Explore > Organizations.

The users -- david, marcus, and root, are all members of Sink_Solutions:

There is also a login option but there are no user credentials gotten yet nor is there a register option for new users. Finding valid user credentials might be one of the goals in the box during exploitation.

2.3 TCP PORT 5000 (HTTP)

Opening the service via a web browser brings you to the following page:

An option to sign up is available where I registered as the user, jebidiah:

And upon successful registration, you will be redirected to the following page:

On the same page, posting comments on posts are possible:

There is also an option to save personal notes within your account on /notes:

Posting notes will create a table on the same page (/notes):

And when you view the notes listed on the table, you are redirected to a page, /notes/<integer> and in this case, /notes/17436:

How the integer in the link and the numerical ID of the posted notes are hard to correlate and fuzzing seems to be not viable as well:

The server times out when flooded by a large volume of requests. But, the usual response code for the other requests are 500 (Internal Server Error) and for notes -- 1, 2, and 3, the response was 302 (Redirect). Trying to access the previously mentioned notes only redirects you back to /notes.

PART 3 : EXPLOITATION

3.2 HTTP REQUEST SMUGGLING

Checking for the response headers of the service running in port 5000:

While searching for relevant exploits for gunicorn with haproxy, I came across this article by Nathan Davidson and a practical application in a CTF challenge write up. It highlights a HTTP Request Smuggling using CL.TE (Content-Length -> Transfer-Encoding) vulnerability that leads to HTTP Desynchronization.

How request smuggling works is that specifying a Transfer-Encoding header with a value chunked along with Content-Length can force the server to interpret the request as multiple requests. The server will interpret the “0\r\n\r\n” as the end of the initial request and will then begin to parse the succeeding lines as a new request. The terminator for the smuggled request will be supplied by the server once it parses the second request.

In the following example, when the request passes through haproxy, the request will be considered as chunked as well as into the server itself leveraging HTTP Request Smuggling using TE.TE (Transfer-Encoding -> Transfer-Encoding):

And after the request was sent, the server responded as well to the smuggled request:

3.2 HTTP DESYNCHRONIZATION

The goal of the exploit is to force haproxy to interpret the Content-Length instead of the Transfer-Encoding header in the initial request to leverage a CL.TE instead of TE.TE in order to trigger an HTTP Desynchronization wherein the server will hang while waiting for a request with a “0\r\n\r\n” terminator; therefore, making the intercepted request part of the smuggle request.

To do this, according to the article by Nathan Davidson, write the Transfer-Encoding header with [\x0b] or [\x0c] before the value, chunked. These characters are short spaces that haproxy will not be able to parse. This will enable the attacker to intercept other requests as part of the smuggled request’s body.

After the sending the request above then checking the created note, an HTTP request was intercepted and was saved along with the note:

Setting the right Content-Length (in this case, 300) for the smuggled request will let you intercept the succeeding request properly. Setting it too long and the request terminator might be interpreted as part of the note.

The entire request will look like this once interpreted by the server:

A session cookie was leaked and maybe could now be used to read another user’s saved notes.

Using the session cookie to access the service reveals that the cookie belongs to [email protected] and the notes previously found while fuzzing are now readable.

The exploit for triggering the HTTP Desync was automated using this python script:

Now, viewing the notes saved in the admin user account, credentials for various services are leaked.:

There is a root user for the Gitea service, maybe this is the credentials for the user given that it is for code.sink.htb.

PART 4 : USER SHELL (marcus)

4.1 EC2 INFORMATION

Logging in using the credentials, root:FaH@3L>Z3})zzfQ3, the following repositories become available:

The Key_Management repo has been archived and upon viewing, there has been 8/9 commits by marcus:

The commit history highly suggests deployments in AWS. The commit with the message, “Adding EC2 Key Management Structure”, seems promising. And in there, an SSH private key is added to the repository as well as various configurations for an EC2 Client.

The dev_keys file:

There seems to be an EC2 instance deployed in the region, eu, and could be reached via http[://]127.0.0.1:4566 based on the ec2.php file.

4.2 SSH SESSION

As the git commit was done by the user, marcus, this must be his own private key. Saving the key into a file and using it to login via SSH:

The login was successful:

There seems to be another user, david, inside the machine. And his home directory seems to be readable. There is a directory, Projects, however that is protected. This might be interesting.

PART 5 : PIVOT (marcus -> david)

5.1 AWS CONFIGURE

Checking to see if port 4566 is listening inside the machine:

And when you check the AWS running services’ health using the endpoint URL, http[://]127.0.0.1:4566:

There are three services running - kms, logs, and secretsmanager. In order to access these services via the aws-cli, we need an AWS Access Key ID and an AWS Secret Access Key. Looking back into the repositories in Gitea, there was a Log_Management repo and given that a “logs” service is running, there might be something interesting there.

In the last commit, “Preparing for prod”, the AWS Access Key ID and an AWS Secret Access Key were deleted from the create_logs.php file:

Which gives us the following:

We can now run aws configure in order to access the running services:

5.2 SECRETSMANAGER

Enumerating the secretsmanager service to see if there are anything interesting:

There were three secrets available in the secretsmanager service. Extracting their respective values:

Credentials from three users were leaked from the secretsmanager service. More importantly, one of them was for the user, david (david:EALB=bcC=`a7f2#k).

PART 6 : PRIVILEGE ESCALATION (david -> root)

6.1 PORT FORWARD -- 4566

Now that we have a shell as the user, david, the Projects directory should now be accessible wherein an encrypted file, servers.enc, is stored:

Looking back again into the running services accessible via http://127.0.0.1:4566, one of them was kms which stands for Key Management Service for AWS. It might have been used to encrypt the file. To make things easier, I forwarded the service running on port 4566 to my local machine:

6.2 KMS ENUMERATION

Enumerating this time the said service after running aws configure again:

I took all the KeyId values from the output of list-keys which I will then iterate through to get their individual descriptions:

There were multiple keys but only a handful were enabled and only one could be used for encryption or decryption -- 804125db-bdf1-465a-a058-07fc87c0fad0:

6.3 KMS DECRYPT

Going back to the shell running as the user, david, to attempt to decrypt the server.enc file:

The contents are still gibberish but when you check what kind of output was generated, the file turned to be a gzip compressed data. Using zcat to view the contents:

Trying to use the credentials when switching user to root:

Last updated